summaryrefslogtreecommitdiff
path: root/chromium/base
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@theqtcompany.com>2016-01-25 11:39:07 +0100
committerOswald Buddenhagen <oswald.buddenhagen@theqtcompany.com>2016-01-25 15:20:42 +0000
commit6c91641271e536ffaa88a1dff5127e42ee99a91e (patch)
tree703d9dd49602377ddc90cbf886aad37913f2496b /chromium/base
parentb145b7fafd36f0c260d6a768c81fc14e32578099 (diff)
downloadqtwebengine-chromium-6c91641271e536ffaa88a1dff5127e42ee99a91e.tar.gz
BASELINE: Update Chromium to 49.0.2623.23
Also adds missing printing sources. Change-Id: I3726b8f0c7d6751c9fc846096c571fadca7108cd Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com>
Diffstat (limited to 'chromium/base')
-rw-r--r--chromium/base/BUILD.gn659
-rw-r--r--chromium/base/DEPS3
-rw-r--r--chromium/base/OWNERS1
-rw-r--r--chromium/base/allocator/BUILD.gn92
-rw-r--r--chromium/base/allocator/allocator.gyp308
-rw-r--r--chromium/base/allocator/allocator_check.cc38
-rw-r--r--chromium/base/allocator/allocator_check.h18
-rw-r--r--chromium/base/allocator/allocator_extension.cc48
-rw-r--r--chromium/base/allocator/allocator_extension.h34
-rw-r--r--chromium/base/allocator/allocator_extension_thunks.cc52
-rw-r--r--chromium/base/allocator/allocator_extension_thunks.h36
-rw-r--r--chromium/base/allocator/allocator_shim_win.cc11
-rw-r--r--chromium/base/allocator/allocator_unittest.cc245
-rwxr-xr-xchromium/base/allocator/prep_libc.py29
-rw-r--r--chromium/base/allocator/tcmalloc_unittest.cc230
-rw-r--r--chromium/base/allocator/unittest_utils.cc1
-rw-r--r--chromium/base/android/OWNERS1
-rw-r--r--chromium/base/android/apk_assets.cc1
-rw-r--r--chromium/base/android/application_status_listener.cc6
-rw-r--r--chromium/base/android/application_status_listener.h6
-rw-r--r--chromium/base/android/build_info.cc1
-rw-r--r--chromium/base/android/build_info.h1
-rw-r--r--chromium/base/android/content_uri_utils.cc1
-rw-r--r--chromium/base/android/content_uri_utils.h1
-rw-r--r--chromium/base/android/context_utils.cc58
-rw-r--r--chromium/base/android/context_utils.h34
-rw-r--r--chromium/base/android/cxa_demangle_stub.cc1
-rw-r--r--chromium/base/android/fifo_utils.h1
-rw-r--r--chromium/base/android/jni_generator/jni_generator.gyp4
-rw-r--r--chromium/base/android/library_loader/library_loader_hooks.cc6
-rw-r--r--chromium/base/android/library_loader/library_prefetcher.cc39
-rw-r--r--chromium/base/android/library_loader/library_prefetcher.h12
-rw-r--r--chromium/base/android/library_loader/library_prefetcher_unittest.cc70
-rw-r--r--chromium/base/android/linker/config.gni11
-rw-r--r--chromium/base/android/memory_pressure_listener_android.cc1
-rw-r--r--chromium/base/android/memory_pressure_listener_android.h1
-rw-r--r--chromium/base/android/path_utils.cc1
-rw-r--r--chromium/base/android/path_utils_unittest.cc7
-rw-r--r--chromium/base/android/record_histogram.cc17
-rw-r--r--chromium/base/android/scoped_java_ref.h32
-rw-r--r--chromium/base/android/sys_utils_unittest.cc1
-rw-r--r--chromium/base/android/trace_event_binding.cc1
-rw-r--r--chromium/base/at_exit.h2
-rw-r--r--chromium/base/atomic_sequence_num.h2
-rw-r--r--chromium/base/atomicops.h26
-rw-r--r--chromium/base/atomicops_internals_atomicword_compat.h6
-rw-r--r--chromium/base/atomicops_internals_mac.h197
-rw-r--r--chromium/base/atomicops_internals_portable.h2
-rw-r--r--chromium/base/atomicops_internals_x86_msvc.h3
-rw-r--r--chromium/base/atomicops_unittest.cc7
-rw-r--r--chromium/base/auto_reset.h2
-rw-r--r--chromium/base/base.gyp85
-rw-r--r--chromium/base/base.gypi30
-rw-r--r--chromium/base/base64.cc2
-rw-r--r--chromium/base/base64url.cc101
-rw-r--r--chromium/base/base64url.h56
-rw-r--r--chromium/base/base64url_unittest.cc115
-rw-r--r--chromium/base/base_export.h5
-rw-r--r--chromium/base/base_nacl.gyp6
-rw-r--r--chromium/base/base_paths.cc15
-rw-r--r--chromium/base/base_paths_android.cc1
-rw-r--r--chromium/base/base_paths_mac.mm1
-rw-r--r--chromium/base/base_paths_posix.cc3
-rw-r--r--chromium/base/base_paths_win.h2
-rw-r--r--chromium/base/base_switches.cc9
-rw-r--r--chromium/base/base_switches.h6
-rw-r--r--chromium/base/basictypes.h46
-rw-r--r--chromium/base/big_endian.cc16
-rw-r--r--chromium/base/big_endian.h32
-rw-r--r--chromium/base/big_endian_unittest.cc26
-rw-r--r--chromium/base/bind.h49
-rw-r--r--chromium/base/bind_helpers.h126
-rw-r--r--chromium/base/bind_internal.h77
-rw-r--r--chromium/base/bind_internal_win.h10
-rw-r--r--chromium/base/bind_unittest.cc170
-rw-r--r--chromium/base/bind_unittest.nc46
-rw-r--r--chromium/base/bit_cast.h71
-rw-r--r--chromium/base/bits.h12
-rw-r--r--chromium/base/bits_unittest.cc2
-rw-r--r--chromium/base/callback.h44
-rw-r--r--chromium/base/callback_forward.h4
-rw-r--r--chromium/base/callback_helpers.h2
-rw-r--r--chromium/base/callback_internal.h63
-rw-r--r--chromium/base/callback_list.h8
-rw-r--r--chromium/base/callback_list_unittest.cc55
-rw-r--r--chromium/base/callback_list_unittest.nc11
-rw-r--r--chromium/base/callback_unittest.cc37
-rw-r--r--chromium/base/callback_unittest.nc13
-rw-r--r--chromium/base/cancelable_callback.h1
-rw-r--r--chromium/base/command_line.cc10
-rw-r--r--chromium/base/command_line_unittest.cc3
-rw-r--r--chromium/base/compiler_specific.h9
-rw-r--r--chromium/base/containers/adapters.h25
-rw-r--r--chromium/base/containers/adapters_unittest.cc14
-rw-r--r--chromium/base/containers/hash_tables.h109
-rw-r--r--chromium/base/containers/hash_tables_unittest.cc19
-rw-r--r--chromium/base/containers/linked_list_unittest.cc2
-rw-r--r--chromium/base/containers/mru_cache.h13
-rw-r--r--chromium/base/containers/mru_cache_unittest.cc107
-rw-r--r--chromium/base/containers/scoped_ptr_hash_map.h10
-rw-r--r--chromium/base/containers/scoped_ptr_hash_map_unittest.cc17
-rw-r--r--chromium/base/containers/scoped_ptr_map.h144
-rw-r--r--chromium/base/containers/scoped_ptr_map_unittest.cc255
-rw-r--r--chromium/base/containers/small_map.h5
-rw-r--r--chromium/base/containers/stack_container.h6
-rw-r--r--chromium/base/containers/stack_container_unittest.cc3
-rw-r--r--chromium/base/cpu.cc16
-rw-r--r--chromium/base/cpu.h7
-rw-r--r--chromium/base/cpu_unittest.cc7
-rw-r--r--chromium/base/critical_closure.h2
-rw-r--r--chromium/base/debug/BUILD.gn76
-rw-r--r--chromium/base/debug/asan_invalid_access.cc9
-rw-r--r--chromium/base/debug/close_handle_hook_win.cc276
-rw-r--r--chromium/base/debug/close_handle_hook_win.h22
-rw-r--r--chromium/base/debug/crash_logging.h4
-rw-r--r--chromium/base/debug/crash_logging_unittest.cc3
-rw-r--r--chromium/base/debug/debugger.cc1
-rw-r--r--chromium/base/debug/debugger_posix.cc3
-rw-r--r--chromium/base/debug/gdi_debug_util_win.cc1
-rw-r--r--chromium/base/debug/leak_annotations.h2
-rw-r--r--chromium/base/debug/leak_tracker.h2
-rw-r--r--chromium/base/debug/proc_maps_linux.cc14
-rw-r--r--chromium/base/debug/proc_maps_linux.h5
-rw-r--r--chromium/base/debug/proc_maps_linux_unittest.cc7
-rw-r--r--chromium/base/debug/profiler.cc6
-rw-r--r--chromium/base/debug/profiler.h3
-rw-r--r--chromium/base/debug/stack_trace.cc4
-rw-r--r--chromium/base/debug/stack_trace.h6
-rw-r--r--chromium/base/debug/stack_trace_android.cc1
-rw-r--r--chromium/base/debug/stack_trace_posix.cc66
-rw-r--r--chromium/base/debug/stack_trace_unittest.cc3
-rw-r--r--chromium/base/debug/stack_trace_win.cc17
-rw-r--r--chromium/base/debug/task_annotator.cc7
-rw-r--r--chromium/base/debug/task_annotator.h16
-rw-r--r--chromium/base/deferred_sequenced_task_runner.h2
-rw-r--r--chromium/base/deferred_sequenced_task_runner_unittest.cc1
-rw-r--r--chromium/base/environment.cc5
-rw-r--r--chromium/base/environment_unittest.cc3
-rw-r--r--chromium/base/feature_list.cc120
-rw-r--r--chromium/base/feature_list.h39
-rw-r--r--chromium/base/feature_list_unittest.cc60
-rw-r--r--chromium/base/file_version_info_mac.h1
-rw-r--r--chromium/base/file_version_info_mac.mm1
-rw-r--r--chromium/base/file_version_info_unittest.cc6
-rw-r--r--chromium/base/file_version_info_win.cc9
-rw-r--r--chromium/base/file_version_info_win.h2
-rw-r--r--chromium/base/files/dir_reader_fallback.h2
-rw-r--r--chromium/base/files/dir_reader_linux.h7
-rw-r--r--chromium/base/files/dir_reader_posix_unittest.cc1
-rw-r--r--chromium/base/files/file.cc41
-rw-r--r--chromium/base/files/file.h48
-rw-r--r--chromium/base/files/file_enumerator.h7
-rw-r--r--chromium/base/files/file_enumerator_posix.cc4
-rw-r--r--chromium/base/files/file_enumerator_win.cc7
-rw-r--r--chromium/base/files/file_locking_unittest.cc226
-rw-r--r--chromium/base/files/file_path.cc3
-rw-r--r--chromium/base/files/file_path.h10
-rw-r--r--chromium/base/files/file_path_constants.cc3
-rw-r--r--chromium/base/files/file_path_unittest.cc5
-rw-r--r--chromium/base/files/file_path_watcher.cc1
-rw-r--r--chromium/base/files/file_path_watcher.h7
-rw-r--r--chromium/base/files/file_path_watcher_fsevents.cc1
-rw-r--r--chromium/base/files/file_path_watcher_fsevents.h2
-rw-r--r--chromium/base/files/file_path_watcher_kqueue.cc1
-rw-r--r--chromium/base/files/file_path_watcher_kqueue.h1
-rw-r--r--chromium/base/files/file_path_watcher_linux.cc2
-rw-r--r--chromium/base/files/file_path_watcher_mac.cc1
-rw-r--r--chromium/base/files/file_path_watcher_unittest.cc3
-rw-r--r--chromium/base/files/file_path_watcher_win.cc1
-rw-r--r--chromium/base/files/file_posix.cc82
-rw-r--r--chromium/base/files/file_proxy.cc61
-rw-r--r--chromium/base/files/file_proxy.h13
-rw-r--r--chromium/base/files/file_proxy_unittest.cc13
-rw-r--r--chromium/base/files/file_tracing.cc5
-rw-r--r--chromium/base/files/file_tracing.h11
-rw-r--r--chromium/base/files/file_unittest.cc14
-rw-r--r--chromium/base/files/file_util.cc7
-rw-r--r--chromium/base/files/file_util.h29
-rw-r--r--chromium/base/files/file_util_mac.mm1
-rw-r--r--chromium/base/files/file_util_posix.cc27
-rw-r--r--chromium/base/files/file_util_proxy.cc1
-rw-r--r--chromium/base/files/file_util_proxy.h1
-rw-r--r--chromium/base/files/file_util_unittest.cc52
-rw-r--r--chromium/base/files/file_util_win.cc112
-rw-r--r--chromium/base/files/file_win.cc26
-rw-r--r--chromium/base/files/important_file_writer.cc8
-rw-r--r--chromium/base/files/important_file_writer.h2
-rw-r--r--chromium/base/files/important_file_writer_unittest.cc1
-rw-r--r--chromium/base/files/memory_mapped_file.cc22
-rw-r--r--chromium/base/files/memory_mapped_file.h23
-rw-r--r--chromium/base/files/memory_mapped_file_posix.cc24
-rw-r--r--chromium/base/files/memory_mapped_file_unittest.cc29
-rw-r--r--chromium/base/files/memory_mapped_file_win.cc27
-rw-r--r--chromium/base/files/scoped_file.cc1
-rw-r--r--chromium/base/files/scoped_temp_dir.h1
-rw-r--r--chromium/base/files/scoped_temp_dir_unittest.cc1
-rw-r--r--chromium/base/format_macros.h3
-rw-r--r--chromium/base/guid.cc2
-rw-r--r--chromium/base/guid.h5
-rw-r--r--chromium/base/guid_posix.cc6
-rw-r--r--chromium/base/guid_unittest.cc7
-rw-r--r--chromium/base/guid_win.cc1
-rw-r--r--chromium/base/hash.cc2
-rw-r--r--chromium/base/hash.h10
-rw-r--r--chromium/base/i18n/base_i18n_switches.cc16
-rw-r--r--chromium/base/i18n/base_i18n_switches.h20
-rw-r--r--chromium/base/i18n/bidi_line_iterator.h2
-rw-r--r--chromium/base/i18n/break_iterator.cc2
-rw-r--r--chromium/base/i18n/break_iterator.h4
-rw-r--r--chromium/base/i18n/break_iterator_unittest.cc3
-rw-r--r--chromium/base/i18n/build_utf8_validator_tables.cc82
-rw-r--r--chromium/base/i18n/case_conversion.cc2
-rw-r--r--chromium/base/i18n/char_iterator.h38
-rw-r--r--chromium/base/i18n/file_util_icu.cc5
-rw-r--r--chromium/base/i18n/file_util_icu_unittest.cc4
-rw-r--r--chromium/base/i18n/icu_encoding_detection.cc14
-rw-r--r--chromium/base/i18n/icu_string_conversions.cc4
-rw-r--r--chromium/base/i18n/icu_string_conversions_unittest.cc4
-rw-r--r--chromium/base/i18n/icu_util.cc37
-rw-r--r--chromium/base/i18n/icu_util.h27
-rw-r--r--chromium/base/i18n/message_formatter.h1
-rw-r--r--chromium/base/i18n/number_formatting.cc4
-rw-r--r--chromium/base/i18n/number_formatting.h5
-rw-r--r--chromium/base/i18n/number_formatting_unittest.cc11
-rw-r--r--chromium/base/i18n/rtl.cc49
-rw-r--r--chromium/base/i18n/rtl_unittest.cc4
-rw-r--r--chromium/base/i18n/streaming_utf8_validator.cc8
-rw-r--r--chromium/base/i18n/streaming_utf8_validator.h7
-rw-r--r--chromium/base/i18n/streaming_utf8_validator_perftest.cc4
-rw-r--r--chromium/base/i18n/streaming_utf8_validator_unittest.cc20
-rw-r--r--chromium/base/i18n/string_search.cc2
-rw-r--r--chromium/base/i18n/string_search.h2
-rw-r--r--chromium/base/i18n/string_search_unittest.cc2
-rw-r--r--chromium/base/i18n/time_formatting.cc2
-rw-r--r--chromium/base/i18n/timezone.cc2
-rw-r--r--chromium/base/i18n/utf8_validator_tables.cc2
-rw-r--r--chromium/base/i18n/utf8_validator_tables.h7
-rw-r--r--chromium/base/id_map.h52
-rw-r--r--chromium/base/id_map_unittest.cc10
-rw-r--r--chromium/base/ios/crb_protocol_observers.mm5
-rw-r--r--chromium/base/ios/crb_protocol_observers_unittest.mm2
-rw-r--r--chromium/base/ios/device_util.h2
-rw-r--r--chromium/base/ios/device_util.mm1
-rw-r--r--chromium/base/ios/ios_util.h16
-rw-r--r--chromium/base/ios/ios_util.mm28
-rw-r--r--chromium/base/ios/scoped_critical_action.h1
-rw-r--r--chromium/base/ios/weak_nsobject.h1
-rw-r--r--chromium/base/ios/weak_nsobject_unittest.mm1
-rw-r--r--chromium/base/json/BUILD.gn37
-rw-r--r--chromium/base/json/json_file_value_serializer.cc6
-rw-r--r--chromium/base/json/json_file_value_serializer.h8
-rw-r--r--chromium/base/json/json_parser.cc27
-rw-r--r--chromium/base/json/json_parser.h17
-rw-r--r--chromium/base/json/json_parser_unittest.cc55
-rw-r--r--chromium/base/json/json_reader.cc30
-rw-r--r--chromium/base/json/json_reader.h14
-rw-r--r--chromium/base/json/json_reader_unittest.cc119
-rw-r--r--chromium/base/json/json_string_value_serializer.cc7
-rw-r--r--chromium/base/json/json_string_value_serializer.h6
-rw-r--r--chromium/base/json/json_value_converter.h4
-rw-r--r--chromium/base/json/json_value_serializer_unittest.cc51
-rw-r--r--chromium/base/json/json_writer.cc10
-rw-r--r--chromium/base/json/json_writer.h4
-rw-r--r--chromium/base/json/json_writer_unittest.cc7
-rw-r--r--chromium/base/json/string_escape.cc21
-rw-r--r--chromium/base/json/string_escape_unittest.cc3
-rw-r--r--chromium/base/lazy_instance.cc1
-rw-r--r--chromium/base/lazy_instance.h1
-rw-r--r--chromium/base/lazy_instance_unittest.cc2
-rw-r--r--chromium/base/linux_util.cc2
-rw-r--r--chromium/base/location.h9
-rw-r--r--chromium/base/logging.cc146
-rw-r--r--chromium/base/logging.h17
-rw-r--r--chromium/base/logging_unittest.cc22
-rw-r--r--chromium/base/logging_win.h6
-rw-r--r--chromium/base/mac/authorization_util.mm7
-rw-r--r--chromium/base/mac/call_with_eh_frame.cc1
-rw-r--r--chromium/base/mac/call_with_eh_frame_unittest.mm4
-rw-r--r--chromium/base/mac/foundation_util.h1
-rw-r--r--chromium/base/mac/foundation_util.mm3
-rw-r--r--chromium/base/mac/foundation_util_unittest.mm10
-rw-r--r--chromium/base/mac/launchd.cc20
-rw-r--r--chromium/base/mac/libdispatch_task_runner.cc4
-rw-r--r--chromium/base/mac/libdispatch_task_runner_unittest.cc3
-rw-r--r--chromium/base/mac/mac_logging.cc1
-rw-r--r--chromium/base/mac/mac_logging.h2
-rw-r--r--chromium/base/mac/mac_util.h5
-rw-r--r--chromium/base/mac/mac_util.mm8
-rw-r--r--chromium/base/mac/mac_util_unittest.mm7
-rw-r--r--chromium/base/mac/mach_logging.cc1
-rw-r--r--chromium/base/mac/mach_logging.h2
-rw-r--r--chromium/base/mac/os_crash_dumps.cc3
-rw-r--r--chromium/base/mac/scoped_aedesc.h2
-rw-r--r--chromium/base/mac/scoped_authorizationref.h2
-rw-r--r--chromium/base/mac/scoped_block.h83
-rw-r--r--chromium/base/mac/scoped_cffiledescriptorref.h68
-rw-r--r--chromium/base/mac/scoped_cftyperef.h23
-rw-r--r--chromium/base/mac/scoped_ioobject.h66
-rw-r--r--chromium/base/mac/scoped_ioplugininterface.h70
-rw-r--r--chromium/base/mac/scoped_launch_data.h64
-rw-r--r--chromium/base/mac/scoped_mach_port.h29
-rw-r--r--chromium/base/mac/scoped_mach_vm.h3
-rw-r--r--chromium/base/mac/scoped_nsautorelease_pool.h2
-rw-r--r--chromium/base/mac/scoped_nsobject.h131
-rw-r--r--chromium/base/mac/scoped_nsobject_unittest.mm9
-rw-r--r--chromium/base/mac/scoped_sending_event.h2
-rw-r--r--chromium/base/mac/scoped_sending_event_unittest.mm2
-rw-r--r--chromium/base/mac/scoped_typeref.h21
-rw-r--r--chromium/base/mac/sdk_forward_declarations.h48
-rw-r--r--chromium/base/macros.h98
-rw-r--r--chromium/base/md5.h1
-rw-r--r--chromium/base/md5_unittest.cc1
-rw-r--r--chromium/base/memory/BUILD.gn84
-rw-r--r--chromium/base/memory/aligned_memory.cc1
-rw-r--r--chromium/base/memory/aligned_memory.h43
-rw-r--r--chromium/base/memory/aligned_memory_unittest.cc1
-rw-r--r--chromium/base/memory/discardable_memory.h1
-rw-r--r--chromium/base/memory/discardable_memory_allocator.h2
-rw-r--r--chromium/base/memory/discardable_shared_memory.cc111
-rw-r--r--chromium/base/memory/discardable_shared_memory.h23
-rw-r--r--chromium/base/memory/discardable_shared_memory_unittest.cc66
-rw-r--r--chromium/base/memory/linked_ptr.h6
-rw-r--r--chromium/base/memory/memory_pressure_listener.h2
-rw-r--r--chromium/base/memory/memory_pressure_monitor.h1
-rw-r--r--chromium/base/memory/memory_pressure_monitor_chromeos_unittest.cc2
-rw-r--r--chromium/base/memory/memory_pressure_monitor_mac.cc1
-rw-r--r--chromium/base/memory/memory_pressure_monitor_mac.h1
-rw-r--r--chromium/base/memory/memory_pressure_monitor_mac_unittest.cc1
-rw-r--r--chromium/base/memory/memory_pressure_monitor_win.h1
-rw-r--r--chromium/base/memory/memory_pressure_monitor_win_unittest.cc2
-rw-r--r--chromium/base/memory/ptr_util.h22
-rw-r--r--chromium/base/memory/ptr_util_unittest.cc40
-rw-r--r--chromium/base/memory/raw_scoped_refptr_mismatch_checker.h73
-rw-r--r--chromium/base/memory/ref_counted.h16
-rw-r--r--chromium/base/memory/ref_counted_delete_on_message_loop.h1
-rw-r--r--chromium/base/memory/ref_counted_memory.cc25
-rw-r--r--chromium/base/memory/ref_counted_memory.h25
-rw-r--r--chromium/base/memory/ref_counted_memory_unittest.cc14
-rw-r--r--chromium/base/memory/ref_counted_unittest.cc36
-rw-r--r--chromium/base/memory/scoped_ptr.h344
-rw-r--r--chromium/base/memory/scoped_ptr_unittest.cc308
-rw-r--r--chromium/base/memory/scoped_ptr_unittest.nc32
-rw-r--r--chromium/base/memory/scoped_vector.h14
-rw-r--r--chromium/base/memory/scoped_vector_unittest.cc11
-rw-r--r--chromium/base/memory/shared_memory.h58
-rw-r--r--chromium/base/memory/shared_memory_android.cc1
-rw-r--r--chromium/base/memory/shared_memory_handle.h14
-rw-r--r--chromium/base/memory/shared_memory_handle_mac.cc25
-rw-r--r--chromium/base/memory/shared_memory_mac.cc179
-rw-r--r--chromium/base/memory/shared_memory_mac_unittest.cc202
-rw-r--r--chromium/base/memory/shared_memory_nacl.cc19
-rw-r--r--chromium/base/memory/shared_memory_posix.cc32
-rw-r--r--chromium/base/memory/shared_memory_unittest.cc116
-rw-r--r--chromium/base/memory/shared_memory_win.cc109
-rw-r--r--chromium/base/memory/singleton.h1
-rw-r--r--chromium/base/memory/singleton_unittest.cc9
-rw-r--r--chromium/base/memory/weak_ptr.h15
-rw-r--r--chromium/base/memory/weak_ptr_unittest.nc7
-rw-r--r--chromium/base/message_loop/incoming_task_queue.cc1
-rw-r--r--chromium/base/message_loop/incoming_task_queue.h1
-rw-r--r--chromium/base/message_loop/message_loop.cc15
-rw-r--r--chromium/base/message_loop/message_loop.h19
-rw-r--r--chromium/base/message_loop/message_loop_task_runner.h1
-rw-r--r--chromium/base/message_loop/message_loop_test.cc58
-rw-r--r--chromium/base/message_loop/message_loop_unittest.cc34
-rw-r--r--chromium/base/message_loop/message_pump.h1
-rw-r--r--chromium/base/message_loop/message_pump_android.h1
-rw-r--r--chromium/base/message_loop/message_pump_default.cc1
-rw-r--r--chromium/base/message_loop/message_pump_default.h1
-rw-r--r--chromium/base/message_loop/message_pump_glib.h1
-rw-r--r--chromium/base/message_loop/message_pump_glib_unittest.cc1
-rw-r--r--chromium/base/message_loop/message_pump_io_ios.cc12
-rw-r--r--chromium/base/message_loop/message_pump_io_ios.h1
-rw-r--r--chromium/base/message_loop/message_pump_io_ios_unittest.cc3
-rw-r--r--chromium/base/message_loop/message_pump_libevent.cc18
-rw-r--r--chromium/base/message_loop/message_pump_libevent.h2
-rw-r--r--chromium/base/message_loop/message_pump_libevent_unittest.cc3
-rw-r--r--chromium/base/message_loop/message_pump_mac.h3
-rw-r--r--chromium/base/message_loop/message_pump_mac.mm2
-rw-r--r--chromium/base/message_loop/message_pump_perftest.cc13
-rw-r--r--chromium/base/message_loop/message_pump_win.cc4
-rw-r--r--chromium/base/message_loop/message_pump_win.h1
-rw-r--r--chromium/base/metrics/BUILD.gn45
-rw-r--r--chromium/base/metrics/bucket_ranges.cc120
-rw-r--r--chromium/base/metrics/bucket_ranges.h19
-rw-r--r--chromium/base/metrics/bucket_ranges_unittest.cc6
-rw-r--r--chromium/base/metrics/field_trial.cc137
-rw-r--r--chromium/base/metrics/field_trial.h38
-rw-r--r--chromium/base/metrics/field_trial_unittest.cc31
-rw-r--r--chromium/base/metrics/histogram.cc75
-rw-r--r--chromium/base/metrics/histogram.h48
-rw-r--r--chromium/base/metrics/histogram_base.cc22
-rw-r--r--chromium/base/metrics/histogram_base.h16
-rw-r--r--chromium/base/metrics/histogram_delta_serialization.cc9
-rw-r--r--chromium/base/metrics/histogram_delta_serialization.h5
-rw-r--r--chromium/base/metrics/histogram_flattener.h2
-rw-r--r--chromium/base/metrics/histogram_macros.h1
-rw-r--r--chromium/base/metrics/histogram_samples.cc64
-rw-r--r--chromium/base/metrics/histogram_samples.h62
-rw-r--r--chromium/base/metrics/histogram_snapshot_manager.cc16
-rw-r--r--chromium/base/metrics/histogram_snapshot_manager.h12
-rw-r--r--chromium/base/metrics/histogram_snapshot_manager_unittest.cc1
-rw-r--r--chromium/base/metrics/histogram_unittest.cc16
-rw-r--r--chromium/base/metrics/metrics_hashes.cc31
-rw-r--r--chromium/base/metrics/metrics_hashes.h21
-rw-r--r--chromium/base/metrics/metrics_hashes_unittest.cc35
-rw-r--r--chromium/base/metrics/sample_map.cc4
-rw-r--r--chromium/base/metrics/sample_map.h8
-rw-r--r--chromium/base/metrics/sample_map_unittest.cc14
-rw-r--r--chromium/base/metrics/sample_vector.cc57
-rw-r--r--chromium/base/metrics/sample_vector.h29
-rw-r--r--chromium/base/metrics/sample_vector_unittest.cc21
-rw-r--r--chromium/base/metrics/sparse_histogram.cc18
-rw-r--r--chromium/base/metrics/sparse_histogram.h14
-rw-r--r--chromium/base/metrics/statistics_recorder.cc31
-rw-r--r--chromium/base/metrics/statistics_recorder.h27
-rw-r--r--chromium/base/metrics/statistics_recorder_unittest.cc15
-rw-r--r--chromium/base/metrics/user_metrics.cc3
-rw-r--r--chromium/base/move.h257
-rw-r--r--chromium/base/move_unittest.cc49
-rw-r--r--chromium/base/native_library_ios.mm2
-rw-r--r--chromium/base/native_library_mac.mm3
-rw-r--r--chromium/base/native_library_unittest.cc29
-rw-r--r--chromium/base/numerics/safe_conversions.h36
-rw-r--r--chromium/base/numerics/safe_conversions_impl.h3
-rw-r--r--chromium/base/numerics/safe_math.h13
-rw-r--r--chromium/base/numerics/safe_math_impl.h123
-rw-r--r--chromium/base/numerics/safe_numerics_unittest.cc43
-rw-r--r--chromium/base/observer_list.h8
-rw-r--r--chromium/base/observer_list_threadsafe.h7
-rw-r--r--chromium/base/os_compat_android.cc1
-rw-r--r--chromium/base/path_service.cc13
-rw-r--r--chromium/base/path_service_unittest.cc1
-rw-r--r--chromium/base/pickle.cc63
-rw-r--r--chromium/base/pickle.h41
-rw-r--r--chromium/base/pickle_unittest.cc85
-rw-r--r--chromium/base/posix/safe_strerror.cc6
-rw-r--r--chromium/base/posix/safe_strerror.h2
-rw-r--r--chromium/base/posix/unix_domain_socket_linux.cc14
-rw-r--r--chromium/base/posix/unix_domain_socket_linux.h9
-rw-r--r--chromium/base/posix/unix_domain_socket_linux_unittest.cc11
-rw-r--r--chromium/base/power_monitor/power_monitor.cc5
-rw-r--r--chromium/base/power_monitor/power_monitor.h2
-rw-r--r--chromium/base/power_monitor/power_monitor_device_source.cc1
-rw-r--r--chromium/base/power_monitor/power_monitor_device_source.h3
-rw-r--r--chromium/base/power_monitor/power_monitor_source.h2
-rw-r--r--chromium/base/power_monitor/power_monitor_unittest.cc1
-rw-r--r--chromium/base/prefs/default_pref_store.cc7
-rw-r--r--chromium/base/prefs/default_pref_store.h1
-rw-r--r--chromium/base/prefs/default_pref_store_unittest.cc1
-rw-r--r--chromium/base/prefs/json_pref_store.cc44
-rw-r--r--chromium/base/prefs/json_pref_store.h16
-rw-r--r--chromium/base/prefs/json_pref_store_unittest.cc31
-rw-r--r--chromium/base/prefs/overlay_user_pref_store.cc18
-rw-r--r--chromium/base/prefs/overlay_user_pref_store.h12
-rw-r--r--chromium/base/prefs/pref_change_registrar.h2
-rw-r--r--chromium/base/prefs/pref_member.cc6
-rw-r--r--chromium/base/prefs/pref_member.h2
-rw-r--r--chromium/base/prefs/pref_notifier_impl.h1
-rw-r--r--chromium/base/prefs/pref_notifier_impl_unittest.cc2
-rw-r--r--chromium/base/prefs/pref_registry.cc5
-rw-r--r--chromium/base/prefs/pref_registry.h11
-rw-r--r--chromium/base/prefs/pref_registry_simple.cc35
-rw-r--r--chromium/base/prefs/pref_registry_simple.h39
-rw-r--r--chromium/base/prefs/pref_service.cc25
-rw-r--r--chromium/base/prefs/pref_service.h15
-rw-r--r--chromium/base/prefs/pref_service_factory.cc2
-rw-r--r--chromium/base/prefs/pref_service_factory.h2
-rw-r--r--chromium/base/prefs/pref_service_unittest.cc26
-rw-r--r--chromium/base/prefs/pref_store.h2
-rw-r--r--chromium/base/prefs/pref_value_map.cc3
-rw-r--r--chromium/base/prefs/pref_value_map.h2
-rw-r--r--chromium/base/prefs/pref_value_store.cc2
-rw-r--r--chromium/base/prefs/pref_value_store.h2
-rw-r--r--chromium/base/prefs/scoped_user_pref_update.h2
-rw-r--r--chromium/base/prefs/testing_pref_service.h1
-rw-r--r--chromium/base/prefs/testing_pref_store.cc14
-rw-r--r--chromium/base/prefs/testing_pref_store.h12
-rw-r--r--chromium/base/prefs/value_map_pref_store.cc13
-rw-r--r--chromium/base/prefs/value_map_pref_store.h12
-rw-r--r--chromium/base/prefs/writeable_pref_store.h14
-rw-r--r--chromium/base/process/BUILD.gn115
-rw-r--r--chromium/base/process/internal_linux.cc9
-rw-r--r--chromium/base/process/internal_linux.h8
-rw-r--r--chromium/base/process/kill.h1
-rw-r--r--chromium/base/process/kill_mac.cc1
-rw-r--r--chromium/base/process/kill_posix.cc3
-rw-r--r--chromium/base/process/kill_win.cc10
-rw-r--r--chromium/base/process/launch.cc1
-rw-r--r--chromium/base/process/launch.h5
-rw-r--r--chromium/base/process/launch_posix.cc2
-rw-r--r--chromium/base/process/launch_win.cc10
-rw-r--r--chromium/base/process/memory.cc1
-rw-r--r--chromium/base/process/memory.h3
-rw-r--r--chromium/base/process/memory_linux.cc3
-rw-r--r--chromium/base/process/memory_mac.mm2
-rw-r--r--chromium/base/process/memory_stubs.cc21
-rw-r--r--chromium/base/process/memory_unittest.cc3
-rw-r--r--chromium/base/process/memory_unittest_mac.h5
-rw-r--r--chromium/base/process/memory_unittest_mac.mm1
-rw-r--r--chromium/base/process/memory_win.cc1
-rw-r--r--chromium/base/process/port_provider_mac.cc27
-rw-r--r--chromium/base/process/port_provider_mac.h34
-rw-r--r--chromium/base/process/process.h24
-rw-r--r--chromium/base/process/process_handle.cc52
-rw-r--r--chromium/base/process/process_handle.h38
-rw-r--r--chromium/base/process/process_handle_freebsd.cc3
-rw-r--r--chromium/base/process/process_handle_mac.cc1
-rw-r--r--chromium/base/process/process_handle_openbsd.cc2
-rw-r--r--chromium/base/process/process_handle_win.cc17
-rw-r--r--chromium/base/process/process_info.h1
-rw-r--r--chromium/base/process/process_info_linux.cc5
-rw-r--r--chromium/base/process/process_info_mac.cc3
-rw-r--r--chromium/base/process/process_info_win.cc16
-rw-r--r--chromium/base/process/process_iterator.cc1
-rw-r--r--chromium/base/process/process_iterator.h4
-rw-r--r--chromium/base/process/process_iterator_freebsd.cc3
-rw-r--r--chromium/base/process/process_iterator_linux.cc2
-rw-r--r--chromium/base/process/process_iterator_mac.cc2
-rw-r--r--chromium/base/process/process_iterator_openbsd.cc2
-rw-r--r--chromium/base/process/process_linux.cc98
-rw-r--r--chromium/base/process/process_metrics.cc21
-rw-r--r--chromium/base/process/process_metrics.h62
-rw-r--r--chromium/base/process/process_metrics_freebsd.cc2
-rw-r--r--chromium/base/process/process_metrics_ios.cc2
-rw-r--r--chromium/base/process/process_metrics_linux.cc99
-rw-r--r--chromium/base/process/process_metrics_mac.cc12
-rw-r--r--chromium/base/process/process_metrics_nacl.cc16
-rw-r--r--chromium/base/process/process_metrics_openbsd.cc5
-rw-r--r--chromium/base/process/process_metrics_posix.cc9
-rw-r--r--chromium/base/process/process_metrics_unittest.cc164
-rw-r--r--chromium/base/process/process_metrics_win.cc15
-rw-r--r--chromium/base/process/process_posix.cc25
-rw-r--r--chromium/base/process/process_unittest.cc23
-rw-r--r--chromium/base/process/process_util_unittest.cc17
-rw-r--r--chromium/base/process/process_win.cc19
-rw-r--r--chromium/base/profiler/OWNERS5
-rw-r--r--chromium/base/profiler/alternate_timer.cc4
-rw-r--r--chromium/base/profiler/native_stack_sampler.cc4
-rw-r--r--chromium/base/profiler/native_stack_sampler.h25
-rw-r--r--chromium/base/profiler/native_stack_sampler_posix.cc3
-rw-r--r--chromium/base/profiler/native_stack_sampler_win.cc355
-rw-r--r--chromium/base/profiler/scoped_profile.h1
-rw-r--r--chromium/base/profiler/scoped_tracker.h1
-rw-r--r--chromium/base/profiler/stack_sampling_profiler.cc31
-rw-r--r--chromium/base/profiler/stack_sampling_profiler.h14
-rw-r--r--chromium/base/profiler/stack_sampling_profiler_unittest.cc601
-rw-r--r--chromium/base/profiler/test_support_library.cc30
-rw-r--r--chromium/base/profiler/tracked_time.cc11
-rw-r--r--chromium/base/profiler/tracked_time.h14
-rw-r--r--chromium/base/profiler/tracked_time_unittest.cc6
-rw-r--r--chromium/base/profiler/win32_stack_frame_unwinder.cc243
-rw-r--r--chromium/base/profiler/win32_stack_frame_unwinder.h66
-rw-r--r--chromium/base/profiler/win32_stack_frame_unwinder_unittest.cc258
-rw-r--r--chromium/base/rand_util.cc24
-rw-r--r--chromium/base/rand_util.h13
-rw-r--r--chromium/base/rand_util_nacl.cc7
-rw-r--r--chromium/base/rand_util_posix.cc6
-rw-r--r--chromium/base/rand_util_unittest.cc34
-rw-r--r--chromium/base/rand_util_win.cc6
-rw-r--r--chromium/base/run_loop.cc1
-rw-r--r--chromium/base/run_loop.h6
-rw-r--r--chromium/base/scoped_clear_errno.h2
-rw-r--r--chromium/base/scoped_generic.h3
-rw-r--r--chromium/base/scoped_generic_unittest.cc12
-rw-r--r--chromium/base/scoped_native_library.h3
-rw-r--r--chromium/base/scoped_native_library_unittest.cc8
-rw-r--r--chromium/base/scoped_observer.h8
-rw-r--r--chromium/base/security_unittest.cc3
-rw-r--r--chromium/base/sequence_checker_impl.h2
-rw-r--r--chromium/base/sequence_checker_unittest.cc19
-rw-r--r--chromium/base/sequenced_task_runner_helpers.h2
-rw-r--r--chromium/base/sha1.h2
-rw-r--r--chromium/base/sha1_portable.cc29
-rw-r--r--chromium/base/sha1_unittest.cc3
-rw-r--r--chromium/base/stl_util.h13
-rw-r--r--chromium/base/strings/latin1_string_conversions.h2
-rw-r--r--chromium/base/strings/safe_sprintf.cc27
-rw-r--r--chromium/base/strings/safe_sprintf.h1
-rw-r--r--chromium/base/strings/safe_sprintf_unittest.cc4
-rw-r--r--chromium/base/strings/string16.h9
-rw-r--r--chromium/base/strings/string_number_conversions.cc74
-rw-r--r--chromium/base/strings/string_number_conversions.h28
-rw-r--r--chromium/base/strings/string_number_conversions_unittest.cc427
-rw-r--r--chromium/base/strings/string_piece.cc4
-rw-r--r--chromium/base/strings/string_piece.h6
-rw-r--r--chromium/base/strings/string_piece_unittest.cc2
-rw-r--r--chromium/base/strings/string_split.cc60
-rw-r--r--chromium/base/strings/string_split.h23
-rw-r--r--chromium/base/strings/string_split_unittest.cc68
-rw-r--r--chromium/base/strings/string_util.cc52
-rw-r--r--chromium/base/strings/string_util.h27
-rw-r--r--chromium/base/strings/string_util_posix.h1
-rw-r--r--chromium/base/strings/string_util_unittest.cc28
-rw-r--r--chromium/base/strings/string_util_win.h1
-rw-r--r--chromium/base/strings/stringprintf.cc3
-rw-r--r--chromium/base/strings/stringprintf.h33
-rw-r--r--chromium/base/strings/stringprintf_unittest.cc14
-rw-r--r--chromium/base/strings/sys_string_conversions.h8
-rw-r--r--chromium/base/strings/sys_string_conversions_mac.mm1
-rw-r--r--chromium/base/strings/sys_string_conversions_posix.cc2
-rw-r--r--chromium/base/strings/sys_string_conversions_unittest.cc5
-rw-r--r--chromium/base/strings/sys_string_conversions_win.cc5
-rw-r--r--chromium/base/strings/utf_offset_string_conversions.cc8
-rw-r--r--chromium/base/strings/utf_offset_string_conversions.h2
-rw-r--r--chromium/base/strings/utf_offset_string_conversions_unittest.cc3
-rw-r--r--chromium/base/strings/utf_string_conversion_utils.cc26
-rw-r--r--chromium/base/strings/utf_string_conversion_utils.h31
-rw-r--r--chromium/base/strings/utf_string_conversions.cc9
-rw-r--r--chromium/base/strings/utf_string_conversions.h2
-rw-r--r--chromium/base/strings/utf_string_conversions_unittest.cc25
-rw-r--r--chromium/base/supports_user_data.h1
-rw-r--r--chromium/base/sync_socket.h13
-rw-r--r--chromium/base/sync_socket_nacl.cc1
-rw-r--r--chromium/base/sync_socket_posix.cc2
-rw-r--r--chromium/base/sync_socket_unittest.cc13
-rw-r--r--chromium/base/sync_socket_win.cc6
-rw-r--r--chromium/base/synchronization/cancellation_flag.h3
-rw-r--r--chromium/base/synchronization/condition_variable.h9
-rw-r--r--chromium/base/synchronization/condition_variable_posix.cc4
-rw-r--r--chromium/base/synchronization/condition_variable_unittest.cc1
-rw-r--r--chromium/base/synchronization/condition_variable_win.cc1
-rw-r--r--chromium/base/synchronization/lock.h2
-rw-r--r--chromium/base/synchronization/lock_impl.h5
-rw-r--r--chromium/base/synchronization/lock_unittest.cc1
-rw-r--r--chromium/base/synchronization/waitable_event.h5
-rw-r--r--chromium/base/synchronization/waitable_event_posix.cc4
-rw-r--r--chromium/base/synchronization/waitable_event_unittest.cc3
-rw-r--r--chromium/base/synchronization/waitable_event_watcher_posix.cc1
-rw-r--r--chromium/base/synchronization/waitable_event_watcher_unittest.cc2
-rw-r--r--chromium/base/synchronization/waitable_event_win.cc1
-rw-r--r--chromium/base/sys_byteorder.h33
-rw-r--r--chromium/base/sys_info.cc7
-rw-r--r--chromium/base/sys_info.h24
-rw-r--r--chromium/base/sys_info_android.cc48
-rw-r--r--chromium/base/sys_info_chromeos.cc23
-rw-r--r--chromium/base/sys_info_freebsd.cc10
-rw-r--r--chromium/base/sys_info_internal.h2
-rw-r--r--chromium/base/sys_info_ios.mm21
-rw-r--r--chromium/base/sys_info_linux.cc24
-rw-r--r--chromium/base/sys_info_mac.cc23
-rw-r--r--chromium/base/sys_info_openbsd.cc15
-rw-r--r--chromium/base/sys_info_posix.cc14
-rw-r--r--chromium/base/sys_info_unittest.cc35
-rw-r--r--chromium/base/sys_info_win.cc30
-rw-r--r--chromium/base/system_monitor/system_monitor.h2
-rw-r--r--chromium/base/system_monitor/system_monitor_unittest.cc1
-rw-r--r--chromium/base/task/cancelable_task_tracker.cc6
-rw-r--r--chromium/base/task/cancelable_task_tracker.h6
-rw-r--r--chromium/base/task_runner.h3
-rw-r--r--chromium/base/task_runner_util_unittest.cc6
-rw-r--r--chromium/base/template_util.h8
-rw-r--r--chromium/base/template_util_unittest.cc132
-rw-r--r--chromium/base/third_party/dynamic_annotations/BUILD.gn3
-rw-r--r--chromium/base/third_party/icu/icu_utf.cc65
-rw-r--r--chromium/base/third_party/icu/icu_utf.h163
-rw-r--r--chromium/base/third_party/libevent/BUILD.gn55
-rw-r--r--chromium/base/third_party/libevent/ChangeLog253
-rw-r--r--chromium/base/third_party/libevent/Doxyfile230
-rw-r--r--chromium/base/third_party/libevent/LICENSE53
-rw-r--r--chromium/base/third_party/libevent/Makefile.am152
-rw-r--r--chromium/base/third_party/libevent/Makefile.nmake48
-rw-r--r--chromium/base/third_party/libevent/README57
-rw-r--r--chromium/base/third_party/libevent/README.chromium35
-rw-r--r--chromium/base/third_party/libevent/android/config.h266
-rw-r--r--chromium/base/third_party/libevent/android/event-config.h281
-rwxr-xr-xchromium/base/third_party/libevent/autogen.sh15
-rw-r--r--chromium/base/third_party/libevent/buffer.c554
-rw-r--r--chromium/base/third_party/libevent/chromium.patch200
-rw-r--r--chromium/base/third_party/libevent/compat/sys/_libevent_time.h163
-rw-r--r--chromium/base/third_party/libevent/compat/sys/queue.h488
-rw-r--r--chromium/base/third_party/libevent/configure.in421
-rw-r--r--chromium/base/third_party/libevent/devpoll.c417
-rw-r--r--chromium/base/third_party/libevent/epoll.c377
-rw-r--r--chromium/base/third_party/libevent/epoll_sub.c52
-rw-r--r--chromium/base/third_party/libevent/evbuffer.c455
-rw-r--r--chromium/base/third_party/libevent/evdns.3322
-rw-r--r--chromium/base/third_party/libevent/evdns.c3192
-rw-r--r--chromium/base/third_party/libevent/evdns.h528
-rw-r--r--chromium/base/third_party/libevent/event-config.h22
-rw-r--r--chromium/base/third_party/libevent/event-internal.h101
-rw-r--r--chromium/base/third_party/libevent/event.3624
-rw-r--r--chromium/base/third_party/libevent/event.c1017
-rw-r--r--chromium/base/third_party/libevent/event.h1212
-rwxr-xr-xchromium/base/third_party/libevent/event_rpcgen.py1423
-rw-r--r--chromium/base/third_party/libevent/event_tagging.c443
-rw-r--r--chromium/base/third_party/libevent/evhttp.h375
-rw-r--r--chromium/base/third_party/libevent/evport.c519
-rw-r--r--chromium/base/third_party/libevent/evrpc-internal.h87
-rw-r--r--chromium/base/third_party/libevent/evrpc.c657
-rw-r--r--chromium/base/third_party/libevent/evrpc.h486
-rw-r--r--chromium/base/third_party/libevent/evsignal.h52
-rw-r--r--chromium/base/third_party/libevent/evutil.c284
-rw-r--r--chromium/base/third_party/libevent/evutil.h186
-rw-r--r--chromium/base/third_party/libevent/freebsd/config.h266
-rw-r--r--chromium/base/third_party/libevent/freebsd/event-config.h284
-rw-r--r--chromium/base/third_party/libevent/http-internal.h154
-rw-r--r--chromium/base/third_party/libevent/http.c2885
-rw-r--r--chromium/base/third_party/libevent/kqueue.c455
-rw-r--r--chromium/base/third_party/libevent/libevent.gyp64
-rw-r--r--chromium/base/third_party/libevent/libevent_nacl_nonsfi.gyp47
-rw-r--r--chromium/base/third_party/libevent/linux/config.h266
-rw-r--r--chromium/base/third_party/libevent/linux/event-config.h284
-rw-r--r--chromium/base/third_party/libevent/log.c187
-rw-r--r--chromium/base/third_party/libevent/log.h51
-rw-r--r--chromium/base/third_party/libevent/m4/.dummy1
-rw-r--r--chromium/base/third_party/libevent/mac/config.h266
-rw-r--r--chromium/base/third_party/libevent/mac/event-config.h284
-rw-r--r--chromium/base/third_party/libevent/min_heap.h149
-rw-r--r--chromium/base/third_party/libevent/nacl_nonsfi/config.h273
-rw-r--r--chromium/base/third_party/libevent/nacl_nonsfi/event-config.h290
-rw-r--r--chromium/base/third_party/libevent/nacl_nonsfi/random.c13
-rw-r--r--chromium/base/third_party/libevent/nacl_nonsfi/signal_stub.c48
-rw-r--r--chromium/base/third_party/libevent/poll.c379
-rw-r--r--chromium/base/third_party/libevent/sample/Makefile.am14
-rw-r--r--chromium/base/third_party/libevent/sample/event-test.c139
-rw-r--r--chromium/base/third_party/libevent/sample/signal-test.c65
-rw-r--r--chromium/base/third_party/libevent/sample/time-test.c70
-rw-r--r--chromium/base/third_party/libevent/select.c364
-rw-r--r--chromium/base/third_party/libevent/signal.c377
-rw-r--r--chromium/base/third_party/libevent/solaris/config.h266
-rw-r--r--chromium/base/third_party/libevent/solaris/event-config.h284
-rw-r--r--chromium/base/third_party/libevent/stamp-h.in1
-rw-r--r--chromium/base/third_party/libevent/strlcpy-internal.h23
-rw-r--r--chromium/base/third_party/libevent/strlcpy.c76
-rw-r--r--chromium/base/third_party/libevent/whatsnew-14.txt167
-rw-r--r--chromium/base/third_party/nspr/prtime.cc2
-rw-r--r--chromium/base/third_party/symbolize/README.chromium3
-rw-r--r--chromium/base/third_party/symbolize/symbolize.cc2
-rw-r--r--chromium/base/third_party/symbolize/symbolize.h2
-rw-r--r--chromium/base/third_party/symbolize/utilities.h2
-rw-r--r--chromium/base/thread_task_runner_handle.h1
-rw-r--r--chromium/base/threading/non_thread_safe_unittest.cc2
-rw-r--r--chromium/base/threading/platform_thread.h4
-rw-r--r--chromium/base/threading/platform_thread_android.cc1
-rw-r--r--chromium/base/threading/platform_thread_freebsd.cc6
-rw-r--r--chromium/base/threading/platform_thread_linux.cc2
-rw-r--r--chromium/base/threading/platform_thread_mac.mm2
-rw-r--r--chromium/base/threading/platform_thread_posix.cc7
-rw-r--r--chromium/base/threading/platform_thread_unittest.cc3
-rw-r--r--chromium/base/threading/platform_thread_win.cc2
-rw-r--r--chromium/base/threading/post_task_and_reply_impl.cc3
-rw-r--r--chromium/base/threading/sequenced_task_runner_handle.cc31
-rw-r--r--chromium/base/threading/sequenced_task_runner_handle.h37
-rw-r--r--chromium/base/threading/sequenced_task_runner_handle_unittest.cc102
-rw-r--r--chromium/base/threading/sequenced_worker_pool.cc152
-rw-r--r--chromium/base/threading/sequenced_worker_pool.h46
-rw-r--r--chromium/base/threading/sequenced_worker_pool_unittest.cc208
-rw-r--r--chromium/base/threading/simple_thread.h7
-rw-r--r--chromium/base/threading/thread.cc9
-rw-r--r--chromium/base/threading/thread.h4
-rw-r--r--chromium/base/threading/thread_checker_unittest.cc4
-rw-r--r--chromium/base/threading/thread_collision_warner.h2
-rw-r--r--chromium/base/threading/thread_collision_warner_unittest.cc1
-rw-r--r--chromium/base/threading/thread_id_name_manager.h2
-rw-r--r--chromium/base/threading/thread_local.h3
-rw-r--r--chromium/base/threading/thread_local_posix.cc1
-rw-r--r--chromium/base/threading/thread_local_storage.cc7
-rw-r--r--chromium/base/threading/thread_local_storage.h5
-rw-r--r--chromium/base/threading/thread_local_storage_unittest.cc2
-rw-r--r--chromium/base/threading/thread_perftest.cc7
-rw-r--r--chromium/base/threading/thread_restrictions.h33
-rw-r--r--chromium/base/threading/thread_unittest.cc3
-rw-r--r--chromium/base/threading/watchdog.h1
-rw-r--r--chromium/base/threading/watchdog_unittest.cc1
-rw-r--r--chromium/base/threading/worker_pool.cc1
-rw-r--r--chromium/base/threading/worker_pool.h17
-rw-r--r--chromium/base/threading/worker_pool_posix.cc192
-rw-r--r--chromium/base/threading/worker_pool_posix.h60
-rw-r--r--chromium/base/threading/worker_pool_posix_unittest.cc178
-rw-r--r--chromium/base/threading/worker_pool_unittest.cc1
-rw-r--r--chromium/base/threading/worker_pool_win.cc6
-rw-r--r--chromium/base/time/pr_time_unittest.cc2
-rw-r--r--chromium/base/time/time.cc45
-rw-r--r--chromium/base/time/time.h240
-rw-r--r--chromium/base/time/time_mac.cc37
-rw-r--r--chromium/base/time/time_posix.cc69
-rw-r--r--chromium/base/time/time_unittest.cc34
-rw-r--r--chromium/base/time/time_win.cc154
-rw-r--r--chromium/base/time/time_win_unittest.cc95
-rw-r--r--chromium/base/timer/hi_res_timer_manager.h2
-rw-r--r--chromium/base/timer/hi_res_timer_manager_unittest.cc5
-rw-r--r--chromium/base/timer/mock_timer_unittest.cc1
-rw-r--r--chromium/base/timer/timer.h2
-rw-r--r--chromium/base/timer/timer_unittest.cc4
-rw-r--r--chromium/base/tools_sanity_unittest.cc3
-rw-r--r--chromium/base/trace_event/BUILD.gn127
-rw-r--r--chromium/base/trace_event/OWNERS3
-rw-r--r--chromium/base/trace_event/common/trace_event_common.h (renamed from chromium/base/trace_event/trace_event_common.h)86
-rw-r--r--chromium/base/trace_event/etw_manifest/BUILD.gn47
-rw-r--r--chromium/base/trace_event/etw_manifest/BUILD/message_compiler.py16
-rw-r--r--chromium/base/trace_event/heap_profiler_allocation_context.cc67
-rw-r--r--chromium/base/trace_event/heap_profiler_allocation_context.h97
-rw-r--r--chromium/base/trace_event/heap_profiler_allocation_context_tracker.cc115
-rw-r--r--chromium/base/trace_event/heap_profiler_allocation_context_tracker.h73
-rw-r--r--chromium/base/trace_event/heap_profiler_allocation_context_tracker_unittest.cc225
-rw-r--r--chromium/base/trace_event/heap_profiler_allocation_register.cc197
-rw-r--r--chromium/base/trace_event/heap_profiler_allocation_register.h176
-rw-r--r--chromium/base/trace_event/heap_profiler_allocation_register_posix.cc59
-rw-r--r--chromium/base/trace_event/heap_profiler_allocation_register_unittest.cc286
-rw-r--r--chromium/base/trace_event/heap_profiler_allocation_register_win.cc63
-rw-r--r--chromium/base/trace_event/heap_profiler_heap_dump_writer.cc300
-rw-r--r--chromium/base/trace_event/heap_profiler_heap_dump_writer.h106
-rw-r--r--chromium/base/trace_event/heap_profiler_heap_dump_writer_unittest.cc236
-rw-r--r--chromium/base/trace_event/heap_profiler_stack_frame_deduplicator.cc115
-rw-r--r--chromium/base/trace_event/heap_profiler_stack_frame_deduplicator.h79
-rw-r--r--chromium/base/trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc134
-rw-r--r--chromium/base/trace_event/heap_profiler_type_name_deduplicator.cc76
-rw-r--r--chromium/base/trace_event/heap_profiler_type_name_deduplicator.h46
-rw-r--r--chromium/base/trace_event/heap_profiler_type_name_deduplicator_unittest.cc71
-rw-r--r--chromium/base/trace_event/java_heap_dump_provider_android.h1
-rw-r--r--chromium/base/trace_event/malloc_dump_provider.cc76
-rw-r--r--chromium/base/trace_event/malloc_dump_provider.h7
-rw-r--r--chromium/base/trace_event/memory_allocator_dump.cc6
-rw-r--r--chromium/base/trace_event/memory_allocator_dump.h6
-rw-r--r--chromium/base/trace_event/memory_allocator_dump_guid.cc7
-rw-r--r--chromium/base/trace_event/memory_allocator_dump_guid.h9
-rw-r--r--chromium/base/trace_event/memory_allocator_dump_unittest.cc9
-rw-r--r--chromium/base/trace_event/memory_dump_manager.cc521
-rw-r--r--chromium/base/trace_event/memory_dump_manager.h183
-rw-r--r--chromium/base/trace_event/memory_dump_manager_unittest.cc500
-rw-r--r--chromium/base/trace_event/memory_dump_provider.h20
-rw-r--r--chromium/base/trace_event/memory_dump_request_args.h5
-rw-r--r--chromium/base/trace_event/memory_dump_session_state.cc7
-rw-r--r--chromium/base/trace_event/memory_dump_session_state.h28
-rw-r--r--chromium/base/trace_event/memory_profiler_allocation_context.cc91
-rw-r--r--chromium/base/trace_event/memory_profiler_allocation_context.h119
-rw-r--r--chromium/base/trace_event/memory_profiler_allocation_context_unittest.cc210
-rw-r--r--chromium/base/trace_event/process_memory_dump.cc92
-rw-r--r--chromium/base/trace_event/process_memory_dump.h34
-rw-r--r--chromium/base/trace_event/process_memory_dump_unittest.cc28
-rw-r--r--chromium/base/trace_event/process_memory_maps.cc6
-rw-r--r--chromium/base/trace_event/process_memory_maps.h28
-rw-r--r--chromium/base/trace_event/process_memory_maps_dump_provider.cc134
-rw-r--r--chromium/base/trace_event/process_memory_maps_dump_provider.h8
-rw-r--r--chromium/base/trace_event/process_memory_maps_dump_provider_unittest.cc49
-rw-r--r--chromium/base/trace_event/process_memory_totals.cc12
-rw-r--r--chromium/base/trace_event/process_memory_totals.h24
-rw-r--r--chromium/base/trace_event/process_memory_totals_dump_provider.cc34
-rw-r--r--chromium/base/trace_event/process_memory_totals_dump_provider.h5
-rw-r--r--chromium/base/trace_event/process_memory_totals_dump_provider_unittest.cc8
-rw-r--r--chromium/base/trace_event/trace_buffer.cc36
-rw-r--r--chromium/base/trace_event/trace_buffer.h11
-rw-r--r--chromium/base/trace_event/trace_config.cc45
-rw-r--r--chromium/base/trace_event/trace_config.h9
-rw-r--r--chromium/base/trace_event/trace_config_unittest.cc9
-rw-r--r--chromium/base/trace_event/trace_event.gypi63
-rw-r--r--chromium/base/trace_event/trace_event.h211
-rw-r--r--chromium/base/trace_event/trace_event_android.cc37
-rw-r--r--chromium/base/trace_event/trace_event_android_unittest.cc22
-rw-r--r--chromium/base/trace_event/trace_event_argument.cc46
-rw-r--r--chromium/base/trace_event/trace_event_argument.h28
-rw-r--r--chromium/base/trace_event/trace_event_argument_unittest.cc9
-rw-r--r--chromium/base/trace_event/trace_event_etw_export_win.cc25
-rw-r--r--chromium/base/trace_event/trace_event_etw_export_win.h18
-rw-r--r--chromium/base/trace_event/trace_event_impl.cc88
-rw-r--r--chromium/base/trace_event/trace_event_impl.h34
-rw-r--r--chromium/base/trace_event/trace_event_memory.cc436
-rw-r--r--chromium/base/trace_event/trace_event_memory.h171
-rw-r--r--chromium/base/trace_event/trace_event_memory_overhead.h3
-rw-r--r--chromium/base/trace_event/trace_event_memory_unittest.cc236
-rw-r--r--chromium/base/trace_event/trace_event_synthetic_delay.cc1
-rw-r--r--chromium/base/trace_event/trace_event_synthetic_delay.h1
-rw-r--r--chromium/base/trace_event/trace_event_synthetic_delay_unittest.cc9
-rw-r--r--chromium/base/trace_event/trace_event_system_stats_monitor.cc1
-rw-r--r--chromium/base/trace_event/trace_event_system_stats_monitor.h1
-rw-r--r--chromium/base/trace_event/trace_event_system_stats_monitor_unittest.cc2
-rw-r--r--chromium/base/trace_event/trace_event_unittest.cc231
-rw-r--r--chromium/base/trace_event/trace_event_win.cc132
-rw-r--r--chromium/base/trace_event/trace_event_win.h125
-rw-r--r--chromium/base/trace_event/trace_event_win_unittest.cc319
-rw-r--r--chromium/base/trace_event/trace_log.cc203
-rw-r--r--chromium/base/trace_event/trace_log.h85
-rw-r--r--chromium/base/trace_event/trace_sampling_thread.cc4
-rw-r--r--chromium/base/trace_event/tracing_agent.cc24
-rw-r--r--chromium/base/trace_event/tracing_agent.h92
-rw-r--r--chromium/base/trace_event/winheap_dump_provider_win.h3
-rw-r--r--chromium/base/trace_event/winheap_dump_provider_win_unittest.cc2
-rw-r--r--chromium/base/tracked_objects.cc106
-rw-r--r--chromium/base/tracked_objects.h98
-rw-r--r--chromium/base/tracked_objects_unittest.cc21
-rw-r--r--chromium/base/tuple.h40
-rw-r--r--chromium/base/value_conversions.cc5
-rw-r--r--chromium/base/values.cc15
-rw-r--r--chromium/base/values.h8
-rw-r--r--chromium/base/values_unittest.cc79
-rw-r--r--chromium/base/version.h3
-rw-r--r--chromium/base/version_unittest.cc4
-rw-r--r--chromium/base/vlog.cc5
-rw-r--r--chromium/base/vlog.h2
-rw-r--r--chromium/base/vlog_unittest.cc1
-rw-r--r--chromium/base/win/OWNERS2
-rw-r--r--chromium/base/win/enum_variant_unittest.cc18
-rw-r--r--chromium/base/win/event_trace_consumer.h4
-rw-r--r--chromium/base/win/event_trace_consumer_unittest.cc15
-rw-r--r--chromium/base/win/event_trace_controller.h3
-rw-r--r--chromium/base/win/event_trace_controller_unittest.cc57
-rw-r--r--chromium/base/win/event_trace_provider.h10
-rw-r--r--chromium/base/win/event_trace_provider_unittest.cc48
-rw-r--r--chromium/base/win/i18n.cc6
-rw-r--r--chromium/base/win/i18n.h1
-rw-r--r--chromium/base/win/i18n_unittest.cc2
-rw-r--r--chromium/base/win/iat_patch_function.cc5
-rw-r--r--chromium/base/win/iat_patch_function.h2
-rw-r--r--chromium/base/win/iunknown_impl_unittest.cc8
-rw-r--r--chromium/base/win/message_window.cc1
-rw-r--r--chromium/base/win/message_window.h2
-rw-r--r--chromium/base/win/metro.cc110
-rw-r--r--chromium/base/win/metro.h125
-rw-r--r--chromium/base/win/object_watcher.h1
-rw-r--r--chromium/base/win/pe_image.cc122
-rw-r--r--chromium/base/win/pe_image.h6
-rw-r--r--chromium/base/win/pe_image_test.cc2
-rw-r--r--chromium/base/win/pe_image_unittest.cc65
-rw-r--r--chromium/base/win/process_startup_helper.cc55
-rw-r--r--chromium/base/win/process_startup_helper.h26
-rw-r--r--chromium/base/win/registry.cc14
-rw-r--r--chromium/base/win/registry.h14
-rw-r--r--chromium/base/win/registry_unittest.cc11
-rw-r--r--chromium/base/win/resource_util.h2
-rw-r--r--chromium/base/win/scoped_bstr.cc8
-rw-r--r--chromium/base/win/scoped_bstr.h2
-rw-r--r--chromium/base/win/scoped_bstr_unittest.cc15
-rw-r--r--chromium/base/win/scoped_co_mem.h2
-rw-r--r--chromium/base/win/scoped_com_initializer.h2
-rw-r--r--chromium/base/win/scoped_comptr.h5
-rw-r--r--chromium/base/win/scoped_gdi_object.h62
-rw-r--r--chromium/base/win/scoped_handle.cc6
-rw-r--r--chromium/base/win/scoped_handle.h18
-rw-r--r--chromium/base/win/scoped_hdc.h2
-rw-r--r--chromium/base/win/scoped_hglobal.h3
-rw-r--r--chromium/base/win/scoped_process_information.h2
-rw-r--r--chromium/base/win/scoped_process_information_unittest.cc4
-rw-r--r--chromium/base/win/scoped_propvariant.h2
-rw-r--r--chromium/base/win/scoped_select_object.h2
-rw-r--r--chromium/base/win/scoped_variant.cc19
-rw-r--r--chromium/base/win/scoped_variant.h19
-rw-r--r--chromium/base/win/scoped_variant_unittest.cc22
-rw-r--r--chromium/base/win/shortcut.cc142
-rw-r--r--chromium/base/win/shortcut.h29
-rw-r--r--chromium/base/win/shortcut_unittest.cc5
-rw-r--r--chromium/base/win/startup_information.h5
-rw-r--r--chromium/base/win/startup_information_unittest.cc1
-rw-r--r--chromium/base/win/win_util.cc114
-rw-r--r--chromium/base/win/win_util.h34
-rw-r--r--chromium/base/win/win_util_unittest.cc2
-rw-r--r--chromium/base/win/windows_version.h4
947 files changed, 41827 insertions, 11694 deletions
diff --git a/chromium/base/BUILD.gn b/chromium/base/BUILD.gn
index 2cb2f6dc586..1265df839b5 100644
--- a/chromium/base/BUILD.gn
+++ b/chromium/base/BUILD.gn
@@ -2,14 +2,42 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+# HOW TO WRITE CONDITIONALS IN THIS FILE
+# ======================================
+#
+# In many other places, one would write a conditional that expresses all the
+# cases when a source file is used or unused, and then either add or subtract
+# it from the sources list in that case
+#
+# Since base includes so many low-level things that vary widely and
+# unpredictably for the various build types, we prefer a slightly different
+# style. Instead, there are big per-platform blocks of inclusions and
+# exclusions. If a given file has an inclusion or exclusion rule that applies
+# for multiple conditions, perfer to duplicate it in both lists. This makes it
+# a bit easier to see which files apply in which cases rather than having a
+# huge sequence of random-looking conditionals.
+
+import("//build/buildflag_header.gni")
import("//build/config/compiler/compiler.gni")
+import("//build/config/nacl/config.gni")
import("//build/config/ui.gni")
+import("//build/nocompile.gni")
import("//testing/test.gni")
if (is_android) {
import("//build/config/android/rules.gni")
}
+config("base_flags") {
+ if (is_clang) {
+ cflags = [
+ # Don't die on dtoa code that uses a char as an array index.
+ # This is required solely for base/third_party/dmg_fp/dtoa_wrapper.cc.
+ "-Wno-char-subscripts",
+ ]
+ }
+}
+
config("base_implementation") {
defines = [ "BASE_IMPLEMENTATION" ]
}
@@ -26,43 +54,72 @@ if (is_win) {
}
}
-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 || is_ios) {
- sources -= [ "base_paths_posix.cc" ]
+if (is_nacl_nonsfi) {
+ # Must be in a config because of how GN orders flags (otherwise -Wall will
+ # appear after this, and turn it back on).
+ config("nacl_nonsfi_warnings") {
+ # file_util_posix.cc contains a function which is not
+ # being used by nacl_helper_nonsfi.
+ cflags = [ "-Wno-unused-function" ]
}
+}
- if (is_nacl) {
- sources -= [
+if (is_nacl) {
+ # None of the files apply to nacl, and we can't make an empty static library.
+ group("base_paths") {
+ }
+} else {
+ static_library("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",
]
- }
- configs += [ ":base_implementation" ]
+ if (is_android || is_mac || is_ios) {
+ sources -= [ "base_paths_posix.cc" ]
+ }
- deps = [
- "//base/memory",
- "//base/process",
- ]
+ configs += [ ":base_implementation" ]
+
+ visibility = [ ":base" ]
+ }
+}
- visibility = [ ":base" ]
+config("android_system_libs") {
+ libs = [ "log" ] # Used by logging.cc.
}
+# Base and everything it depends on should be a static library rather than
+# a source set. Base is more of a "library" in the classic sense in that many
+# small parts of it are used in many different contexts. This combined with a
+# few static initializers floating around means that dead code stripping
+# still leaves a lot of code behind that isn't always used. For example, this
+# saves more than 40K for a smaller target like chrome_elf.
+#
+# Use static libraries for the helper stuff as well like //base/debug since
+# those things refer back to base code, which will force base compilation units
+# to be linked in where they wouldn't have otherwise. This does not include
+# test code (test support and anything in the test directory) which should use
+# source_set as is recommended for GN targets).
component("base") {
+ # TODO(phosek) bug 570839: If field_trial.cc is in a static library,
+ # hacl_helper_nonsfi doesn't link properly on Linux in debug builds. The
+ # reasons for this seem to involve obscure toolchain bugs. This should be
+ # fixed and this target should always be a static_library in the
+ # non-component case.
+ component_never_use_source_set = !is_nacl_nonsfi
+
sources = [
+ "allocator/allocator_check.cc",
+ "allocator/allocator_check.h",
"allocator/allocator_extension.cc",
"allocator/allocator_extension.h",
"android/animation_frame_time_histogram.cc",
@@ -81,6 +138,8 @@ component("base") {
"android/command_line_android.h",
"android/content_uri_utils.cc",
"android/content_uri_utils.h",
+ "android/context_utils.cc",
+ "android/context_utils.h",
"android/cpu_features.cc",
"android/cxa_demangle_stub.cc",
"android/event_log.cc",
@@ -136,7 +195,6 @@ component("base") {
"atomic_ref_count.h",
"atomic_sequence_num.h",
"atomicops.h",
- "atomicops_internals_mac.h",
"atomicops_internals_portable.h",
"atomicops_internals_x86_msvc.h",
"auto_reset.h",
@@ -144,9 +202,10 @@ component("base") {
"barrier_closure.h",
"base64.cc",
"base64.h",
+ "base64url.cc",
+ "base64url.h",
"base_export.h",
"base_switches.h",
- "basictypes.h",
"big_endian.cc",
"big_endian.h",
"bind.h",
@@ -154,6 +213,7 @@ component("base") {
"bind_helpers.h",
"bind_internal.h",
"bind_internal_win.h",
+ "bit_cast.h",
"bits.h",
"build_time.cc",
"build_time.h",
@@ -171,13 +231,45 @@ component("base") {
"containers/linked_list.h",
"containers/mru_cache.h",
"containers/scoped_ptr_hash_map.h",
- "containers/scoped_ptr_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/close_handle_hook_win.cc",
+ "debug/close_handle_hook_win.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 "debug/allocator" target,
+ # but this target does not depend on "debug/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",
"deferred_sequenced_task_runner.cc",
"deferred_sequenced_task_runner.h",
"environment.cc",
@@ -256,6 +348,20 @@ component("base") {
"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",
+ "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.cc",
+ "json/json_value_converter.h",
+ "json/json_writer.cc",
+ "json/json_writer.h",
+ "json/string_escape.cc",
+ "json/string_escape.h",
"lazy_instance.cc",
"lazy_instance.h",
"linux_util.cc",
@@ -318,6 +424,49 @@ component("base") {
"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_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/memory_pressure_monitor_chromeos.cc",
+ "memory/memory_pressure_monitor_chromeos.h",
+ "memory/memory_pressure_monitor_mac.cc",
+ "memory/memory_pressure_monitor_mac.h",
+ "memory/memory_pressure_monitor_win.cc",
+ "memory/memory_pressure_monitor_win.h",
+ "memory/ptr_util.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_policy.h",
+ "memory/scoped_ptr.h",
+ "memory/scoped_vector.h",
+ "memory/shared_memory.h",
+ "memory/shared_memory_android.cc",
+ "memory/shared_memory_handle.h",
+ "memory/shared_memory_handle_mac.cc",
+ "memory/shared_memory_handle_win.cc",
+ "memory/shared_memory_mac.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",
@@ -340,6 +489,35 @@ component("base") {
"message_loop/message_pump_mac.mm",
"message_loop/message_pump_win.cc",
"message_loop/message_pump_win.h",
+ "metrics/bucket_ranges.cc",
+ "metrics/bucket_ranges.h",
+ "metrics/field_trial.cc",
+ "metrics/field_trial.h",
+ "metrics/histogram.cc",
+ "metrics/histogram.h",
+ "metrics/histogram_base.cc",
+ "metrics/histogram_base.h",
+ "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/metrics_hashes.cc",
+ "metrics/metrics_hashes.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/user_metrics.cc",
+ "metrics/user_metrics.h",
+ "metrics/user_metrics_action.h",
"move.h",
"native_library.h",
"native_library_ios.mm",
@@ -388,6 +566,63 @@ 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/port_provider_mac.cc",
+ "process/port_provider_mac.h",
+ "process/process.h",
+ "process/process_handle.cc",
+
+ #"process/process_handle_freebsd.cc", # Unused in Chromium build.
+ "process/process_handle_linux.cc",
+ "process/process_handle_mac.cc",
+
+ #"process/process_handle_openbsd.cc", # Unused in Chromium build.
+ "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", # Unused in Chromium build.
+ "process/process_iterator_linux.cc",
+ "process/process_iterator_mac.cc",
+
+ #"process/process_iterator_openbsd.cc", # Unused in Chromium build.
+ "process/process_iterator_win.cc",
+ "process/process_linux.cc",
+ "process/process_metrics.cc",
+ "process/process_metrics.h",
+
+ #"process/process_metrics_freebsd.cc", # Unused in Chromium build.
+ "process/process_metrics_ios.cc",
+ "process/process_metrics_linux.cc",
+ "process/process_metrics_mac.cc",
+
+ #"process/process_metrics_openbsd.cc", # Unused in Chromium build.
+ "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",
@@ -486,11 +721,13 @@ component("base") {
"sys_info.h",
"sys_info_android.cc",
"sys_info_chromeos.cc",
- "sys_info_freebsd.cc",
+
+ #"sys_info_freebsd.cc", # Unused in Chromium build.
"sys_info_ios.mm",
"sys_info_linux.cc",
"sys_info_mac.cc",
- "sys_info_openbsd.cc",
+
+ #"sys_info_openbsd.cc", # Unused in Chromium build.
"sys_info_posix.cc",
"sys_info_win.cc",
"system_monitor/system_monitor.cc",
@@ -524,6 +761,8 @@ component("base") {
"threading/platform_thread_win.cc",
"threading/post_task_and_reply_impl.cc",
"threading/post_task_and_reply_impl.h",
+ "threading/sequenced_task_runner_handle.cc",
+ "threading/sequenced_task_runner_handle.h",
"threading/sequenced_worker_pool.cc",
"threading/sequenced_worker_pool.h",
"threading/simple_thread.cc",
@@ -576,6 +815,70 @@ component("base") {
"timer/mock_timer.h",
"timer/timer.cc",
"timer/timer.h",
+ "trace_event/common/trace_event_common.h",
+ "trace_event/heap_profiler_allocation_context.cc",
+ "trace_event/heap_profiler_allocation_context.h",
+ "trace_event/heap_profiler_allocation_context_tracker.cc",
+ "trace_event/heap_profiler_allocation_context_tracker.h",
+ "trace_event/heap_profiler_allocation_register.cc",
+ "trace_event/heap_profiler_allocation_register.h",
+ "trace_event/heap_profiler_allocation_register_posix.cc",
+ "trace_event/heap_profiler_allocation_register_win.cc",
+ "trace_event/heap_profiler_heap_dump_writer.cc",
+ "trace_event/heap_profiler_heap_dump_writer.h",
+ "trace_event/heap_profiler_stack_frame_deduplicator.cc",
+ "trace_event/heap_profiler_stack_frame_deduplicator.h",
+ "trace_event/heap_profiler_type_name_deduplicator.cc",
+ "trace_event/heap_profiler_type_name_deduplicator.h",
+ "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_allocator_dump_guid.cc",
+ "trace_event/memory_allocator_dump_guid.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.cc",
+ "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.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_buffer.cc",
+ "trace_event/trace_buffer.h",
+ "trace_event/trace_config.cc",
+ "trace_event/trace_config.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_memory_overhead.cc",
+ "trace_event/trace_event_memory_overhead.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_log.cc",
+ "trace_event/trace_log.h",
+ "trace_event/trace_log_constants.cc",
+ "trace_event/trace_sampling_thread.cc",
+ "trace_event/trace_sampling_thread.h",
+ "trace_event/tracing_agent.cc",
+ "trace_event/tracing_agent.h",
+ "trace_event/winheap_dump_provider_win.cc",
+ "trace_event/winheap_dump_provider_win.h",
"tracked_objects.cc",
"tracked_objects.h",
"tracking_info.cc",
@@ -604,10 +907,10 @@ component("base") {
"win/iunknown_impl.h",
"win/message_window.cc",
"win/message_window.h",
- "win/metro.cc",
- "win/metro.h",
"win/object_watcher.cc",
"win/object_watcher.h",
+ "win/process_startup_helper.cc",
+ "win/process_startup_helper.h",
"win/registry.cc",
"win/registry.h",
"win/resource_util.cc",
@@ -640,90 +943,82 @@ component("base") {
"win/wrapped_window_proc.h",
]
- if (is_ios) {
- sources -= [
- "files/file_path_watcher.cc",
- "files/file_path_watcher.h",
- "files/file_path_watcher_fsevents.cc",
- "files/file_path_watcher_fsevents.h",
- "files/file_path_watcher_kqueue.cc",
- "files/file_path_watcher_kqueue.h",
- "message_loop/message_pump_libevent.cc",
- "message_loop/message_pump_libevent.h",
-
- # These don't work and are unused on iOS.
- "sync_socket.h",
- "sync_socket_posix.cc",
- ]
- }
-
- sources -= [
- "sys_info_freebsd.cc",
- "sys_info_openbsd.cc",
- ]
-
+ defines = []
data = []
configs += [
+ ":base_flags",
":base_implementation",
+ "//base/allocator:allocator_shim_define", # for allocator_check.cc.
"//build/config:precompiled_headers",
]
deps = [
- ":base_static",
- "//base/allocator:allocator_extension_thunks",
"//base/third_party/dynamic_annotations",
"//third_party/modp_b64",
]
public_deps = [
":base_paths",
- "//base/debug",
- "//base/json",
- "//base/memory",
- "//base/metrics",
- "//base/process",
- "//base/trace_event",
+ ":base_static",
+ ":debugging_flags",
]
# Allow more direct string conversions on platforms with native utf8
# strings
if (is_mac || is_ios || is_chromeos) {
- defines = [ "SYSTEM_NATIVE_UTF8" ]
+ defines += [ "SYSTEM_NATIVE_UTF8" ]
}
+ # Android.
if (is_android) {
- sources -= [ "power_monitor/power_monitor_device_source_posix.cc" ]
+ sources -= [
+ "debug/stack_trace_posix.cc",
+ "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",
"posix/unix_domain_socket_linux.cc",
+ "process/internal_linux.cc",
+ "process/memory_linux.cc",
+ "process/process_handle_linux.cc",
+ "process/process_iterator_linux.cc",
+ "process/process_metrics_linux.cc",
"sys_info_linux.cc",
+ "trace_event/malloc_dump_provider.cc",
+ "trace_event/malloc_dump_provider.h",
+ "trace_event/process_memory_maps_dump_provider.cc",
]
set_sources_assignment_filter(sources_assignment_filter)
deps += [
":base_jni_headers",
- "//third_party/ashmem",
"//third_party/android_tools:cpu_features",
+ "//third_party/ashmem",
]
- # logging.cc uses the Android logging library.
- libs = [ "log" ]
+ # Needs to be a public config so that dependent targets link against it as
+ # well when doing a component build.
+ public_configs = [ ":android_system_libs" ]
}
+ # Chromeos.
if (is_chromeos) {
sources -= [ "power_monitor/power_monitor_device_source_posix.cc" ]
}
+ # NaCl.
if (is_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",
+ "process/process_metrics_nacl.cc",
"sync_socket_nacl.cc",
"threading/platform_thread_linux.cc",
]
@@ -731,26 +1026,68 @@ component("base") {
sources -= [
"cpu.cc",
+ "debug/crash_logging.cc",
+ "debug/crash_logging.h",
+ "debug/stack_trace.cc",
+ "debug/stack_trace_posix.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",
+ "memory/discardable_memory.cc",
+ "memory/discardable_memory.h",
+ "memory/discardable_memory_allocator.cc",
+ "memory/discardable_memory_allocator.h",
+ "memory/discardable_shared_memory.cc",
+ "memory/discardable_shared_memory.h",
+ "memory/shared_memory_posix.cc",
"native_library_posix.cc",
"path_service.cc",
- "rand_util_posix.cc",
+ "process/kill.cc",
+ "process/kill.h",
+ "process/memory.cc",
+ "process/memory.h",
+ "process/process_iterator.cc",
+ "process/process_iterator.h",
+ "process/process_metrics.cc",
+ "process/process_metrics_posix.cc",
+ "process/process_posix.cc",
"scoped_native_library.cc",
"sync_socket_posix.cc",
"sys_info.cc",
"sys_info_posix.cc",
+ "trace_event/process_memory_totals_dump_provider.cc",
+ "trace_event/trace_event_system_stats_monitor.cc",
]
+
+ if (is_nacl_nonsfi) {
+ set_sources_assignment_filter([])
+ sources += [ "posix/unix_domain_socket_linux.cc" ]
+ set_sources_assignment_filter(sources_assignment_filter)
+ sources -= [ "rand_util_nacl.cc" ]
+ configs += [ ":nacl_nonsfi_warnings" ]
+ } else {
+ sources -= [
+ "files/file_util.cc",
+ "files/file_util.h",
+ "files/file_util_posix.cc",
+ "json/json_file_value_serializer.cc",
+ "json/json_file_value_serializer.h",
+ "message_loop/message_pump_libevent.cc",
+ "message_loop/message_pump_libevent.h",
+ "process/kill_posix.cc",
+ "process/launch.cc",
+ "process/launch.h",
+ "process/launch_posix.cc",
+ "rand_util_posix.cc",
+ ]
+ }
} else {
# Remove NaCl stuff.
sources -= [
+ "memory/shared_memory_nacl.cc",
"os_compat_nacl.cc",
"os_compat_nacl.h",
"rand_util_nacl.cc",
@@ -776,6 +1113,8 @@ component("base") {
# Required for base/stack_trace_win.cc to symbolize correctly.
data += [ "$root_build_dir/dbghelp.dll" ]
+ deps += [ "//base/trace_event/etw_manifest:chrome_events_win" ]
+
if (is_component_build) {
# Copy the VS runtime DLLs into the isolate so that they don't have to be
# preinstalled on the target machine. The debug runtimes have a "d" at
@@ -807,15 +1146,23 @@ component("base") {
"setupapi.lib",
]
all_dependent_configs = [ ":base_win_linker_flags" ]
- } else if (!is_nacl) {
+ } else if (!is_nacl || is_nacl_nonsfi) {
# Non-Windows.
- deps += [ "//third_party/libevent" ]
+ deps += [ "//base/third_party/libevent" ]
}
- # Mac.
+ # Desktop Mac.
+ if (is_mac) {
+ sources += [
+ "trace_event/malloc_dump_provider.cc",
+ "trace_event/malloc_dump_provider.h",
+ ]
+ }
+
+ # Mac or iOS.
if (is_mac || is_ios) {
- # Common Desktop / iOS excludes
sources -= [
+ "memory/shared_memory_posix.cc",
"native_library_posix.cc",
"strings/sys_string_conversions_posix.cc",
"threading/platform_thread_internal_posix.cc",
@@ -826,7 +1173,7 @@ component("base") {
#data += [ "$root_out_dir/libclang_rt.asan_osx_dynamic.dylib" ]
}
} else {
- # Non-Mac.
+ # Non-Mac/ios.
sources -= [
"files/file_path_watcher_fsevents.cc",
"files/file_path_watcher_fsevents.h",
@@ -837,6 +1184,12 @@ component("base") {
# Linux.
if (is_linux) {
+ sources += [
+ "trace_event/malloc_dump_provider.cc",
+ "trace_event/malloc_dump_provider.h",
+ "trace_event/process_memory_maps_dump_provider.cc",
+ ]
+
if (is_asan || is_lsan || is_msan || is_tsan) {
# For llvm-sanitizer.
data += [ "//third_party/llvm-build/Release+Asserts/lib/libstdc++.so.6" ]
@@ -848,12 +1201,15 @@ component("base") {
linux_configs += [ "//build/config/linux:glib" ]
}
+ defines += [ "USE_SYMBOLIZE" ]
+
configs += linux_configs
all_dependent_configs = linux_configs
# 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",
]
@@ -878,8 +1234,33 @@ component("base") {
if (is_ios) {
set_sources_assignment_filter([])
+ sources -= [
+ "files/file_path_watcher.cc",
+ "files/file_path_watcher.h",
+ "files/file_path_watcher_fsevents.cc",
+ "files/file_path_watcher_fsevents.h",
+ "files/file_path_watcher_kqueue.cc",
+ "files/file_path_watcher_kqueue.h",
+ "memory/discardable_shared_memory.cc",
+ "memory/discardable_shared_memory.h",
+ "message_loop/message_pump_libevent.cc",
+ "message_loop/message_pump_libevent.h",
+ "process/kill.cc",
+ "process/kill.h",
+ "process/kill_posix.cc",
+ "process/launch.cc",
+ "process/launch.h",
+ "process/launch_posix.cc",
+ "process/memory.cc",
+ "process/memory.h",
+ "process/process_iterator.cc",
+ "process/process_iterator.h",
+ "process/process_metrics_posix.cc",
+ "process/process_posix.cc",
+ "sync_socket.h",
+ "sync_socket_posix.cc",
+ ]
sources += [
- "atomicops_internals_mac.h",
"base_paths_mac.h",
"base_paths_mac.mm",
"file_version_info_mac.h",
@@ -908,6 +1289,7 @@ component("base") {
"mac/scoped_objc_class_swizzler.mm",
"message_loop/message_pump_mac.h",
"message_loop/message_pump_mac.mm",
+ "process/memory_stubs.cc",
"strings/sys_string_conversions_mac.mm",
"threading/platform_thread_mac.mm",
"time/time_mac.cc",
@@ -942,10 +1324,16 @@ component("base") {
allow_circular_includes_from = public_deps
}
+buildflag_header("debugging_flags") {
+ header = "debugging_flags.h"
+ header_dir = "base/debug"
+ flags = [ "ENABLE_PROFILING=$enable_profiling" ]
+}
+
# This is the subset of files from base that should not be used with a dynamic
# library. Note that this library cannot depend on base because base depends on
# base_static.
-source_set("base_static") {
+static_library("base_static") {
sources = [
"base_switches.cc",
"base_switches.h",
@@ -963,6 +1351,8 @@ component("i18n") {
output_name = "base_i18n"
sources = [
"i18n/base_i18n_export.h",
+ "i18n/base_i18n_switches.cc",
+ "i18n/base_i18n_switches.h",
"i18n/bidi_line_iterator.cc",
"i18n/bidi_line_iterator.h",
"i18n/break_iterator.cc",
@@ -1019,7 +1409,7 @@ component("i18n") {
configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
}
-if (is_ios || is_win || (is_linux && !is_chromeos)) {
+if (is_ios || is_android || is_win || (is_linux && !is_chromeos)) {
# TODO(GYP): Figure out which of these work and are needed on other platforms.
test("base_perftests") {
sources = [
@@ -1032,8 +1422,8 @@ if (is_ios || is_win || (is_linux && !is_chromeos)) {
":base",
"//base/test:test_support",
"//base/test:test_support_perf",
- "//testing/perf",
"//testing/gtest",
+ "//testing/perf",
]
if (is_android) {
@@ -1190,6 +1580,18 @@ if (is_win) {
"//build/config/sanitizers:deps",
]
}
+
+ if (target_cpu == "x64") {
+ # Must be a shared library so that it can be unloaded during testing.
+ shared_library("base_profiler_test_support_library") {
+ sources = [
+ "profiler/test_support_library.cc",
+ ]
+ deps = [
+ "//build/config/sanitizers:deps",
+ ]
+ }
+ }
}
# TODO(GYP): Delete this after we've converted everything to GN.
@@ -1203,6 +1605,7 @@ group("base_unittests_run") {
test("base_unittests") {
sources = [
+ "allocator/tcmalloc_unittest.cc",
"android/application_status_listener_unittest.cc",
"android/content_uri_utils_unittest.cc",
"android/jni_android_unittest.cc",
@@ -1216,16 +1619,14 @@ test("base_unittests") {
"atomicops_unittest.cc",
"barrier_closure_unittest.cc",
"base64_unittest.cc",
+ "base64url_unittest.cc",
"big_endian_unittest.cc",
"bind_unittest.cc",
- "bind_unittest.nc",
"bits_unittest.cc",
"build_time_unittest.cc",
"callback_helpers_unittest.cc",
"callback_list_unittest.cc",
- "callback_list_unittest.nc",
"callback_unittest.cc",
- "callback_unittest.nc",
"cancelable_callback_unittest.cc",
"command_line_unittest.cc",
"containers/adapters_unittest.cc",
@@ -1233,7 +1634,6 @@ test("base_unittests") {
"containers/linked_list_unittest.cc",
"containers/mru_cache_unittest.cc",
"containers/scoped_ptr_hash_map_unittest.cc",
- "containers/scoped_ptr_map_unittest.cc",
"containers/small_map_unittest.cc",
"containers/stack_container_unittest.cc",
"cpu_unittest.cc",
@@ -1247,6 +1647,7 @@ test("base_unittests") {
"environment_unittest.cc",
"file_version_info_unittest.cc",
"files/dir_reader_posix_unittest.cc",
+ "files/file_locking_unittest.cc",
"files/file_path_unittest.cc",
"files/file_path_watcher_unittest.cc",
"files/file_proxy_unittest.cc",
@@ -1298,16 +1699,15 @@ test("base_unittests") {
"memory/linked_ptr_unittest.cc",
"memory/memory_pressure_monitor_chromeos_unittest.cc",
"memory/memory_pressure_monitor_win_unittest.cc",
+ "memory/ptr_util_unittest.cc",
"memory/ref_counted_memory_unittest.cc",
"memory/ref_counted_unittest.cc",
"memory/scoped_ptr_unittest.cc",
- "memory/scoped_ptr_unittest.nc",
"memory/scoped_vector_unittest.cc",
"memory/shared_memory_mac_unittest.cc",
"memory/shared_memory_unittest.cc",
"memory/singleton_unittest.cc",
"memory/weak_ptr_unittest.cc",
- "memory/weak_ptr_unittest.nc",
"message_loop/message_loop_task_runner_unittest.cc",
"message_loop/message_loop_unittest.cc",
"message_loop/message_pump_glib_unittest.cc",
@@ -1319,11 +1719,12 @@ test("base_unittests") {
"metrics/histogram_macros_unittest.cc",
"metrics/histogram_snapshot_manager_unittest.cc",
"metrics/histogram_unittest.cc",
+ "metrics/metrics_hashes_unittest.cc",
"metrics/sample_map_unittest.cc",
"metrics/sample_vector_unittest.cc",
"metrics/sparse_histogram_unittest.cc",
"metrics/statistics_recorder_unittest.cc",
- "move_unittest.cc",
+ "native_library_unittest.cc",
"numerics/safe_numerics_unittest.cc",
"observer_list_unittest.cc",
"os_compat_android_unittest.cc",
@@ -1395,6 +1796,7 @@ test("base_unittests") {
"test/user_action_tester_unittest.cc",
"threading/non_thread_safe_unittest.cc",
"threading/platform_thread_unittest.cc",
+ "threading/sequenced_task_runner_handle_unittest.cc",
"threading/sequenced_worker_pool_unittest.cc",
"threading/simple_thread_unittest.cc",
"threading/thread_checker_unittest.cc",
@@ -1413,6 +1815,23 @@ test("base_unittests") {
"timer/mock_timer_unittest.cc",
"timer/timer_unittest.cc",
"tools_sanity_unittest.cc",
+ "trace_event/heap_profiler_allocation_context_tracker_unittest.cc",
+ "trace_event/heap_profiler_allocation_register_unittest.cc",
+ "trace_event/heap_profiler_heap_dump_writer_unittest.cc",
+ "trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc",
+ "trace_event/heap_profiler_type_name_deduplicator_unittest.cc",
+ "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_dump_unittest.cc",
+ "trace_event/process_memory_totals_dump_provider_unittest.cc",
+ "trace_event/trace_config_memory_test_util.h",
+ "trace_event/trace_config_unittest.cc",
+ "trace_event/trace_event_argument_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/winheap_dump_provider_win_unittest.cc",
"tracked_objects_unittest.cc",
"tuple_unittest.cc",
"values_unittest.cc",
@@ -1450,7 +1869,6 @@ 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",
@@ -1467,9 +1885,10 @@ test("base_unittests") {
}
if (is_android) {
- apk_deps = [
+ deps += [
":base_java",
":base_java_unittest_support",
+ "//base/android/jni_generator:jni_generator_tests",
]
# TODO(brettw) I think this should not be here, we should not be using
@@ -1479,6 +1898,7 @@ test("base_unittests") {
if (is_ios) {
sources -= [
+ "files/file_locking_unittest.cc",
"files/file_path_watcher_unittest.cc",
"memory/discardable_shared_memory_unittest.cc",
"memory/shared_memory_unittest.cc",
@@ -1506,11 +1926,21 @@ test("base_unittests") {
if (is_linux) {
sources -= [ "file_version_info_unittest.cc" ]
sources += [ "nix/xdg_util_unittest.cc" ]
+
deps += [ "//base/test:malloc_wrapper" ]
if (use_glib) {
configs += [ "//build/config/linux:glib" ]
}
+
+ if (!is_component_build) {
+ # Set rpath to find libmalloc_wrapper.so even in a non-component build.
+ configs += [ "//build/config/gcc:rpath_for_built_shared_libraries" ]
+ }
+ }
+
+ if (is_linux || is_android) {
+ sources += [ "trace_event/process_memory_maps_dump_provider_unittest.cc" ]
}
if (!is_linux || use_ozone) {
@@ -1519,16 +1949,24 @@ test("base_unittests") {
if (is_posix && !is_ios) {
sources += [ "message_loop/message_pump_libevent_unittest.cc" ]
- deps += [ "//third_party/libevent" ]
+ deps += [ "//base/third_party/libevent" ]
}
if (is_android) {
deps += [ "//testing/android/native_test:native_test_native_code" ]
set_sources_assignment_filter([])
- sources += [ "debug/proc_maps_linux_unittest.cc" ]
+ sources += [
+ "debug/proc_maps_linux_unittest.cc",
+ "trace_event/trace_event_android_unittest.cc",
+ ]
set_sources_assignment_filter(sources_assignment_filter)
}
+ if (is_win && target_cpu == "x64") {
+ sources += [ "profiler/win32_stack_frame_unwinder_unittest.cc" ]
+ deps += [ ":base_profiler_test_support_library" ]
+ }
+
# TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
@@ -1542,6 +1980,24 @@ test("base_unittests") {
}
}
+if (enable_nocompile_tests) {
+ nocompile_test("base_nocompile_tests") {
+ sources = [
+ "bind_unittest.nc",
+ "callback_list_unittest.nc",
+ "callback_unittest.nc",
+ "memory/scoped_ptr_unittest.nc",
+ "memory/weak_ptr_unittest.nc",
+ ]
+
+ deps = [
+ ":base",
+ "//base/test:run_all_unittests",
+ "//testing/gtest",
+ ]
+ }
+}
+
if (is_android) {
# GYP: //base.gyp:base_jni_headers
generate_jni("base_jni_headers") {
@@ -1552,6 +2008,7 @@ if (is_android) {
"android/java/src/org/chromium/base/BuildInfo.java",
"android/java/src/org/chromium/base/CommandLine.java",
"android/java/src/org/chromium/base/ContentUriUtils.java",
+ "android/java/src/org/chromium/base/ContextUtils.java",
"android/java/src/org/chromium/base/CpuFeatures.java",
"android/java/src/org/chromium/base/EventLog.java",
"android/java/src/org/chromium/base/FieldTrialList.java",
@@ -1589,6 +2046,7 @@ if (is_android) {
android_library("base_java") {
srcjar_deps = [
":base_android_java_enums_srcjar",
+ ":base_multidex_gen",
":base_native_libraries_gen",
]
@@ -1599,9 +2057,10 @@ if (is_android) {
DEPRECATED_java_in_dir = "android/java/src"
- # A new version of NativeLibraries.java (with the actual correct values)
- # will be created when creating an apk.
+ # New versions of ChromiumMultiDex.java and NativeLibraries.java
+ # (with the actual correct values) will be created when creating an apk.
jar_excluded_patterns = [
+ "*/ChromiumMultiDex.class",
"*/NativeLibraries.class",
"*/NativeLibraries##*.class",
]
@@ -1636,6 +2095,7 @@ if (is_android) {
"//third_party/robolectric:android-all-4.3_r2-robolectric-0",
"//third_party/robolectric:robolectric_java",
]
+ srcjar_deps = [ ":base_multidex_gen" ]
}
# GYP: //base.gyp:base_junit_tests
@@ -1643,6 +2103,7 @@ if (is_android) {
java_files = [
"android/junit/src/org/chromium/base/BaseChromiumApplicationTest.java",
"android/junit/src/org/chromium/base/LogTest.java",
+ "test/android/junit/src/org/chromium/base/test/util/DisableIfTest.java",
]
deps = [
":base_java",
@@ -1662,12 +2123,14 @@ if (is_android) {
"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",
+ }
+
+ # GYP: //base/base.gyp:base_multidex_gen
+ java_cpp_template("base_multidex_gen") {
+ sources = [
+ "android/java/templates/ChromiumMultiDex.template",
]
+ package_name = "org/chromium/base/multidex"
}
# GYP: //base/base.gyp:base_native_libraries_gen
diff --git a/chromium/base/DEPS b/chromium/base/DEPS
index 6d91c8d947f..c0e95a00f6a 100644
--- a/chromium/base/DEPS
+++ b/chromium/base/DEPS
@@ -2,10 +2,7 @@ include_rules = [
"+jni",
"+third_party/ashmem",
"+third_party/apple_apsl",
- "+third_party/libevent",
- "+third_party/dmg_fp",
"+third_party/lss",
- "+third_party/mach_override",
"+third_party/modp_b64",
"+third_party/tcmalloc",
diff --git a/chromium/base/OWNERS b/chromium/base/OWNERS
index 76ffc068ba0..4d4a2391a4c 100644
--- a/chromium/base/OWNERS
+++ b/chromium/base/OWNERS
@@ -24,6 +24,7 @@ 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*=torne@chromium.org
per-file *android*=yfriedman@chromium.org
# For FeatureList API:
diff --git a/chromium/base/allocator/BUILD.gn b/chromium/base/allocator/BUILD.gn
index 32e5e6cdc65..9d09a357af6 100644
--- a/chromium/base/allocator/BUILD.gn
+++ b/chromium/base/allocator/BUILD.gn
@@ -3,6 +3,11 @@
# found in the LICENSE file.
import("//build/config/allocator.gni")
+import("//build/config/compiler/compiler.gni")
+
+if (is_win) {
+ import("//build/config/win/visual_studio_version.gni")
+}
declare_args() {
# Provide a way to force disable debugallocation in Debug builds,
@@ -22,7 +27,7 @@ group("allocator") {
}
# This condition expresses the win_use_allocator_shim in the GYP build.
- if (is_win && !is_component_build) {
+ if (is_win && !is_component_build && visual_studio_version != "2015") {
public_deps += [ ":allocator_shim" ]
}
}
@@ -34,7 +39,7 @@ group("allocator") {
# assumes that the library using it will eventually be linked with
# //base/allocator in the default way. Clean this up and delete this.
config("allocator_shim_define") {
- if (is_win && !is_component_build) {
+ if (is_win && !is_component_build && visual_studio_version != "2015") {
defines = [ "ALLOCATOR_SHIM" ]
}
}
@@ -47,12 +52,27 @@ config("tcmalloc_flags") {
"TCMALLOC_FOR_DEBUGALLOCATION",
]
}
+ if (is_clang) {
+ cflags = [
+ # tcmalloc initializes some fields in the wrong order.
+ "-Wno-reorder",
+
+ # tcmalloc contains some unused local template specializations.
+ "-Wno-unused-function",
+
+ # tcmalloc uses COMPILE_ASSERT without static_assert but with
+ # typedefs.
+ "-Wno-unused-local-typedefs",
+
+ # for magic2_ in debugallocation.cc (only built in Debug builds)
+ # typedefs.
+ "-Wno-unused-private-field",
+ ]
+ }
}
# This config and libc modification are only used on Windows.
if (is_win) {
- import("//build/config/win/visual_studio_version.gni")
-
config("nocmt") {
ldflags = [
"/NODEFAULTLIB:libcmt",
@@ -61,7 +81,7 @@ if (is_win) {
libs = [ rebase_path("$target_gen_dir/allocator/libcmt.lib") ]
}
- if (!is_component_build) {
+ if (!is_component_build && visual_studio_version != "2015") {
action("prep_libc") {
script = "prep_libc.py"
outputs = [
@@ -71,6 +91,12 @@ if (is_win) {
visual_studio_path + "/vc/lib",
rebase_path("$target_gen_dir/allocator"),
current_cpu,
+
+ # The environment file in the build directory. This is required because
+ # the Windows toolchain setup saves the VC paths and such so that
+ # running "mc.exe" will work with the configured toolchain. This file
+ # is in the root build dir.
+ "environment.$current_cpu",
]
}
@@ -84,6 +110,7 @@ if (is_win) {
public_configs = [ ":nocmt" ]
deps = [
":prep_libc",
+ "//base",
]
}
}
@@ -119,7 +146,6 @@ if (use_allocator == "tcmalloc") {
"$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",
@@ -140,8 +166,6 @@ if (use_allocator == "tcmalloc") {
"$tcmalloc_dir/src/base/synchronization_profiling.h",
"$tcmalloc_dir/src/base/sysinfo.cc",
"$tcmalloc_dir/src/base/sysinfo.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",
@@ -168,11 +192,6 @@ if (use_allocator == "tcmalloc") {
"$tcmalloc_dir/src/memory_region_map.h",
"$tcmalloc_dir/src/page_heap.cc",
"$tcmalloc_dir/src/page_heap.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",
@@ -219,21 +238,8 @@ if (use_allocator == "tcmalloc") {
deps = []
- if (is_win) {
- sources -= [
- "$tcmalloc_dir/src/base/elf_mem_image.cc",
- "$tcmalloc_dir/src/base/elf_mem_image.h",
- "$tcmalloc_dir/src/base/linuxthreads.cc",
- "$tcmalloc_dir/src/base/linuxthreads.h",
- "$tcmalloc_dir/src/base/vdso_support.cc",
- "$tcmalloc_dir/src/base/vdso_support.h",
- "$tcmalloc_dir/src/maybe_threads.cc",
- "$tcmalloc_dir/src/maybe_threads.h",
- "$tcmalloc_dir/src/symbolize.h",
- "$tcmalloc_dir/src/system-alloc.cc",
- "$tcmalloc_dir/src/system-alloc.h",
-
- # cpuprofiler
+ if (enable_profiling) {
+ sources += [
"$tcmalloc_dir/src/base/thread_lister.c",
"$tcmalloc_dir/src/base/thread_lister.h",
"$tcmalloc_dir/src/profile-handler.cc",
@@ -242,17 +248,7 @@ if (use_allocator == "tcmalloc") {
"$tcmalloc_dir/src/profiledata.h",
"$tcmalloc_dir/src/profiler.cc",
]
- defines += [ "PERFTOOLS_DLL_DECL=" ]
-
- configs -= [
- # Tcmalloc defines this itself, and we don't want duplicate definition
- # warnings.
- "//build/config/win:nominmax",
- ]
-
- public_configs = [ ":nocmt" ]
-
- deps += [ ":prep_libc" ]
+ defines += [ "ENABLE_PROFILING=1" ]
}
if (is_linux || is_android) {
@@ -292,21 +288,5 @@ if (use_allocator == "tcmalloc") {
}
deps += [ "//base/third_party/dynamic_annotations" ]
-
- if (is_win) {
- ldflags = [ "/ignore:4006:4221" ]
- }
- }
-} # !is_android
-
-source_set("allocator_extension_thunks") {
- visibility = [ "//base/*" ]
- sources = [
- "allocator_extension_thunks.cc",
- "allocator_extension_thunks.h",
- ]
- if (is_android && !is_debug) {
- configs -= [ "//build/config/compiler:default_optimization" ]
- configs += [ "//build/config/compiler:optimize_max" ]
}
-}
+} # use_allocator == "tcmalloc"
diff --git a/chromium/base/allocator/allocator.gyp b/chromium/base/allocator/allocator.gyp
index ae93e9e03ca..45a95bbdc26 100644
--- a/chromium/base/allocator/allocator.gyp
+++ b/chromium/base/allocator/allocator.gyp
@@ -16,6 +16,10 @@
'variables': {
'tcmalloc_dir': '../../third_party/tcmalloc/chromium',
'use_vtable_verify%': 0,
+ # Provide a way to force disable debugallocation in Debug builds
+ # e.g. for profiling (it's more rare to profile Debug builds,
+ # but people sometimes need to do that).
+ 'disable_debugallocation%': 0,
},
'targets': [
# Only executables and not libraries should depend on the
@@ -23,70 +27,64 @@
# knows what allocator makes sense.
{
'target_name': 'allocator',
+ # TODO(primiano): This should be type: none for the noop cases (an empty
+ # static lib can confuse some gyp generators). Fix it once the refactoring
+ # (crbug.com/564618) bring this file to a saner state (fewer conditions).
'type': 'static_library',
- 'direct_dependent_settings': {
- 'configurations': {
- 'Common_Base': {
- 'msvs_settings': {
- 'VCLinkerTool': {
- 'IgnoreDefaultLibraryNames': ['libcmtd.lib', 'libcmt.lib'],
- 'AdditionalDependencies': [
- '<(SHARED_INTERMEDIATE_DIR)/allocator/libcmt.lib'
- ],
- },
+ 'conditions': [
+ ['OS=="win" and win_use_allocator_shim==1', {
+ 'msvs_settings': {
+ # TODO(sgk): merge this with build/common.gypi settings
+ 'VCLibrarianTool': {
+ 'AdditionalOptions': ['/ignore:4006,4221'],
+ },
+ 'VCLinkerTool': {
+ 'AdditionalOptions': ['/ignore:4006'],
},
},
- },
- 'conditions': [
- ['OS=="win"', {
- 'defines': [
- 'PERFTOOLS_DLL_DECL=',
- ],
- }],
- ],
- },
- 'dependencies': [
- '../third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
- ],
- 'msvs_settings': {
- # TODO(sgk): merge this with build/common.gypi settings
- 'VCLibrarianTool': {
- 'AdditionalOptions': ['/ignore:4006,4221'],
- },
- 'VCLinkerTool': {
- 'AdditionalOptions': ['/ignore:4006'],
- },
- },
- 'configurations': {
- 'Debug_Base': {
- 'msvs_settings': {
- 'VCCLCompilerTool': {
- 'RuntimeLibrary': '0',
+ 'dependencies': [
+ 'libcmt',
+ ],
+ 'include_dirs': [
+ '../..',
+ ],
+ 'sources': [
+ 'allocator_shim_win.cc',
+ ],
+ 'configurations': {
+ 'Debug_Base': {
+ 'msvs_settings': {
+ 'VCCLCompilerTool': {
+ 'RuntimeLibrary': '0',
+ },
+ },
},
},
- 'variables': {
- # Provide a way to force disable debugallocation in Debug builds,
- # e.g. for profiling (it's more rare to profile Debug builds,
- # but people sometimes need to do that).
- 'disable_debugallocation%': 0,
+ 'direct_dependent_settings': {
+ 'configurations': {
+ 'Common_Base': {
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'IgnoreDefaultLibraryNames': ['libcmtd.lib', 'libcmt.lib'],
+ 'AdditionalDependencies': [
+ '<(SHARED_INTERMEDIATE_DIR)/allocator/libcmt.lib'
+ ],
+ },
+ },
+ },
+ },
},
- 'conditions': [
- ['disable_debugallocation==0', {
- 'defines': [
- # Use debugallocation for Debug builds to catch problems early
- # and cleanly, http://crbug.com/30715 .
- 'TCMALLOC_FOR_DEBUGALLOCATION',
- ],
- }],
- ],
- },
- },
- 'conditions': [
+ }], # OS=="win"
['use_allocator=="tcmalloc"', {
# Disable the heap checker in tcmalloc.
'defines': [
'NO_HEAP_CHECK',
],
+ 'dependencies': [
+ '../third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+ ],
+ # The order of this include_dirs matters, as tc-malloc has its own
+ # base/ mini-fork. Do not factor these out of this conditions section.
'include_dirs': [
'.',
'<(tcmalloc_dir)/src/base',
@@ -114,7 +112,6 @@
'<(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
@@ -238,7 +235,6 @@
'<(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',
@@ -287,59 +283,80 @@
# Included by debugallocation_shim.cc.
'<(tcmalloc_dir)/src/debugallocation.cc',
'<(tcmalloc_dir)/src/tcmalloc.cc',
- ]
- },{
- 'include_dirs': [
- '.',
- '../..',
- ],
- }],
- ['OS=="win" and component!="shared_library"', {
- 'dependencies': [
- 'libcmt',
- ],
- 'sources': [
- 'allocator_shim_win.cc',
- ],
- }],
- ['profiling!=1', {
- 'sources!': [
- # cpuprofiler
- '<(tcmalloc_dir)/src/base/thread_lister.c',
- '<(tcmalloc_dir)/src/base/thread_lister.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',
- ],
- # We enable all warnings by default, but upstream disables a few.
- # Keep "-Wno-*" flags in sync with upstream by comparing against:
- # http://code.google.com/p/google-perftools/source/browse/trunk/Makefile.am
- 'cflags': [
- '-Wno-sign-compare',
- '-Wno-unused-result',
],
- 'cflags!': [
- '-fvisibility=hidden',
+ 'variables': {
+ 'clang_warning_flags': [
+ # tcmalloc initializes some fields in the wrong order.
+ '-Wno-reorder',
+ # tcmalloc contains some unused local template specializations.
+ '-Wno-unused-function',
+ # tcmalloc uses COMPILE_ASSERT without static_assert but with
+ # typedefs.
+ '-Wno-unused-local-typedefs',
+ # for magic2_ in debugallocation.cc (only built in Debug builds)
+ # typedefs.
+ '-Wno-unused-private-field',
+ ],
+ },
+ 'conditions': [
+ ['OS=="linux" or OS=="freebsd" or OS=="solaris" or OS=="android"', {
+ 'sources!': [
+ '<(tcmalloc_dir)/src/system-alloc.h',
+ ],
+ # We enable all warnings by default, but upstream disables a few.
+ # Keep "-Wno-*" flags in sync with upstream by comparing against:
+ # http://code.google.com/p/google-perftools/source/browse/trunk/Makefile.am
+ 'cflags': [
+ '-Wno-sign-compare',
+ '-Wno-unused-result',
+ ],
+ 'cflags!': [
+ '-fvisibility=hidden',
+ ],
+ 'link_settings': {
+ 'ldflags': [
+ # 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',
+ '-Wl,-u_ZN15HeapLeakChecker12IgnoreObjectEPKv,-u_ZN15HeapLeakChecker14UnIgnoreObjectEPKv',
+ ],
+ },
+ }],
+ ['profiling!=1', {
+ 'sources!': [
+ # cpuprofiler
+ '<(tcmalloc_dir)/src/base/thread_lister.c',
+ '<(tcmalloc_dir)/src/base/thread_lister.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',
+ ],
+ }],
],
- 'link_settings': {
- 'ldflags': [
- # 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',
- '-Wl,-u_ZN15HeapLeakChecker12IgnoreObjectEPKv,-u_ZN15HeapLeakChecker14UnIgnoreObjectEPKv',
- ]},
- }],
- [ 'use_vtable_verify==1', {
+ 'configurations': {
+ 'Debug_Base': {
+ 'conditions': [
+ ['disable_debugallocation==0', {
+ 'defines': [
+ # Use debugallocation for Debug builds to catch problems
+ # early and cleanly, http://crbug.com/30715 .
+ 'TCMALLOC_FOR_DEBUGALLOCATION',
+ ],
+ }],
+ ],
+ },
+ },
+ }], # use_allocator=="tcmalloc
+ # For CrOS builds with vtable verification. According to the author of
+ # crrev.com/10854031 this is used in conjuction with some other CrOS
+ # build flag, to enable verification of any allocator that uses virtual
+ # function calls.
+ ['use_vtable_verify==1', {
'cflags': [
'-fvtable-verify=preinit',
],
@@ -351,24 +368,9 @@
}],
],
}],
- ],
- },
- {
- # This library is linked in to src/base.gypi:base and allocator_unittests
- # It can't depend on either and nothing else should depend on it - all
- # other code should use the interfaced provided by base.
- 'target_name': 'allocator_extension_thunks',
- 'type': 'static_library',
- 'sources': [
- 'allocator_extension_thunks.cc',
- 'allocator_extension_thunks.h',
- ],
- 'toolsets': ['host', 'target'],
- 'include_dirs': [
- '../../'
- ],
- },
- ],
+ ], # conditions of 'allocator' target.
+ }, # 'allocator' target.
+ ], # targets.
'conditions': [
['OS=="win" and component!="shared_library"', {
'targets': [
@@ -394,64 +396,6 @@
},
],
},
- {
- 'target_name': 'allocator_unittests',
- 'type': 'executable',
- 'dependencies': [
- 'allocator',
- 'allocator_extension_thunks',
- '../../testing/gtest.gyp:gtest',
- ],
- 'include_dirs': [
- '.',
- '../..',
- ],
- 'sources': [
- '../profiler/alternate_timer.cc',
- '../profiler/alternate_timer.h',
- 'allocator_unittest.cc',
- ],
- },
- ],
- }],
- ['OS=="win" and target_arch=="ia32"', {
- 'targets': [
- {
- 'target_name': 'allocator_extension_thunks_win64',
- 'type': 'static_library',
- 'sources': [
- 'allocator_extension_thunks.cc',
- 'allocator_extension_thunks.h',
- ],
- 'toolsets': ['host', 'target'],
- 'include_dirs': [
- '../../'
- ],
- 'configurations': {
- 'Common_Base': {
- 'msvs_target_platform': 'x64',
- },
- },
- },
- ],
- }],
- ['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_check.cc b/chromium/base/allocator/allocator_check.cc
new file mode 100644
index 00000000000..a708f0faf3c
--- /dev/null
+++ b/chromium/base/allocator/allocator_check.cc
@@ -0,0 +1,38 @@
+// Copyright 2016 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_check.h"
+
+#include "build/build_config.h"
+
+#if defined(OS_LINUX)
+#include <malloc.h>
+#endif
+
+namespace base {
+namespace allocator {
+
+// Defined in allocator_shim_win.cc .
+// TODO(primiano): replace with an include once base can depend on allocator.
+#if defined(OS_WIN) && defined(ALLOCATOR_SHIM)
+extern bool g_is_win_shim_layer_initialized;
+#endif
+
+bool IsAllocatorInitialized() {
+#if defined(OS_WIN) && defined(ALLOCATOR_SHIM)
+ // Set by allocator_shim_win.cc when the shimmed _heap_init() is called.
+ return g_is_win_shim_layer_initialized;
+#elif defined(OS_LINUX) && defined(USE_TCMALLOC)
+// From third_party/tcmalloc/chromium/src/gperftools/tcmalloc.h.
+// TODO(primiano): replace with an include once base can depend on allocator.
+#define TC_MALLOPT_IS_OVERRIDDEN_BY_TCMALLOC 0xbeef42
+ return (mallopt(TC_MALLOPT_IS_OVERRIDDEN_BY_TCMALLOC, 0) ==
+ TC_MALLOPT_IS_OVERRIDDEN_BY_TCMALLOC);
+#else
+ return true;
+#endif
+}
+
+} // namespace allocator
+} // namespace base
diff --git a/chromium/base/allocator/allocator_check.h b/chromium/base/allocator/allocator_check.h
new file mode 100644
index 00000000000..cf519fd89a4
--- /dev/null
+++ b/chromium/base/allocator/allocator_check.h
@@ -0,0 +1,18 @@
+// Copyright 2016 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_ALLOCATOR_CHECK_H_
+#define BASE_ALLOCATOR_ALLOCATOR_ALLOCATOR_CHECK_H_
+
+#include "base/base_export.h"
+
+namespace base {
+namespace allocator {
+
+BASE_EXPORT bool IsAllocatorInitialized();
+
+} // namespace allocator
+} // namespace base
+
+#endif // BASE_ALLOCATOR_ALLOCATOR_ALLOCATOR_CHECK_H_
diff --git a/chromium/base/allocator/allocator_extension.cc b/chromium/base/allocator/allocator_extension.cc
index 83e460ac82b..4f0b3a90032 100644
--- a/chromium/base/allocator/allocator_extension.cc
+++ b/chromium/base/allocator/allocator_extension.cc
@@ -9,47 +9,31 @@
namespace base {
namespace allocator {
-bool GetAllocatorWasteSize(size_t* size) {
- thunks::GetAllocatorWasteSizeFunction get_allocator_waste_size_function =
- thunks::GetGetAllocatorWasteSizeFunction();
- return get_allocator_waste_size_function != NULL &&
- get_allocator_waste_size_function(size);
-}
-
-void GetStats(char* buffer, int buffer_length) {
- DCHECK_GT(buffer_length, 0);
- thunks::GetStatsFunction get_stats_function = thunks::GetGetStatsFunction();
- if (get_stats_function)
- get_stats_function(buffer, buffer_length);
- else
- buffer[0] = '\0';
+namespace {
+ReleaseFreeMemoryFunction g_release_free_memory_function = nullptr;
+GetNumericPropertyFunction g_get_numeric_property_function = nullptr;
}
void ReleaseFreeMemory() {
- thunks::ReleaseFreeMemoryFunction release_free_memory_function =
- thunks::GetReleaseFreeMemoryFunction();
- if (release_free_memory_function)
- release_free_memory_function();
+ if (g_release_free_memory_function)
+ g_release_free_memory_function();
}
-void SetGetAllocatorWasteSizeFunction(
- thunks::GetAllocatorWasteSizeFunction get_allocator_waste_size_function) {
- DCHECK_EQ(thunks::GetGetAllocatorWasteSizeFunction(),
- reinterpret_cast<thunks::GetAllocatorWasteSizeFunction>(NULL));
- thunks::SetGetAllocatorWasteSizeFunction(get_allocator_waste_size_function);
+bool GetNumericProperty(const char* name, size_t* value) {
+ return g_get_numeric_property_function &&
+ g_get_numeric_property_function(name, value);
}
-void SetGetStatsFunction(thunks::GetStatsFunction get_stats_function) {
- DCHECK_EQ(thunks::GetGetStatsFunction(),
- reinterpret_cast<thunks::GetStatsFunction>(NULL));
- thunks::SetGetStatsFunction(get_stats_function);
+void SetReleaseFreeMemoryFunction(
+ ReleaseFreeMemoryFunction release_free_memory_function) {
+ DCHECK(!g_release_free_memory_function);
+ g_release_free_memory_function = release_free_memory_function;
}
-void SetReleaseFreeMemoryFunction(
- thunks::ReleaseFreeMemoryFunction release_free_memory_function) {
- DCHECK_EQ(thunks::GetReleaseFreeMemoryFunction(),
- reinterpret_cast<thunks::ReleaseFreeMemoryFunction>(NULL));
- thunks::SetReleaseFreeMemoryFunction(release_free_memory_function);
+void SetGetNumericPropertyFunction(
+ GetNumericPropertyFunction get_numeric_property_function) {
+ DCHECK(!g_get_numeric_property_function);
+ g_get_numeric_property_function = get_numeric_property_function;
}
} // namespace allocator
diff --git a/chromium/base/allocator/allocator_extension.h b/chromium/base/allocator/allocator_extension.h
index e65822b359e..3be2cea00c1 100644
--- a/chromium/base/allocator/allocator_extension.h
+++ b/chromium/base/allocator/allocator_extension.h
@@ -7,34 +7,24 @@
#include <stddef.h> // for size_t
-#include "base/allocator/allocator_extension_thunks.h"
#include "base/base_export.h"
#include "build/build_config.h"
namespace base {
namespace allocator {
-// Request the allocator to report value of its waste memory size.
-// Waste size corresponds to memory that has been allocated from the OS but
-// not passed up to the application. It e.g. includes memory retained by free
-// lists, internal data, chunks padding, etc.
-//
-// |size| pointer to the returned value, must be not NULL.
-// Returns true if the value has been returned, false otherwise.
-BASE_EXPORT bool GetAllocatorWasteSize(size_t* size);
-
-// Request that the allocator print a human-readable description of the current
-// state of the allocator into a null-terminated string in the memory segment
-// buffer[0,buffer_length-1].
-//
-// |buffer| must point to a valid piece of memory
-// |buffer_length| must be > 0.
-BASE_EXPORT void GetStats(char* buffer, int buffer_length);
+typedef void (*ReleaseFreeMemoryFunction)();
+typedef bool (*GetNumericPropertyFunction)(const char* name, size_t* value);
// Request that the allocator release any free memory it knows about to the
// system.
BASE_EXPORT void ReleaseFreeMemory();
+// Get the named property's |value|. Returns true if the property is known.
+// Returns false if the property is not a valid property name for the current
+// allocator implementation.
+// |name| or |value| cannot be NULL
+BASE_EXPORT bool GetNumericProperty(const char* name, size_t* value);
// These settings allow specifying a callback used to implement the allocator
// extension functions. These are optional, but if set they must only be set
@@ -44,14 +34,12 @@ BASE_EXPORT void ReleaseFreeMemory();
// No threading promises are made. The caller is responsible for making sure
// these pointers are set before any other threads attempt to call the above
// functions.
-BASE_EXPORT void SetGetAllocatorWasteSizeFunction(
- thunks::GetAllocatorWasteSizeFunction get_allocator_waste_size_function);
-
-BASE_EXPORT void SetGetStatsFunction(
- thunks::GetStatsFunction get_stats_function);
BASE_EXPORT void SetReleaseFreeMemoryFunction(
- thunks::ReleaseFreeMemoryFunction release_free_memory_function);
+ ReleaseFreeMemoryFunction release_free_memory_function);
+
+BASE_EXPORT void SetGetNumericPropertyFunction(
+ GetNumericPropertyFunction get_numeric_property_function);
} // namespace allocator
} // namespace base
diff --git a/chromium/base/allocator/allocator_extension_thunks.cc b/chromium/base/allocator/allocator_extension_thunks.cc
deleted file mode 100644
index e4024fb332e..00000000000
--- a/chromium/base/allocator/allocator_extension_thunks.cc
+++ /dev/null
@@ -1,52 +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_extension_thunks.h"
-
-#include <cstddef> // for NULL
-
-namespace base {
-namespace allocator {
-namespace thunks {
-
-// This slightly odd translation unit exists because of the peculularity of how
-// allocator_unittests work on windows. That target has to perform
-// tcmalloc-specific initialization on windows, but it cannot depend on base
-// otherwise. This target sits in the middle - base and allocator_unittests
-// can depend on it. This file can't depend on anything else in base, including
-// logging.
-
-static GetAllocatorWasteSizeFunction g_get_allocator_waste_size_function = NULL;
-static GetStatsFunction g_get_stats_function = NULL;
-static ReleaseFreeMemoryFunction g_release_free_memory_function = NULL;
-
-void SetGetAllocatorWasteSizeFunction(
- GetAllocatorWasteSizeFunction get_allocator_waste_size_function) {
- g_get_allocator_waste_size_function = get_allocator_waste_size_function;
-}
-
-GetAllocatorWasteSizeFunction GetGetAllocatorWasteSizeFunction() {
- return g_get_allocator_waste_size_function;
-}
-
-void SetGetStatsFunction(GetStatsFunction get_stats_function) {
- g_get_stats_function = get_stats_function;
-}
-
-GetStatsFunction GetGetStatsFunction() {
- return g_get_stats_function;
-}
-
-void SetReleaseFreeMemoryFunction(
- ReleaseFreeMemoryFunction release_free_memory_function) {
- g_release_free_memory_function = release_free_memory_function;
-}
-
-ReleaseFreeMemoryFunction GetReleaseFreeMemoryFunction() {
- return g_release_free_memory_function;
-}
-
-} // namespace thunks
-} // namespace allocator
-} // namespace base
diff --git a/chromium/base/allocator/allocator_extension_thunks.h b/chromium/base/allocator/allocator_extension_thunks.h
deleted file mode 100644
index 4e5027b2921..00000000000
--- a/chromium/base/allocator/allocator_extension_thunks.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_ALLOCATOR_ALLOCATOR_EXTENSION_THUNKS_H_
-#define BASE_ALLOCATOR_ALLOCATOR_EXTENSION_THUNKS_H_
-
-#include <stddef.h> // for size_t
-
-namespace base {
-namespace allocator {
-namespace thunks {
-
-// WARNING: You probably don't want to use this file unless you are routing a
-// new allocator extension from a specific allocator implementation to base.
-// See allocator_extension.h to see the interface that base exports.
-
-typedef bool (*GetAllocatorWasteSizeFunction)(size_t* size);
-void SetGetAllocatorWasteSizeFunction(
- GetAllocatorWasteSizeFunction get_allocator_waste_size_function);
-GetAllocatorWasteSizeFunction GetGetAllocatorWasteSizeFunction();
-
-typedef void (*GetStatsFunction)(char* buffer, int buffer_length);
-void SetGetStatsFunction(GetStatsFunction get_stats_function);
-GetStatsFunction GetGetStatsFunction();
-
-typedef void (*ReleaseFreeMemoryFunction)();
-void SetReleaseFreeMemoryFunction(
- ReleaseFreeMemoryFunction release_free_memory_function);
-ReleaseFreeMemoryFunction GetReleaseFreeMemoryFunction();
-
-} // namespace thunks
-} // namespace allocator
-} // namespace base
-
-#endif // BASE_ALLOCATOR_ALLOCATOR_EXTENSION_THUNKS_H_
diff --git a/chromium/base/allocator/allocator_shim_win.cc b/chromium/base/allocator/allocator_shim_win.cc
index 2a933ee93db..b65544f5dd8 100644
--- a/chromium/base/allocator/allocator_shim_win.cc
+++ b/chromium/base/allocator/allocator_shim_win.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 <limits.h>
#include <malloc.h>
#include <new.h>
#include <windows.h>
-
-#include "base/basictypes.h"
+#include <stddef.h>
// This shim make it possible to perform additional checks on allocations
// before passing them to the Heap functions.
@@ -26,6 +26,12 @@ extern "C" {
void* _crtheap = reinterpret_cast<void*>(1);
}
+namespace base {
+namespace allocator {
+bool g_is_win_shim_layer_initialized = false;
+} // namespace allocator
+} // namespace base
+
namespace {
const size_t kWindowsPageSize = 4096;
@@ -211,6 +217,7 @@ intptr_t _get_heap_handle() {
// heapinit.c
int _heap_init() {
+ base::allocator::g_is_win_shim_layer_initialized = true;
return win_heap_init() ? 1 : 0;
}
diff --git a/chromium/base/allocator/allocator_unittest.cc b/chromium/base/allocator/allocator_unittest.cc
deleted file mode 100644
index a1d1ef0c639..00000000000
--- a/chromium/base/allocator/allocator_unittest.cc
+++ /dev/null
@@ -1,245 +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 <stdio.h>
-#include <stdlib.h>
-#include <algorithm> // for min()
-
-#include "base/macros.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-// Number of bits in a size_t.
-static const int kSizeBits = 8 * sizeof(size_t);
-// The maximum size of a 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);
-
-namespace {
-
-using std::min;
-
-// Fill a buffer of the specified size with a predetermined pattern
-static void Fill(unsigned char* buffer, int n) {
- for (int i = 0; i < n; i++) {
- buffer[i] = (i & 0xff);
- }
-}
-
-// Check that the specified buffer has the predetermined pattern
-// generated by Fill()
-static bool Valid(unsigned char* buffer, int n) {
- for (int i = 0; i < n; i++) {
- if (buffer[i] != (i & 0xff)) {
- return false;
- }
- }
- return true;
-}
-
-// Check that a buffer is completely zeroed.
-static bool IsZeroed(unsigned char* buffer, int n) {
- for (int i = 0; i < n; i++) {
- if (buffer[i] != 0) {
- return false;
- }
- }
- return true;
-}
-
-// Check alignment
-static void CheckAlignment(void* p, int align) {
- EXPECT_EQ(0, reinterpret_cast<uintptr_t>(p) & (align-1));
-}
-
-// Return the next interesting size/delta to check. Returns -1 if no more.
-static int NextSize(int size) {
- if (size < 100)
- return size+1;
-
- if (size < 100000) {
- // Find next power of two
- int power = 1;
- while (power < size)
- power <<= 1;
-
- // Yield (power-1, power, power+1)
- if (size < power-1)
- return power-1;
-
- if (size == power-1)
- return power;
-
- assert(size == power);
- return power+1;
- } else {
- return -1;
- }
-}
-
-static void TestCalloc(size_t n, size_t s, bool ok) {
- char* p = reinterpret_cast<char*>(calloc(n, s));
- if (!ok) {
- EXPECT_EQ(NULL, p) << "calloc(n, s) should not succeed";
- } else {
- EXPECT_NE(reinterpret_cast<void*>(NULL), p) <<
- "calloc(n, s) should succeed";
- for (size_t i = 0; i < n*s; i++) {
- EXPECT_EQ('\0', p[i]);
- }
- free(p);
- }
-}
-
-} // namespace
-
-//-----------------------------------------------------------------------------
-
-
-TEST(Allocators, Malloc) {
- // Try allocating data with a bunch of alignments and sizes
- for (int size = 1; size < 1048576; size *= 2) {
- unsigned char* ptr = reinterpret_cast<unsigned char*>(malloc(size));
- CheckAlignment(ptr, 2); // Should be 2 byte aligned
- Fill(ptr, size);
- EXPECT_TRUE(Valid(ptr, size));
- free(ptr);
- }
-}
-
-TEST(Allocators, Calloc) {
- TestCalloc(0, 0, true);
- TestCalloc(0, 1, true);
- TestCalloc(1, 1, true);
- TestCalloc(1<<10, 0, true);
- TestCalloc(1<<20, 0, true);
- TestCalloc(0, 1<<10, true);
- TestCalloc(0, 1<<20, true);
- TestCalloc(1<<20, 2, true);
- TestCalloc(2, 1<<20, true);
- TestCalloc(1000, 1000, true);
-
- TestCalloc(kMaxSize, 2, false);
- TestCalloc(2, kMaxSize, false);
- TestCalloc(kMaxSize, kMaxSize, false);
-
- TestCalloc(kMaxSignedSize, 3, false);
- TestCalloc(3, kMaxSignedSize, false);
- TestCalloc(kMaxSignedSize, kMaxSignedSize, false);
-}
-
-// This makes sure that reallocing a small number of bytes in either
-// direction doesn't cause us to allocate new memory.
-TEST(Allocators, Realloc1) {
- int start_sizes[] = { 100, 1000, 10000, 100000 };
- int deltas[] = { 1, -2, 4, -8, 16, -32, 64, -128 };
-
- for (int s = 0; s < sizeof(start_sizes)/sizeof(*start_sizes); ++s) {
- void* p = malloc(start_sizes[s]);
- ASSERT_TRUE(p);
- // The larger the start-size, the larger the non-reallocing delta.
- for (int d = 0; d < s*2; ++d) {
- void* new_p = realloc(p, start_sizes[s] + deltas[d]);
- ASSERT_EQ(p, new_p); // realloc should not allocate new memory
- }
- // Test again, but this time reallocing smaller first.
- for (int d = 0; d < s*2; ++d) {
- void* new_p = realloc(p, start_sizes[s] - deltas[d]);
- ASSERT_EQ(p, new_p); // realloc should not allocate new memory
- }
- free(p);
- }
-}
-
-TEST(Allocators, Realloc2) {
- for (int src_size = 0; src_size >= 0; src_size = NextSize(src_size)) {
- for (int dst_size = 0; dst_size >= 0; dst_size = NextSize(dst_size)) {
- unsigned char* src = reinterpret_cast<unsigned char*>(malloc(src_size));
- Fill(src, src_size);
- unsigned char* dst =
- reinterpret_cast<unsigned char*>(realloc(src, dst_size));
- EXPECT_TRUE(Valid(dst, min(src_size, dst_size)));
- Fill(dst, dst_size);
- EXPECT_TRUE(Valid(dst, dst_size));
- if (dst != NULL) free(dst);
- }
- }
-
- // Now make sure realloc works correctly even when we overflow the
- // packed cache, so some entries are evicted from the cache.
- // The cache has 2^12 entries, keyed by page number.
- const int kNumEntries = 1 << 14;
- int** p = reinterpret_cast<int**>(malloc(sizeof(*p) * kNumEntries));
- int sum = 0;
- for (int i = 0; i < kNumEntries; i++) {
- // no page size is likely to be bigger than 8192?
- p[i] = reinterpret_cast<int*>(malloc(8192));
- p[i][1000] = i; // use memory deep in the heart of p
- }
- for (int i = 0; i < kNumEntries; i++) {
- p[i] = reinterpret_cast<int*>(realloc(p[i], 9000));
- }
- for (int i = 0; i < kNumEntries; i++) {
- sum += p[i][1000];
- free(p[i]);
- }
- EXPECT_EQ(kNumEntries/2 * (kNumEntries - 1), sum); // assume kNE is even
- free(p);
-}
-
-// Test recalloc
-TEST(Allocators, Recalloc) {
- for (int src_size = 0; src_size >= 0; src_size = NextSize(src_size)) {
- for (int dst_size = 0; dst_size >= 0; dst_size = NextSize(dst_size)) {
- unsigned char* src =
- reinterpret_cast<unsigned char*>(_recalloc(NULL, 1, src_size));
- EXPECT_TRUE(IsZeroed(src, src_size));
- Fill(src, src_size);
- unsigned char* dst =
- reinterpret_cast<unsigned char*>(_recalloc(src, 1, dst_size));
- EXPECT_TRUE(Valid(dst, min(src_size, dst_size)));
- Fill(dst, dst_size);
- EXPECT_TRUE(Valid(dst, dst_size));
- if (dst != NULL)
- free(dst);
- }
- }
-}
-
-// Test windows specific _aligned_malloc() and _aligned_free() methods.
-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) {
- unsigned char* ptr = static_cast<unsigned char*>(
- _aligned_malloc(size, kTestAlignments[i]));
- CheckAlignment(ptr, kTestAlignments[i]);
- Fill(ptr, size);
- EXPECT_TRUE(Valid(ptr, size));
-
- // Make a second allocation of the same size and alignment to prevent
- // allocators from passing this test by accident. Per jar, tcmalloc
- // provides allocations for new (never before seen) sizes out of a thread
- // local heap of a given "size class." Each time the test requests a new
- // size, it will usually get the first element of a span, which is a
- // 4K aligned allocation.
- unsigned char* ptr2 = static_cast<unsigned char*>(
- _aligned_malloc(size, kTestAlignments[i]));
- CheckAlignment(ptr2, kTestAlignments[i]);
- Fill(ptr2, size);
- EXPECT_TRUE(Valid(ptr2, size));
-
- // Should never happen, but sanity check just in case.
- ASSERT_NE(ptr, ptr2);
- _aligned_free(ptr);
- _aligned_free(ptr2);
- }
- }
-}
-
-int main(int argc, char** argv) {
- testing::InitGoogleTest(&argc, argv);
- return RUN_ALL_TESTS();
-}
diff --git a/chromium/base/allocator/prep_libc.py b/chromium/base/allocator/prep_libc.py
index 079297b4629..a88d3bd0257 100755
--- a/chromium/base/allocator/prep_libc.py
+++ b/chromium/base/allocator/prep_libc.py
@@ -7,24 +7,34 @@
# This script takes libcmt.lib for VS2013 and removes the allocation related
# functions from it.
#
-# Usage: prep_libc.py <VCLibDir> <OutputDir> <arch>
+# Usage: prep_libc.py <VCLibDir> <OutputDir> <arch> [<environment_file>]
#
# VCLibDir is the path where VC is installed, something like:
# C:\Program Files\Microsoft Visual Studio 8\VC\lib
+#
# OutputDir is the directory where the modified libcmt file should be stored.
# arch is one of: 'ia32', 'x86' or 'x64'. ia32 and x86 are synonyms.
+#
+# If the environment_file argument is set, the environment variables in the
+# given file will be used to execute the VC tools. This file is in the same
+# format as the environment block passed to CreateProcess.
import os
import shutil
import subprocess
import sys
-def run(command):
+def run(command, env_dict):
"""Run |command|. If any lines that match an error condition then
- terminate."""
+ terminate.
+
+ The env_dict, will be used for the environment. None can be used to get the
+ default environment."""
error = 'cannot find member object'
+ # Need shell=True to search the path in env_dict for the executable.
popen = subprocess.Popen(
- command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True,
+ env=env_dict)
out, _ = popen.communicate()
for line in out.splitlines():
print line
@@ -41,6 +51,13 @@ def main():
bindir = 'SELF_64_amd64'
objdir = 'amd64'
vs_install_dir = os.path.join(vs_install_dir, 'amd64')
+
+ if len(sys.argv) == 5:
+ env_pairs = open(sys.argv[4]).read()[:-2].split('\0')
+ env_dict = dict([item.split('=', 1) for item in env_pairs])
+ else:
+ env_dict = None # Use the default environment.
+
output_lib = os.path.join(outdir, 'libcmt.lib')
shutil.copyfile(os.path.join(vs_install_dir, 'libcmt.lib'), output_lib)
shutil.copyfile(os.path.join(vs_install_dir, 'libcmt.pdb'),
@@ -57,11 +74,11 @@ def main():
for obj in cobjfiles:
cmd = ('lib /nologo /ignore:4006,4221 /remove:%s%s.obj %s' %
(cvspath, obj, output_lib))
- run(cmd)
+ run(cmd, env_dict)
for obj in cppobjfiles:
cmd = ('lib /nologo /ignore:4006,4221 /remove:%s%s.obj %s' %
(cppvspath, obj, output_lib))
- run(cmd)
+ run(cmd, env_dict)
if __name__ == "__main__":
sys.exit(main())
diff --git a/chromium/base/allocator/tcmalloc_unittest.cc b/chromium/base/allocator/tcmalloc_unittest.cc
index 0f7082eb026..eb1b0f0ca8b 100644
--- a/chromium/base/allocator/tcmalloc_unittest.cc
+++ b/chromium/base/allocator/tcmalloc_unittest.cc
@@ -1,96 +1,224 @@
// 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/logging.h"
+#include "base/process/process_metrics.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
-// TCMalloc header files.
-#include "common.h" // For TCMalloc constants like page size, etc.
-
-// TCMalloc implementation.
-#include "debugallocation_shim.cc"
+#if defined(USE_TCMALLOC)
+extern "C" {
+void* tc_malloc(size_t size);
+void tc_free(void*);
+}
namespace {
+using std::min;
+
+#ifdef NDEBUG
void* TCMallocDoMallocForTest(size_t size) {
- return do_malloc(size);
+ return tc_malloc(size);
}
void TCMallocDoFreeForTest(void* ptr) {
- do_free(ptr);
+ tc_free(ptr);
}
+#endif
-size_t ExcludeSpaceForMarkForTest(size_t size) {
- return ExcludeSpaceForMark(size);
+// Fill a buffer of the specified size with a predetermined pattern
+static void Fill(unsigned char* buffer, int n) {
+ for (int i = 0; i < n; i++) {
+ buffer[i] = (i & 0xff);
+ }
+}
+
+// Check that the specified buffer has the predetermined pattern
+// generated by Fill()
+static bool Valid(unsigned char* buffer, int n) {
+ for (int i = 0; i < n; i++) {
+ if (buffer[i] != (i & 0xff)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+// Return the next interesting size/delta to check. Returns -1 if no more.
+static int NextSize(int size) {
+ if (size < 100)
+ return size + 1;
+
+ if (size < 100000) {
+ // Find next power of two
+ int power = 1;
+ while (power < size)
+ power <<= 1;
+
+ // Yield (power-1, power, power+1)
+ if (size < power - 1)
+ return power - 1;
+
+ if (size == power - 1)
+ return power;
+
+ CHECK_EQ(size, power);
+ return power + 1;
+ } else {
+ return -1;
+ }
+}
+
+static void TestCalloc(size_t n, size_t s, bool ok) {
+ char* p = reinterpret_cast<char*>(calloc(n, s));
+ if (!ok) {
+ EXPECT_EQ(NULL, p) << "calloc(n, s) should not succeed";
+ } else {
+ EXPECT_NE(reinterpret_cast<void*>(NULL), p)
+ << "calloc(n, s) should succeed";
+ for (size_t i = 0; i < n * s; i++) {
+ EXPECT_EQ('\0', p[i]);
+ }
+ free(p);
+ }
}
} // namespace
-TEST(TCMallocFreeCheck, BadPointerInFirstPageOfTheLargeObject) {
- char* p = reinterpret_cast<char*>(
- TCMallocDoMallocForTest(ExcludeSpaceForMarkForTest(kMaxSize + 1)));
- for (int offset = 1; offset < kPageSize ; offset <<= 1) {
+TEST(TCMallocTest, Malloc) {
+ // Try allocating data with a bunch of alignments and sizes
+ for (int size = 1; size < 1048576; size *= 2) {
+ unsigned char* ptr = reinterpret_cast<unsigned char*>(malloc(size));
+ // Should be 2 byte aligned
+ EXPECT_EQ(0u, reinterpret_cast<uintptr_t>(ptr) & 1);
+ Fill(ptr, size);
+ EXPECT_TRUE(Valid(ptr, size));
+ free(ptr);
+ }
+}
+
+TEST(TCMallocTest, Calloc) {
+ TestCalloc(0, 0, true);
+ TestCalloc(0, 1, true);
+ TestCalloc(1, 1, true);
+ TestCalloc(1 << 10, 0, true);
+ TestCalloc(1 << 20, 0, true);
+ TestCalloc(0, 1 << 10, true);
+ TestCalloc(0, 1 << 20, true);
+ TestCalloc(1 << 20, 2, true);
+ TestCalloc(2, 1 << 20, true);
+ TestCalloc(1000, 1000, true);
+}
+
+#ifdef NDEBUG
+// This makes sure that reallocing a small number of bytes in either
+// direction doesn't cause us to allocate new memory. Tcmalloc in debug mode
+// does not follow this.
+TEST(TCMallocTest, ReallocSmallDelta) {
+ int start_sizes[] = {100, 1000, 10000, 100000};
+ int deltas[] = {1, -2, 4, -8, 16, -32, 64, -128};
+
+ for (unsigned s = 0; s < sizeof(start_sizes) / sizeof(*start_sizes); ++s) {
+ void* p = malloc(start_sizes[s]);
+ ASSERT_TRUE(p);
+ // The larger the start-size, the larger the non-reallocing delta.
+ for (unsigned d = 0; d < s * 2; ++d) {
+ void* new_p = realloc(p, start_sizes[s] + deltas[d]);
+ ASSERT_EQ(p, new_p); // realloc should not allocate new memory
+ }
+ // Test again, but this time reallocing smaller first.
+ for (unsigned d = 0; d < s * 2; ++d) {
+ void* new_p = realloc(p, start_sizes[s] - deltas[d]);
+ ASSERT_EQ(p, new_p); // realloc should not allocate new memory
+ }
+ free(p);
+ }
+}
+#endif
+
+TEST(TCMallocTest, Realloc) {
+ for (int src_size = 0; src_size >= 0; src_size = NextSize(src_size)) {
+ for (int dst_size = 0; dst_size >= 0; dst_size = NextSize(dst_size)) {
+ unsigned char* src = reinterpret_cast<unsigned char*>(malloc(src_size));
+ Fill(src, src_size);
+ unsigned char* dst =
+ reinterpret_cast<unsigned char*>(realloc(src, dst_size));
+ EXPECT_TRUE(Valid(dst, min(src_size, dst_size)));
+ Fill(dst, dst_size);
+ EXPECT_TRUE(Valid(dst, dst_size));
+ if (dst != NULL)
+ free(dst);
+ }
+ }
+
+ // Now make sure realloc works correctly even when we overflow the
+ // packed cache, so some entries are evicted from the cache.
+ // The cache has 2^12 entries, keyed by page number.
+ const int kNumEntries = 1 << 14;
+ int** p = reinterpret_cast<int**>(malloc(sizeof(*p) * kNumEntries));
+ int sum = 0;
+ for (int i = 0; i < kNumEntries; i++) {
+ // no page size is likely to be bigger than 8192?
+ p[i] = reinterpret_cast<int*>(malloc(8192));
+ p[i][1000] = i; // use memory deep in the heart of p
+ }
+ for (int i = 0; i < kNumEntries; i++) {
+ p[i] = reinterpret_cast<int*>(realloc(p[i], 9000));
+ }
+ for (int i = 0; i < kNumEntries; i++) {
+ sum += p[i][1000];
+ free(p[i]);
+ }
+ EXPECT_EQ(kNumEntries / 2 * (kNumEntries - 1), sum); // assume kNE is even
+ free(p);
+}
+
+#ifdef NDEBUG
+TEST(TCMallocFreeTest, BadPointerInFirstPageOfTheLargeObject) {
+ const size_t kPageSize = base::GetPageSize();
+ char* p =
+ reinterpret_cast<char*>(TCMallocDoMallocForTest(10 * kPageSize + 1));
+ for (unsigned offset = 1; offset < kPageSize; offset <<= 1) {
ASSERT_DEATH(TCMallocDoFreeForTest(p + offset),
"Pointer is not pointing to the start of a span");
}
+ TCMallocDoFreeForTest(p);
}
-TEST(TCMallocFreeCheck, BadPageAlignedPointerInsideLargeObject) {
- char* p = reinterpret_cast<char*>(
- TCMallocDoMallocForTest(ExcludeSpaceForMarkForTest(kMaxSize + 1)));
+TEST(TCMallocFreeTest, BadPageAlignedPointerInsideLargeObject) {
+ const size_t kPageSize = base::GetPageSize();
+ const size_t kMaxSize = 10 * kPageSize;
+ char* p = reinterpret_cast<char*>(TCMallocDoMallocForTest(kMaxSize + 1));
- for (int offset = kPageSize; offset < kMaxSize; offset += kPageSize) {
+ for (unsigned offset = kPageSize; offset < kMaxSize; offset += kPageSize) {
// Only the first and last page of a span are in heap map. So for others
// tcmalloc will give a general error of invalid pointer.
- ASSERT_DEATH(TCMallocDoFreeForTest(p + offset),
- "Attempt to free invalid pointer");
+ ASSERT_DEATH(TCMallocDoFreeForTest(p + offset), "");
}
ASSERT_DEATH(TCMallocDoFreeForTest(p + kMaxSize),
"Pointer is not pointing to the start of a span");
+ TCMallocDoFreeForTest(p);
}
-TEST(TCMallocFreeCheck, DoubleFreeLargeObject) {
- char* p = reinterpret_cast<char*>(
- TCMallocDoMallocForTest(ExcludeSpaceForMarkForTest(kMaxSize + 1)));
+TEST(TCMallocFreeTest, DoubleFreeLargeObject) {
+ const size_t kMaxSize = 10 * base::GetPageSize();
+ char* p = reinterpret_cast<char*>(TCMallocDoMallocForTest(kMaxSize + 1));
ASSERT_DEATH(TCMallocDoFreeForTest(p); TCMallocDoFreeForTest(p),
"Object was not in-use");
}
-
-#ifdef NDEBUG
-TEST(TCMallocFreeCheck, DoubleFreeSmallObject) {
- for (size_t size = 1;
- size <= ExcludeSpaceForMarkForTest(kMaxSize);
- size <<= 1) {
+TEST(TCMallocFreeTest, DoubleFreeSmallObject) {
+ const size_t kPageSize = base::GetPageSize();
+ for (size_t size = 1; size <= kPageSize; size <<= 1) {
char* p = reinterpret_cast<char*>(TCMallocDoMallocForTest(size));
ASSERT_DEATH(TCMallocDoFreeForTest(p); TCMallocDoFreeForTest(p),
"Circular loop in list detected");
}
}
-#else
-TEST(TCMallocFreeCheck, DoubleFreeSmallObject) {
- size_t size = 1;
-
- // When the object is small, tcmalloc validation can not distinguish normal
- // memory corruption or double free, because there's not enough space in
- // freed objects to keep the mark.
- for (; size <= ExcludeSpaceForMarkForTest(kMinClassSize); size <<= 1) {
- char* p = reinterpret_cast<char*>(TCMallocDoMallocForTest(size));
- ASSERT_DEATH(TCMallocDoFreeForTest(p); TCMallocDoFreeForTest(p),
- "Memory corrupted");
- }
+#endif // NDEBUG
- for (; size <= ExcludeSpaceForMarkForTest(kMaxSize); size <<= 1) {
- char* p = reinterpret_cast<char*>(TCMallocDoMallocForTest(size));
- ASSERT_DEATH(TCMallocDoFreeForTest(p); TCMallocDoFreeForTest(p),
- "Attempt to double free");
- }
-}
#endif
-
-int main(int argc, char **argv) {
- testing::InitGoogleTest(&argc, argv);
- return RUN_ALL_TESTS();
-}
diff --git a/chromium/base/allocator/unittest_utils.cc b/chromium/base/allocator/unittest_utils.cc
index 130ba15f539..051d5685650 100644
--- a/chromium/base/allocator/unittest_utils.cc
+++ b/chromium/base/allocator/unittest_utils.cc
@@ -6,6 +6,7 @@
// of other libraries
#include <config.h>
+#include <stddef.h>
inline int snprintf(char* buffer, size_t count, const char* format, ...) {
int result;
diff --git a/chromium/base/android/OWNERS b/chromium/base/android/OWNERS
index 778fb752628..077efd6a8f2 100644
--- a/chromium/base/android/OWNERS
+++ b/chromium/base/android/OWNERS
@@ -1,3 +1,4 @@
nyquist@chromium.org
rmcilroy@chromium.org
+torne@chromium.org
yfriedman@chromium.org
diff --git a/chromium/base/android/apk_assets.cc b/chromium/base/android/apk_assets.cc
index fab7fd017f4..5319e73a4f0 100644
--- a/chromium/base/android/apk_assets.cc
+++ b/chromium/base/android/apk_assets.cc
@@ -6,6 +6,7 @@
#include "base/android/apk_assets.h"
+#include "base/android/context_utils.h"
#include "base/android/jni_array.h"
#include "base/android/jni_string.h"
#include "base/android/scoped_java_ref.h"
diff --git a/chromium/base/android/application_status_listener.cc b/chromium/base/android/application_status_listener.cc
index 5aee781faab..a1392686819 100644
--- a/chromium/base/android/application_status_listener.cc
+++ b/chromium/base/android/application_status_listener.cc
@@ -65,6 +65,12 @@ void ApplicationStatusListener::NotifyApplicationStateChange(
state);
}
+// static
+ApplicationState ApplicationStatusListener::GetState() {
+ return static_cast<ApplicationState>(
+ Java_ApplicationStatus_getStateForApplication(AttachCurrentThread()));
+}
+
static void OnApplicationStateChange(JNIEnv* env,
const JavaParamRef<jclass>& clazz,
jint new_state) {
diff --git a/chromium/base/android/application_status_listener.h b/chromium/base/android/application_status_listener.h
index 30048b2b515..6396a377f59 100644
--- a/chromium/base/android/application_status_listener.h
+++ b/chromium/base/android/application_status_listener.h
@@ -9,7 +9,7 @@
#include "base/android/jni_android.h"
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/singleton.h"
#include "base/observer_list_threadsafe.h"
@@ -27,6 +27,7 @@ namespace android {
// A Java counterpart will be generated for this enum.
// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.base
enum ApplicationState {
+ APPLICATION_STATE_UNKNOWN = 0,
APPLICATION_STATE_HAS_RUNNING_ACTIVITIES = 1,
APPLICATION_STATE_HAS_PAUSED_ACTIVITIES = 2,
APPLICATION_STATE_HAS_STOPPED_ACTIVITIES = 3,
@@ -73,6 +74,9 @@ class BASE_EXPORT ApplicationStatusListener {
// Internal use only: must be public to be called from JNI and unit tests.
static void NotifyApplicationStateChange(ApplicationState state);
+ // Expose jni call for ApplicationStatus.getStateForApplication.
+ static ApplicationState GetState();
+
private:
void Notify(ApplicationState state);
diff --git a/chromium/base/android/build_info.cc b/chromium/base/android/build_info.cc
index 68824b4c97b..2d3ef278ee2 100644
--- a/chromium/base/android/build_info.cc
+++ b/chromium/base/android/build_info.cc
@@ -6,6 +6,7 @@
#include <string>
+#include "base/android/context_utils.h"
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/android/scoped_java_ref.h"
diff --git a/chromium/base/android/build_info.h b/chromium/base/android/build_info.h
index cc90df22016..5195fb8829b 100644
--- a/chromium/base/android/build_info.h
+++ b/chromium/base/android/build_info.h
@@ -10,6 +10,7 @@
#include <string>
#include "base/base_export.h"
+#include "base/macros.h"
#include "base/memory/singleton.h"
namespace base {
diff --git a/chromium/base/android/content_uri_utils.cc b/chromium/base/android/content_uri_utils.cc
index 0482feef891..195598bfb3f 100644
--- a/chromium/base/android/content_uri_utils.cc
+++ b/chromium/base/android/content_uri_utils.cc
@@ -4,6 +4,7 @@
#include "base/android/content_uri_utils.h"
+#include "base/android/context_utils.h"
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "jni/ContentUriUtils_jni.h"
diff --git a/chromium/base/android/content_uri_utils.h b/chromium/base/android/content_uri_utils.h
index e66b77077e1..59fa1e68a07 100644
--- a/chromium/base/android/content_uri_utils.h
+++ b/chromium/base/android/content_uri_utils.h
@@ -8,7 +8,6 @@
#include <jni.h>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/files/file.h"
#include "base/files/file_path.h"
diff --git a/chromium/base/android/context_utils.cc b/chromium/base/android/context_utils.cc
new file mode 100644
index 00000000000..fd62c45f606
--- /dev/null
+++ b/chromium/base/android/context_utils.cc
@@ -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.
+
+#include "base/android/context_utils.h"
+
+#include <jni.h>
+
+#include "base/android/scoped_java_ref.h"
+#include "base/lazy_instance.h"
+#include "jni/ContextUtils_jni.h"
+
+using base::android::JavaRef;
+
+namespace base {
+namespace android {
+
+namespace {
+
+// Leak the global app context, as it is used from a non-joinable worker thread
+// that may still be running at shutdown. There is no harm in doing this.
+base::LazyInstance<base::android::ScopedJavaGlobalRef<jobject>>::Leaky
+ g_application_context = LAZY_INSTANCE_INITIALIZER;
+
+void SetNativeApplicationContext(JNIEnv* env, const JavaRef<jobject>& context) {
+ if (env->IsSameObject(g_application_context.Get().obj(), context.obj())) {
+ // It's safe to set the context more than once if it's the same context.
+ return;
+ }
+ DCHECK(g_application_context.Get().is_null());
+ g_application_context.Get().Reset(context);
+}
+
+} // namespace
+
+jobject GetApplicationContext() {
+ DCHECK(!g_application_context.Get().is_null());
+ return g_application_context.Get().obj();
+}
+
+void InitApplicationContext(JNIEnv* env, const JavaRef<jobject>& context) {
+ SetNativeApplicationContext(env, context);
+ Java_ContextUtils_initJavaSideApplicationContext(env, context.obj());
+}
+
+static void InitNativeSideApplicationContext(
+ JNIEnv* env,
+ const JavaParamRef<jclass>& clazz,
+ const JavaParamRef<jobject>& context) {
+ SetNativeApplicationContext(env, context);
+}
+
+bool RegisterContextUtils(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
+
+} // namespace android
+} // namespace base
diff --git a/chromium/base/android/context_utils.h b/chromium/base/android/context_utils.h
new file mode 100644
index 00000000000..52895a9a530
--- /dev/null
+++ b/chromium/base/android/context_utils.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_ANDROID_CONTEXT_UTILS_H_
+#define BASE_ANDROID_CONTEXT_UTILS_H_
+
+#include <jni.h>
+
+#include "base/android/scoped_java_ref.h"
+#include "base/base_export.h"
+
+namespace base {
+namespace android {
+
+// Gets a global ref to the application context set with
+// InitApplicationContext(). Ownership is retained by the function - the caller
+// must NOT release it.
+BASE_EXPORT jobject GetApplicationContext();
+
+// Initialize the global application context object.
+// Either this or the Java equivalent ContextUtils.initApplicationContext must
+// be called once during startup. JNI bindings must have been initialized, as
+// the context is stored on both sides.
+BASE_EXPORT void InitApplicationContext(
+ JNIEnv* env,
+ const base::android::JavaRef<jobject>& context);
+
+bool RegisterContextUtils(JNIEnv* env);
+
+} // namespace android
+} // namespace base
+
+#endif // BASE_ANDROID_CONTEXT_UTILS_H_
diff --git a/chromium/base/android/cxa_demangle_stub.cc b/chromium/base/android/cxa_demangle_stub.cc
index b0d2b87c593..18297284373 100644
--- a/chromium/base/android/cxa_demangle_stub.cc
+++ b/chromium/base/android/cxa_demangle_stub.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
#include <unistd.h>
// LLVM's demangler is large, and we have no need of it. Overriding it with
diff --git a/chromium/base/android/fifo_utils.h b/chromium/base/android/fifo_utils.h
index 1936defaf6e..0bad8e2c6e5 100644
--- a/chromium/base/android/fifo_utils.h
+++ b/chromium/base/android/fifo_utils.h
@@ -8,7 +8,6 @@
#include <stdio.h>
#include "base/base_export.h"
-#include "base/basictypes.h"
namespace base {
diff --git a/chromium/base/android/jni_generator/jni_generator.gyp b/chromium/base/android/jni_generator/jni_generator.gyp
index 4a17f3e57c1..ce936a0ec4c 100644
--- a/chromium/base/android/jni_generator/jni_generator.gyp
+++ b/chromium/base/android/jni_generator/jni_generator.gyp
@@ -4,6 +4,7 @@
{
'targets': [
+ # GYP: //base/android/jni_generator:jni_generator_tests
{
'target_name': 'jni_generator_py_tests',
'type': 'none',
@@ -29,6 +30,7 @@
},
],
},
+ # GYP: //base/android/jni_generator:jni_sample_header
{
'target_name': 'jni_sample_header',
'type': 'none',
@@ -40,6 +42,7 @@
},
'includes': [ '../../../build/jni_generator.gypi' ],
},
+ # GYP: //base/android/jni_generator:jni_sample_java
{
'target_name': 'jni_sample_java',
'type': 'none',
@@ -51,6 +54,7 @@
],
'includes': [ '../../../build/java.gypi' ],
},
+ # GYP: //base/android/jni_generator:jni_generator_tests
{
'target_name': 'jni_generator_tests',
'type': 'executable',
diff --git a/chromium/base/android/library_loader/library_loader_hooks.cc b/chromium/base/android/library_loader/library_loader_hooks.cc
index 67b7c5db1dd..bbc99352f6d 100644
--- a/chromium/base/android/library_loader/library_loader_hooks.cc
+++ b/chromium/base/android/library_loader/library_loader_hooks.cc
@@ -148,6 +148,12 @@ static jboolean ForkAndPrefetchNativeLibrary(
return NativeLibraryPrefetcher::ForkAndPrefetchNativeLibrary();
}
+static jint PercentageOfResidentNativeLibraryCode(
+ JNIEnv* env,
+ const JavaParamRef<jclass>& clazz) {
+ return NativeLibraryPrefetcher::PercentageOfResidentNativeLibraryCode();
+}
+
bool RegisterLibraryLoaderEntryHook(JNIEnv* env) {
return RegisterNativesImpl(env);
}
diff --git a/chromium/base/android/library_loader/library_prefetcher.cc b/chromium/base/android/library_loader/library_prefetcher.cc
index 118e80cc0e7..c7ec990f0a7 100644
--- a/chromium/base/android/library_loader/library_prefetcher.cc
+++ b/chromium/base/android/library_loader/library_prefetcher.cc
@@ -4,9 +4,12 @@
#include "base/android/library_loader/library_prefetcher.h"
+#include <stddef.h>
+#include <sys/mman.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <unistd.h>
+#include <algorithm>
#include <utility>
#include <vector>
@@ -153,5 +156,41 @@ bool NativeLibraryPrefetcher::ForkAndPrefetchNativeLibrary() {
}
}
+// static
+int NativeLibraryPrefetcher::PercentageOfResidentCode(
+ const std::vector<AddressRange>& ranges) {
+ size_t total_pages = 0;
+ size_t resident_pages = 0;
+ const uintptr_t page_mask = kPageSize - 1;
+
+ for (const auto& range : ranges) {
+ if (range.first & page_mask || range.second & page_mask)
+ return -1;
+ size_t length = range.second - range.first;
+ size_t pages = length / kPageSize;
+ total_pages += pages;
+ std::vector<unsigned char> is_page_resident(pages);
+ int err = mincore(reinterpret_cast<void*>(range.first), length,
+ &is_page_resident[0]);
+ DPCHECK(!err);
+ if (err)
+ return -1;
+ resident_pages +=
+ std::count_if(is_page_resident.begin(), is_page_resident.end(),
+ [](unsigned char x) { return x & 1; });
+ }
+ if (total_pages == 0)
+ return -1;
+ return static_cast<int>((100 * resident_pages) / total_pages);
+}
+
+// static
+int NativeLibraryPrefetcher::PercentageOfResidentNativeLibraryCode() {
+ std::vector<AddressRange> ranges;
+ if (!FindRanges(&ranges))
+ return -1;
+ return PercentageOfResidentCode(ranges);
+}
+
} // namespace android
} // namespace base
diff --git a/chromium/base/android/library_loader/library_prefetcher.h b/chromium/base/android/library_loader/library_prefetcher.h
index 64e5e1ecb4b..44a93e67680 100644
--- a/chromium/base/android/library_loader/library_prefetcher.h
+++ b/chromium/base/android/library_loader/library_prefetcher.h
@@ -12,6 +12,7 @@
#include "base/debug/proc_maps_linux.h"
#include "base/gtest_prod_util.h"
+#include "base/macros.h"
namespace base {
namespace android {
@@ -30,6 +31,9 @@ class BASE_EXPORT NativeLibraryPrefetcher {
// process pre-fetching these ranges and wait()s for it.
// Returns true for success.
static bool ForkAndPrefetchNativeLibrary();
+ // Returns the percentage of the native library code currently resident in
+ // memory, or -1 in case of error.
+ static int PercentageOfResidentNativeLibraryCode();
private:
using AddressRange = std::pair<uintptr_t, uintptr_t>;
@@ -43,6 +47,10 @@ class BASE_EXPORT NativeLibraryPrefetcher {
// Returns true for success.
static bool FindRanges(std::vector<AddressRange>* ranges);
+ // Returns the percentage of the given address ranges currently resident in
+ // memory, or -1 in case of error.
+ static int PercentageOfResidentCode(const std::vector<AddressRange>& ranges);
+
FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
TestIsGoodToPrefetchNoRange);
FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
@@ -57,6 +65,10 @@ class BASE_EXPORT NativeLibraryPrefetcher {
TestFilterLibchromeRangesOnlyIfPossibleNoLibchrome);
FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
TestFilterLibchromeRangesOnlyIfPossibleHasLibchrome);
+ FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
+ TestPercentageOfResidentCode);
+ FRIEND_TEST_ALL_PREFIXES(NativeLibraryPrefetcherTest,
+ TestPercentageOfResidentCodeTwoRegions);
DISALLOW_IMPLICIT_CONSTRUCTORS(NativeLibraryPrefetcher);
};
diff --git a/chromium/base/android/library_loader/library_prefetcher_unittest.cc b/chromium/base/android/library_loader/library_prefetcher_unittest.cc
index 7b7296f5f61..f0a6ffe733e 100644
--- a/chromium/base/android/library_loader/library_prefetcher_unittest.cc
+++ b/chromium/base/android/library_loader/library_prefetcher_unittest.cc
@@ -4,20 +4,25 @@
#include "base/android/library_loader/library_prefetcher.h"
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/mman.h>
#include <string>
#include <vector>
#include "base/debug/proc_maps_linux.h"
+#include "base/memory/shared_memory.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;
+const uint8_t kRead = base::debug::MappedMemoryRegion::READ;
+const uint8_t kReadPrivate = base::debug::MappedMemoryRegion::READ |
+ base::debug::MappedMemoryRegion::PRIVATE;
+const uint8_t kExecutePrivate = base::debug::MappedMemoryRegion::EXECUTE |
+ base::debug::MappedMemoryRegion::PRIVATE;
+const size_t kPageSize = 4096;
} // namespace
TEST(NativeLibraryPrefetcherTest, TestIsGoodToPrefetchNoRange) {
@@ -91,5 +96,60 @@ TEST(NativeLibraryPrefetcherTest,
EXPECT_EQ(ranges[0].second, 0x7U);
}
+TEST(NativeLibraryPrefetcherTest, DISABLED_TestPercentageOfResidentCode) {
+ size_t length = 4 * kPageSize;
+ base::SharedMemory shared_mem;
+ ASSERT_TRUE(shared_mem.CreateAndMapAnonymous(length));
+ void* address = shared_mem.memory();
+
+ std::vector<NativeLibraryPrefetcher::AddressRange> ranges = {
+ {reinterpret_cast<uintptr_t>(address),
+ reinterpret_cast<uintptr_t>(address) + length}};
+
+ // Remove everything.
+ ASSERT_EQ(0, madvise(address, length, MADV_DONTNEED));
+ // TODO(lizeb): If flaky, mock mincore().
+ EXPECT_EQ(0, NativeLibraryPrefetcher::PercentageOfResidentCode(ranges));
+
+ // Get everything back.
+ ASSERT_EQ(0, mlock(address, length));
+ EXPECT_EQ(100, NativeLibraryPrefetcher::PercentageOfResidentCode(ranges));
+ munlock(address, length);
+}
+
+TEST(NativeLibraryPrefetcherTest,
+ DISABLED_TestPercentageOfResidentCodeTwoRegions) {
+ size_t length = 4 * kPageSize;
+ base::SharedMemory shared_mem;
+ ASSERT_TRUE(shared_mem.CreateAndMapAnonymous(length));
+ void* address = shared_mem.memory();
+
+ size_t length2 = 8 * kPageSize;
+ base::SharedMemory shared_mem2;
+ ASSERT_TRUE(shared_mem2.CreateAndMapAnonymous(length2));
+ void* address2 = shared_mem2.memory();
+
+ std::vector<NativeLibraryPrefetcher::AddressRange> ranges = {
+ {reinterpret_cast<uintptr_t>(address),
+ reinterpret_cast<uintptr_t>(address) + length},
+ {reinterpret_cast<uintptr_t>(address2),
+ reinterpret_cast<uintptr_t>(address2) + length2}};
+
+ // Remove everything.
+ ASSERT_EQ(0, madvise(address, length, MADV_DONTNEED));
+ ASSERT_EQ(0, madvise(address2, length, MADV_DONTNEED));
+ // TODO(lizeb): If flaky, mock mincore().
+ EXPECT_EQ(0, NativeLibraryPrefetcher::PercentageOfResidentCode(ranges));
+
+ // Get back the first range.
+ ASSERT_EQ(0, mlock(address, length));
+ EXPECT_EQ(33, NativeLibraryPrefetcher::PercentageOfResidentCode(ranges));
+ // The second one.
+ ASSERT_EQ(0, mlock(address2, length2));
+ EXPECT_EQ(100, NativeLibraryPrefetcher::PercentageOfResidentCode(ranges));
+ munlock(address, length);
+ munlock(address2, length);
+}
+
} // namespace android
} // namespace base
diff --git a/chromium/base/android/linker/config.gni b/chromium/base/android/linker/config.gni
index 99cbcf0e252..d07caa6dc12 100644
--- a/chromium/base/android/linker/config.gni
+++ b/chromium/base/android/linker/config.gni
@@ -2,7 +2,10 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# TODO(GYP) add "|| profiling_full_stack_frames
-# Only enable the chromium linker on regular builds, since the
-# component build crashes on Android 4.4. See b/11379966
-chromium_linker_supported = !is_component_build
+import("//build/config/android/config.gni")
+import("//build/config/sanitizers/sanitizers.gni")
+
+# Chromium linker crashes on component builds on Android 4.4. See b/11379966
+# Chromium linker causes instrumentation to return incorrect results.
+chromium_linker_supported =
+ !is_component_build && !use_order_profiling && !is_asan
diff --git a/chromium/base/android/memory_pressure_listener_android.cc b/chromium/base/android/memory_pressure_listener_android.cc
index 9d3dd463df0..5975b946a4d 100644
--- a/chromium/base/android/memory_pressure_listener_android.cc
+++ b/chromium/base/android/memory_pressure_listener_android.cc
@@ -4,6 +4,7 @@
#include "base/android/memory_pressure_listener_android.h"
+#include "base/android/context_utils.h"
#include "base/memory/memory_pressure_listener.h"
#include "jni/MemoryPressureListener_jni.h"
diff --git a/chromium/base/android/memory_pressure_listener_android.h b/chromium/base/android/memory_pressure_listener_android.h
index eed8dbb5756..15f68c26d69 100644
--- a/chromium/base/android/memory_pressure_listener_android.h
+++ b/chromium/base/android/memory_pressure_listener_android.h
@@ -6,6 +6,7 @@
#define BASE_ANDROID_MEMORY_PRESSURE_LISTENER_ANDROID_H_
#include "base/android/jni_android.h"
+#include "base/macros.h"
namespace base {
namespace android {
diff --git a/chromium/base/android/path_utils.cc b/chromium/base/android/path_utils.cc
index caad53a36f6..85e29de8bfa 100644
--- a/chromium/base/android/path_utils.cc
+++ b/chromium/base/android/path_utils.cc
@@ -4,6 +4,7 @@
#include "base/android/path_utils.h"
+#include "base/android/context_utils.h"
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/android/scoped_java_ref.h"
diff --git a/chromium/base/android/path_utils_unittest.cc b/chromium/base/android/path_utils_unittest.cc
index d991810aa91..dca8ca13ac1 100644
--- a/chromium/base/android/path_utils_unittest.cc
+++ b/chromium/base/android/path_utils_unittest.cc
@@ -54,8 +54,11 @@ TEST_F(PathUtilsTest, TestGetNativeLibraryDirectory) {
// the base tests shared object.
FilePath path;
GetNativeLibraryDirectory(&path);
- EXPECT_TRUE(base::PathExists(path.Append(("libbase_unittests.so"))) ||
- base::PathExists(path.Append(("libbase_unittests.cr.so"))));
+ EXPECT_TRUE(
+ base::PathExists(path.Append("libbase_unittests.so")) ||
+ base::PathExists(path.Append("libbase_unittests.cr.so")) ||
+ base::PathExists(path.Append("lib_base_unittests__library.so")) ||
+ base::PathExists(path.Append("lib_base_unittests__library.cr.so")));
}
} // namespace android
diff --git a/chromium/base/android/record_histogram.cc b/chromium/base/android/record_histogram.cc
index 51ca482e291..ea88f312a9e 100644
--- a/chromium/base/android/record_histogram.cc
+++ b/chromium/base/android/record_histogram.cc
@@ -4,11 +4,14 @@
#include "base/android/record_histogram.h"
+#include <stdint.h>
+
#include <map>
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/lazy_instance.h"
+#include "base/macros.h"
#include "base/metrics/histogram.h"
#include "base/metrics/sparse_histogram.h"
#include "base/metrics/statistics_recorder.h"
@@ -69,8 +72,8 @@ class HistogramCache {
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);
+ int64_t min = static_cast<int64_t>(j_min);
+ int64_t max = static_cast<int64_t>(j_max);
int num_buckets = static_cast<int>(j_num_buckets);
HistogramBase* histogram = FindLocked(j_histogram_key);
if (histogram) {
@@ -93,8 +96,8 @@ class HistogramCache {
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);
+ int64_t min = static_cast<int64_t>(j_min);
+ int64_t max = static_cast<int64_t>(j_max);
int num_buckets = static_cast<int>(j_num_buckets);
HistogramBase* histogram = FindLocked(j_histogram_key);
if (histogram) {
@@ -133,8 +136,8 @@ class HistogramCache {
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);
+ int64_t min = static_cast<int64_t>(j_min);
+ int64_t max = static_cast<int64_t>(j_max);
int bucket_count = static_cast<int>(j_bucket_count);
if (histogram) {
DCHECK(histogram->HasConstructionArguments(min, max, bucket_count));
@@ -252,7 +255,7 @@ void RecordCustomTimesHistogramMilliseconds(
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)));
+ ->AddTime(TimeDelta::FromMilliseconds(static_cast<int64_t>(j_duration)));
}
void Initialize(JNIEnv* env, const JavaParamRef<jclass>&) {
diff --git a/chromium/base/android/scoped_java_ref.h b/chromium/base/android/scoped_java_ref.h
index cad63b75617..8dcf2bca039 100644
--- a/chromium/base/android/scoped_java_ref.h
+++ b/chromium/base/android/scoped_java_ref.h
@@ -9,8 +9,8 @@
#include <stddef.h>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/template_util.h"
namespace base {
@@ -42,6 +42,15 @@ template<typename T> class JavaRef;
template<>
class BASE_EXPORT JavaRef<jobject> {
public:
+ // Allow nullptr to be converted to JavaRef. This avoids having to declare an
+ // empty ScopedJavaLocalRef just to pass null to a function with a JavaRef
+ // parameter, and makes C++ "nullptr" and Java "null" equivalent.
+ JavaRef(std::nullptr_t) : JavaRef() {}
+
+ // Public to allow destruction of temporary JavaRef objects created by the
+ // nullptr conversion. Don't add anything else here; it's inlined.
+ ~JavaRef() {}
+
jobject obj() const { return obj_; }
bool is_null() const { return obj_ == NULL; }
@@ -60,9 +69,6 @@ class BASE_EXPORT JavaRef<jobject> {
JavaRef(JNIEnv* env, jobject obj) : obj_(obj) {}
#endif
- // Don't add anything else here; it's inlined.
- ~JavaRef() {}
-
// The following are implementation detail convenience methods, for
// use by the sub-classes.
JNIEnv* SetNewLocalRef(JNIEnv* env, jobject obj);
@@ -83,11 +89,13 @@ class BASE_EXPORT JavaRef<jobject> {
template<typename T>
class JavaRef : public JavaRef<jobject> {
public:
+ JavaRef(std::nullptr_t) : JavaRef<jobject>(nullptr) {}
+ ~JavaRef() {}
+
T obj() const { return static_cast<T>(JavaRef<jobject>::obj()); }
protected:
JavaRef() {}
- ~JavaRef() {}
JavaRef(JNIEnv* env, T obj) : JavaRef<jobject>(env, obj) {}
@@ -106,6 +114,12 @@ class JavaParamRef : public JavaRef<T> {
// Does not assume ownership as parameters should not be deleted.
JavaParamRef(JNIEnv* env, T obj) : JavaRef<T>(env, obj) {}
+ // Allow nullptr to be converted to JavaParamRef. Some unit tests call JNI
+ // methods directly from C++ and pass null for objects which are not actually
+ // used by the implementation (e.g. the caller object); allow this to keep
+ // working.
+ JavaParamRef(std::nullptr_t) : JavaRef<T>(nullptr) {}
+
~JavaParamRef() {}
// TODO(torne): remove this cast once we're using JavaRef consistently.
@@ -213,7 +227,7 @@ class ScopedJavaGlobalRef : public JavaRef<T> {
public:
ScopedJavaGlobalRef() {}
- explicit ScopedJavaGlobalRef(const ScopedJavaGlobalRef<T>& other) {
+ ScopedJavaGlobalRef(const ScopedJavaGlobalRef<T>& other) {
this->Reset(other);
}
@@ -228,6 +242,12 @@ class ScopedJavaGlobalRef : public JavaRef<T> {
this->Reset();
}
+ // Overloaded assignment operator defined for consistency with the implicit
+ // copy constructor.
+ void operator=(const ScopedJavaGlobalRef<T>& other) {
+ this->Reset(other);
+ }
+
void Reset() {
this->ResetGlobalRef();
}
diff --git a/chromium/base/android/sys_utils_unittest.cc b/chromium/base/android/sys_utils_unittest.cc
index d1421ec57ab..d16e2368de5 100644
--- a/chromium/base/android/sys_utils_unittest.cc
+++ b/chromium/base/android/sys_utils_unittest.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
#include <unistd.h>
#include "base/sys_info.h"
diff --git a/chromium/base/android/trace_event_binding.cc b/chromium/base/android/trace_event_binding.cc
index f761a646027..534d8552fcd 100644
--- a/chromium/base/android/trace_event_binding.cc
+++ b/chromium/base/android/trace_event_binding.cc
@@ -10,6 +10,7 @@
#include "base/android/jni_string.h"
#include "base/lazy_instance.h"
+#include "base/macros.h"
#include "base/trace_event/trace_event.h"
#include "base/trace_event/trace_event_impl.h"
#include "jni/TraceEvent_jni.h"
diff --git a/chromium/base/at_exit.h b/chromium/base/at_exit.h
index 6fe7361a850..04e3f764222 100644
--- a/chromium/base/at_exit.h
+++ b/chromium/base/at_exit.h
@@ -8,8 +8,8 @@
#include <stack>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/callback.h"
+#include "base/macros.h"
#include "base/synchronization/lock.h"
namespace base {
diff --git a/chromium/base/atomic_sequence_num.h b/chromium/base/atomic_sequence_num.h
index 7bf27789910..59b0d2551a4 100644
--- a/chromium/base/atomic_sequence_num.h
+++ b/chromium/base/atomic_sequence_num.h
@@ -6,7 +6,7 @@
#define BASE_ATOMIC_SEQUENCE_NUM_H_
#include "base/atomicops.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
namespace base {
diff --git a/chromium/base/atomicops.h b/chromium/base/atomicops.h
index f983b455f19..3428fe87abb 100644
--- a/chromium/base/atomicops.h
+++ b/chromium/base/atomicops.h
@@ -144,27 +144,13 @@ Atomic64 Release_Load(volatile const Atomic64* ptr);
} // namespace subtle
} // namespace base
-// Try to use a portable implementation based on C++11 atomics.
-//
-// Some toolchains support C++11 language features without supporting library
-// features (recent compiler, older STL). Whitelist libstdc++ and libc++ that we
-// know will have <atomic> when compiling C++11.
-#if ((__cplusplus >= 201103L) && \
- ((defined(__GLIBCXX__) && (__GLIBCXX__ > 20110216)) || \
- (defined(_LIBCPP_VERSION) && (_LIBCPP_STD_VER >= 11))))
+#if defined(OS_WIN)
+// TODO(jfb): The MSVC header includes windows.h, which other files end up
+// relying on. Fix this as part of crbug.com/559247.
+# include "base/atomicops_internals_x86_msvc.h"
+#else
# include "base/atomicops_internals_portable.h"
-#else // Otherwise use a platform specific implementation.
-# if defined(THREAD_SANITIZER)
-# error "Thread sanitizer must use the portable atomic operations"
-# elif (defined(OS_WIN) && defined(COMPILER_MSVC) && \
- defined(ARCH_CPU_X86_FAMILY))
-# include "base/atomicops_internals_x86_msvc.h"
-# elif defined(OS_MACOSX)
-# include "base/atomicops_internals_mac.h"
-# else
-# error "Atomic operations are not supported on your platform"
-# endif
-#endif // Portable / non-portable includes.
+#endif
// On some platforms we need additional declarations to make
// AtomicWord compatible with our other Atomic* types.
diff --git a/chromium/base/atomicops_internals_atomicword_compat.h b/chromium/base/atomicops_internals_atomicword_compat.h
index 342a6e4592c..8b000d2571d 100644
--- a/chromium/base/atomicops_internals_atomicword_compat.h
+++ b/chromium/base/atomicops_internals_atomicword_compat.h
@@ -7,7 +7,11 @@
#ifndef BASE_ATOMICOPS_INTERNALS_ATOMICWORD_COMPAT_H_
#define BASE_ATOMICOPS_INTERNALS_ATOMICWORD_COMPAT_H_
-// AtomicWord is a synonym for intptr_t, and Atomic32 is a synonym for int32,
+#include <stdint.h>
+
+#include "build/build_config.h"
+
+// AtomicWord is a synonym for intptr_t, and Atomic32 is a synonym for int32_t,
// which in turn means int. On some LP32 platforms, intptr_t is an int, but
// on others, it's a long. When AtomicWord and Atomic32 are based on different
// fundamental types, their pointers are incompatible.
diff --git a/chromium/base/atomicops_internals_mac.h b/chromium/base/atomicops_internals_mac.h
deleted file mode 100644
index 98864a77da2..00000000000
--- a/chromium/base/atomicops_internals_mac.h
+++ /dev/null
@@ -1,197 +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 file is an internal atomic implementation, use base/atomicops.h instead.
-
-#ifndef BASE_ATOMICOPS_INTERNALS_MAC_H_
-#define BASE_ATOMICOPS_INTERNALS_MAC_H_
-
-#include <libkern/OSAtomic.h>
-
-namespace base {
-namespace subtle {
-
-inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
- Atomic32 old_value,
- Atomic32 new_value) {
- Atomic32 prev_value;
- do {
- if (OSAtomicCompareAndSwap32(old_value, new_value,
- const_cast<Atomic32*>(ptr))) {
- return old_value;
- }
- prev_value = *ptr;
- } while (prev_value == old_value);
- return prev_value;
-}
-
-inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
- Atomic32 new_value) {
- Atomic32 old_value;
- do {
- old_value = *ptr;
- } while (!OSAtomicCompareAndSwap32(old_value, new_value,
- const_cast<Atomic32*>(ptr)));
- return old_value;
-}
-
-inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
- Atomic32 increment) {
- return OSAtomicAdd32(increment, const_cast<Atomic32*>(ptr));
-}
-
-inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
- Atomic32 increment) {
- return OSAtomicAdd32Barrier(increment, const_cast<Atomic32*>(ptr));
-}
-
-inline void MemoryBarrier() {
- OSMemoryBarrier();
-}
-
-inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
- Atomic32 old_value,
- Atomic32 new_value) {
- Atomic32 prev_value;
- do {
- if (OSAtomicCompareAndSwap32Barrier(old_value, new_value,
- const_cast<Atomic32*>(ptr))) {
- return old_value;
- }
- prev_value = *ptr;
- } while (prev_value == old_value);
- return prev_value;
-}
-
-inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
- Atomic32 old_value,
- Atomic32 new_value) {
- return Acquire_CompareAndSwap(ptr, old_value, new_value);
-}
-
-inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
- *ptr = value;
-}
-
-inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
- *ptr = value;
- MemoryBarrier();
-}
-
-inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
- MemoryBarrier();
- *ptr = value;
-}
-
-inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
- return *ptr;
-}
-
-inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
- Atomic32 value = *ptr;
- MemoryBarrier();
- return value;
-}
-
-inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
- MemoryBarrier();
- return *ptr;
-}
-
-#ifdef __LP64__
-
-// 64-bit implementation on 64-bit platform
-
-inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
- Atomic64 old_value,
- Atomic64 new_value) {
- Atomic64 prev_value;
- do {
- if (OSAtomicCompareAndSwap64(old_value, new_value,
- reinterpret_cast<volatile int64_t*>(ptr))) {
- return old_value;
- }
- prev_value = *ptr;
- } while (prev_value == old_value);
- return prev_value;
-}
-
-inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
- Atomic64 new_value) {
- Atomic64 old_value;
- do {
- old_value = *ptr;
- } while (!OSAtomicCompareAndSwap64(old_value, new_value,
- reinterpret_cast<volatile int64_t*>(ptr)));
- return old_value;
-}
-
-inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
- Atomic64 increment) {
- return OSAtomicAdd64(increment, reinterpret_cast<volatile int64_t*>(ptr));
-}
-
-inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
- Atomic64 increment) {
- return OSAtomicAdd64Barrier(increment,
- reinterpret_cast<volatile int64_t*>(ptr));
-}
-
-inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
- Atomic64 old_value,
- Atomic64 new_value) {
- Atomic64 prev_value;
- do {
- if (OSAtomicCompareAndSwap64Barrier(
- old_value, new_value, reinterpret_cast<volatile int64_t*>(ptr))) {
- return old_value;
- }
- prev_value = *ptr;
- } while (prev_value == old_value);
- return prev_value;
-}
-
-inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
- Atomic64 old_value,
- Atomic64 new_value) {
- // The lib kern interface does not distinguish between
- // Acquire and Release memory barriers; they are equivalent.
- return Acquire_CompareAndSwap(ptr, old_value, new_value);
-}
-
-inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
- *ptr = value;
-}
-
-inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
- *ptr = value;
- MemoryBarrier();
-}
-
-inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
- MemoryBarrier();
- *ptr = value;
-}
-
-inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
- return *ptr;
-}
-
-inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
- Atomic64 value = *ptr;
- MemoryBarrier();
- return value;
-}
-
-inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
- MemoryBarrier();
- return *ptr;
-}
-
-#endif // defined(__LP64__)
-
-} // namespace subtle
-} // namespace base
-
-#endif // BASE_ATOMICOPS_INTERNALS_MAC_H_
diff --git a/chromium/base/atomicops_internals_portable.h b/chromium/base/atomicops_internals_portable.h
index d28561076dd..ee034dee123 100644
--- a/chromium/base/atomicops_internals_portable.h
+++ b/chromium/base/atomicops_internals_portable.h
@@ -34,6 +34,8 @@
#include <atomic>
+#include "build/build_config.h"
+
namespace base {
namespace subtle {
diff --git a/chromium/base/atomicops_internals_x86_msvc.h b/chromium/base/atomicops_internals_x86_msvc.h
index 71ddca2ba38..9f05b7e78d0 100644
--- a/chromium/base/atomicops_internals_x86_msvc.h
+++ b/chromium/base/atomicops_internals_x86_msvc.h
@@ -12,6 +12,7 @@
#include <intrin.h>
#include "base/macros.h"
+#include "build/build_config.h"
#if defined(ARCH_CPU_64_BITS)
// windows.h #defines this (only on x64). This causes problems because the
@@ -109,7 +110,7 @@ inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
// 64-bit low-level operations on 64-bit platform.
-COMPILE_ASSERT(sizeof(Atomic64) == sizeof(PVOID), atomic_word_is_atomic);
+static_assert(sizeof(Atomic64) == sizeof(PVOID), "atomic word is atomic");
inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
Atomic64 old_value,
diff --git a/chromium/base/atomicops_unittest.cc b/chromium/base/atomicops_unittest.cc
index 3fd55974722..7298609270f 100644
--- a/chromium/base/atomicops_unittest.cc
+++ b/chromium/base/atomicops_unittest.cc
@@ -89,6 +89,13 @@ static void TestCompareAndSwap() {
EXPECT_EQ(1, value);
EXPECT_EQ(0, prev);
+ // Verify that CAS will *not* change "value" if it doesn't match the
+ // expected number. CAS will always return the actual value of the
+ // variable from before any change.
+ AtomicType fail = base::subtle::NoBarrier_CompareAndSwap(&value, 0, 2);
+ EXPECT_EQ(1, value);
+ EXPECT_EQ(1, fail);
+
// 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) <<
diff --git a/chromium/base/auto_reset.h b/chromium/base/auto_reset.h
index a5bcfaae8a8..9116537bfb3 100644
--- a/chromium/base/auto_reset.h
+++ b/chromium/base/auto_reset.h
@@ -5,7 +5,7 @@
#ifndef BASE_AUTO_RESET_H_
#define BASE_AUTO_RESET_H_
-#include "base/basictypes.h"
+#include "base/macros.h"
// base::AutoReset<> is useful for setting a variable to a new value only within
// a particular scope. An base::AutoReset<> object resets a variable to its
diff --git a/chromium/base/base.gyp b/chromium/base/base.gyp
index 4b11485e0a5..94a1d492585 100644
--- a/chromium/base/base.gyp
+++ b/chromium/base/base.gyp
@@ -21,8 +21,8 @@
'optimize': 'max',
},
'dependencies': [
+ 'base_debugging_flags#target',
'base_static',
- 'allocator/allocator.gyp:allocator_extension_thunks',
'../testing/gtest.gyp:gtest_prod',
'../third_party/modp_b64/modp_b64.gyp:modp_b64',
'third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
@@ -207,7 +207,7 @@
},
}],
['OS != "win" and (OS != "ios" or _toolset == "host")', {
- 'dependencies': ['../third_party/libevent/libevent.gyp:libevent'],
+ 'dependencies': ['third_party/libevent/libevent.gyp:libevent'],
},],
['component=="shared_library"', {
'conditions': [
@@ -426,6 +426,7 @@
'target_name': 'base_unittests',
'type': '<(gtest_target_type)',
'sources': [
+ 'allocator/tcmalloc_unittest.cc',
'android/application_status_listener_unittest.cc',
'android/content_uri_utils_unittest.cc',
'android/jni_android_unittest.cc',
@@ -439,6 +440,7 @@
'atomicops_unittest.cc',
'barrier_closure_unittest.cc',
'base64_unittest.cc',
+ 'base64url_unittest.cc',
'big_endian_unittest.cc',
'bind_unittest.cc',
'bind_unittest.nc',
@@ -456,7 +458,6 @@
'containers/linked_list_unittest.cc',
'containers/mru_cache_unittest.cc',
'containers/scoped_ptr_hash_map_unittest.cc',
- 'containers/scoped_ptr_map_unittest.cc',
'containers/small_map_unittest.cc',
'containers/stack_container_unittest.cc',
'cpu_unittest.cc',
@@ -471,6 +472,7 @@
'feature_list_unittest.cc',
'file_version_info_unittest.cc',
'files/dir_reader_posix_unittest.cc',
+ 'files/file_locking_unittest.cc',
'files/file_path_unittest.cc',
'files/file_path_watcher_unittest.cc',
'files/file_proxy_unittest.cc',
@@ -525,6 +527,7 @@
'memory/memory_pressure_monitor_chromeos_unittest.cc',
'memory/memory_pressure_monitor_mac_unittest.cc',
'memory/memory_pressure_monitor_win_unittest.cc',
+ 'memory/ptr_util_unittest.cc',
'memory/ref_counted_memory_unittest.cc',
'memory/ref_counted_unittest.cc',
'memory/scoped_ptr_unittest.cc',
@@ -547,11 +550,12 @@
'metrics/histogram_macros_unittest.cc',
'metrics/histogram_snapshot_manager_unittest.cc',
'metrics/histogram_unittest.cc',
+ 'metrics/metrics_hashes_unittest.cc',
'metrics/sample_map_unittest.cc',
'metrics/sample_vector_unittest.cc',
'metrics/sparse_histogram_unittest.cc',
'metrics/statistics_recorder_unittest.cc',
- 'move_unittest.cc',
+ 'native_library_unittest.cc',
'numerics/safe_numerics_unittest.cc',
'observer_list_unittest.cc',
'os_compat_android_unittest.cc',
@@ -623,6 +627,7 @@
'threading/non_thread_safe_unittest.cc',
'threading/platform_thread_unittest.cc',
'threading/sequenced_worker_pool_unittest.cc',
+ 'threading/sequenced_task_runner_handle_unittest.cc',
'threading/simple_thread_unittest.cc',
'threading/thread_checker_unittest.cc',
'threading/thread_collision_warner_unittest.cc',
@@ -696,6 +701,8 @@
}],
['OS == "ios" and _toolset != "host"', {
'sources/': [
+ # This test needs multiple processes.
+ ['exclude', '^files/file_locking_unittest\\.cc$'],
# iOS does not support FilePathWatcher.
['exclude', '^files/file_path_watcher_unittest\\.cc$'],
# Only test the iOS-meaningful portion of memory and process_utils.
@@ -766,6 +773,9 @@
'sources': [
'profiler/win32_stack_frame_unwinder_unittest.cc',
],
+ 'dependencies': [
+ 'base_profiler_test_support_library',
+ ],
}],
['OS == "win"', {
'sources!': [
@@ -799,7 +809,7 @@
],
}, { # OS != "win"
'dependencies': [
- '../third_party/libevent/libevent.gyp:libevent'
+ 'third_party/libevent/libevent.gyp:libevent'
],
}],
], # conditions
@@ -1071,6 +1081,21 @@
}],
],
},
+ {
+ # GN version: //base/debug:debugging_flags
+ # Since this generates a file, it most only be referenced in the target
+ # toolchain or there will be multiple rules that generate the header.
+ # When referenced from a target that might be compiled in the host
+ # toolchain, always refer to 'base_debugging_flags#target'.
+ 'target_name': 'base_debugging_flags',
+ 'includes': [ '../build/buildflag_header.gypi' ],
+ 'variables': {
+ 'buildflag_header_path': 'base/debug/debugging_flags.h',
+ 'buildflag_flags': [
+ 'ENABLE_PROFILING=<(profiling)',
+ ],
+ },
+ },
],
'conditions': [
['OS=="ios" and "<(GENERATOR)"=="ninja"', {
@@ -1126,8 +1151,8 @@
'base_target': 1,
},
'dependencies': [
+ 'base_debugging_flags#target',
'base_static_win64',
- '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',
@@ -1271,6 +1296,21 @@
},
],
}],
+ ['OS == "win" and target_arch=="x64"', {
+ 'targets': [
+ {
+ 'target_name': 'base_profiler_test_support_library',
+ # Must be a shared library so that it can be unloaded during testing.
+ 'type': 'shared_library',
+ 'include_dirs': [
+ '..',
+ ],
+ 'sources': [
+ 'profiler/test_support_library.cc',
+ ],
+ },
+ ]
+ }],
['os_posix==1 and OS!="mac" and OS!="ios"', {
'targets': [
{
@@ -1375,6 +1415,7 @@
'android/java/src/org/chromium/base/BuildInfo.java',
'android/java/src/org/chromium/base/CommandLine.java',
'android/java/src/org/chromium/base/ContentUriUtils.java',
+ 'android/java/src/org/chromium/base/ContextUtils.java',
'android/java/src/org/chromium/base/CpuFeatures.java',
'android/java/src/org/chromium/base/EventLog.java',
'android/java/src/org/chromium/base/FieldTrialList.java',
@@ -1413,7 +1454,7 @@
'includes': [ '../build/jar_file_jni_generator.gypi' ],
},
{
- # TODO(GN)
+ # GN: //base:base_unittests_jni_headers
'target_name': 'base_unittests_jni_headers',
'type': 'none',
'sources': [
@@ -1439,6 +1480,19 @@
'includes': [ '../build/android/java_cpp_template.gypi' ],
},
{
+ # GN: //base:base_multidex_gen
+ 'target_name': 'base_multidex_gen',
+ 'type': 'none',
+ 'sources': [
+ 'android/java/templates/ChromiumMultiDex.template',
+ ],
+ 'variables': {
+ 'package_name': 'org/chromium/base/multidex',
+ 'template_deps': [],
+ },
+ 'includes': ['../build/android/java_cpp_template.gypi'],
+ },
+ {
# GN: //base:base_android_java_enums_srcjar
'target_name': 'base_java_library_process_type',
'type': 'none',
@@ -1453,17 +1507,26 @@
'type': 'none',
'variables': {
'java_in_dir': 'android/java',
- 'jar_excluded_classes': [ '*/NativeLibraries.class' ],
+ 'jar_excluded_classes': [
+ '*/ChromiumMultiDex.class',
+ '*/NativeLibraries.class',
+ ],
},
'dependencies': [
'base_java_application_state',
'base_java_library_load_from_apk_status_codes',
'base_java_library_process_type',
'base_java_memory_pressure_level',
+ 'base_multidex_gen',
'base_native_libraries_gen',
'../third_party/android_tools/android_tools.gyp:android_support_multidex_javalib',
'../third_party/jsr-305/jsr-305.gyp:jsr_305_javalib',
],
+ 'all_dependent_settings': {
+ 'variables': {
+ 'generate_multidex_config': 1,
+ },
+ },
'includes': [ '../build/java.gypi' ],
},
{
@@ -1525,12 +1588,13 @@
'target_name': 'base_junit_test_support',
'type': 'none',
'dependencies': [
+ 'base_multidex_gen',
'../testing/android/junit/junit_test.gyp:junit_test_support',
'../third_party/android_tools/android_tools.gyp:android_support_multidex_javalib',
],
'variables': {
'src_paths': [
- '../base/test/android/junit/',
+ '../base/test/android/junit/src/org/chromium/base/test/shadows/ShadowMultiDex.java',
],
},
'includes': [ '../build/host_jar.gypi' ]
@@ -1549,6 +1613,7 @@
'main_class': 'org.chromium.testing.local.JunitTestMain',
'src_paths': [
'../base/android/junit/',
+ '../base/test/android/junit/src/org/chromium/base/test/util/DisableIfTest.java',
],
},
'includes': [ '../build/host_jar.gypi' ],
@@ -1591,7 +1656,7 @@
],
},
{
- # TODO(GN)
+ # GN: //base:base_perftests_apk
'target_name': 'base_perftests_apk',
'type': 'none',
'dependencies': [
diff --git a/chromium/base/base.gypi b/chromium/base/base.gypi
index ffb96bb65ac..bb028bdf11a 100644
--- a/chromium/base/base.gypi
+++ b/chromium/base/base.gypi
@@ -16,6 +16,8 @@
['base_target==1', {
'sources': [
'../build/build_config.h',
+ 'allocator/allocator_check.cc',
+ 'allocator/allocator_check.h',
'allocator/allocator_extension.cc',
'allocator/allocator_extension.h',
'android/animation_frame_time_histogram.cc',
@@ -34,6 +36,8 @@
'android/command_line_android.h',
'android/content_uri_utils.cc',
'android/content_uri_utils.h',
+ 'android/context_utils.cc',
+ 'android/context_utils.h',
'android/cpu_features.cc',
'android/cxa_demangle_stub.cc',
'android/event_log.cc',
@@ -89,13 +93,14 @@
'atomic_ref_count.h',
'atomic_sequence_num.h',
'atomicops.h',
- 'atomicops_internals_mac.h',
'atomicops_internals_portable.h',
'atomicops_internals_x86_msvc.h',
'barrier_closure.cc',
'barrier_closure.h',
'base64.cc',
'base64.h',
+ 'base64url.cc',
+ 'base64url.h',
'base_export.h',
'base_paths.cc',
'base_paths.h',
@@ -108,7 +113,6 @@
'base_paths_win.cc',
'base_paths_win.h',
'base_switches.h',
- 'basictypes.h',
'big_endian.cc',
'big_endian.h',
'bind.h',
@@ -116,6 +120,7 @@
'bind_helpers.h',
'bind_internal.h',
'bind_internal_win.h',
+ 'bit_cast.h',
'bits.h',
'build_time.cc',
'build_time.h',
@@ -134,7 +139,6 @@
'containers/linked_list.h',
'containers/mru_cache.h',
'containers/scoped_ptr_hash_map.h',
- 'containers/scoped_ptr_map.h',
'containers/small_map.h',
'containers/stack_container.h',
'cpu.cc',
@@ -145,6 +149,8 @@
'debug/alias.h',
'debug/asan_invalid_access.cc',
'debug/asan_invalid_access.h',
+ 'debug/close_handle_hook_win.cc',
+ 'debug/close_handle_hook_win.h',
'debug/crash_logging.cc',
'debug/crash_logging.h',
'debug/debugger.cc',
@@ -348,6 +354,7 @@
'memory/memory_pressure_monitor_mac.h',
'memory/memory_pressure_monitor_win.cc',
'memory/memory_pressure_monitor_win.h',
+ 'memory/ptr_util.h',
'memory/raw_scoped_refptr_mismatch_checker.h',
'memory/ref_counted.cc',
'memory/ref_counted.h',
@@ -399,6 +406,8 @@
'metrics/histogram_samples.h',
'metrics/histogram_snapshot_manager.cc',
'metrics/histogram_snapshot_manager.h',
+ 'metrics/metrics_hashes.cc',
+ 'metrics/metrics_hashes.h',
'metrics/sample_map.cc',
'metrics/sample_map.h',
'metrics/sample_vector.cc',
@@ -475,8 +484,10 @@
'process/memory_linux.cc',
'process/memory_mac.mm',
'process/memory_win.cc',
+ 'process/port_provider_mac.cc',
'process/port_provider_mac.h',
'process/process.h',
+ 'process/process_handle.cc',
'process/process_handle_freebsd.cc',
'process/process_handle_linux.cc',
'process/process_handle_mac.cc',
@@ -501,6 +512,7 @@
'process/process_metrics_ios.cc',
'process/process_metrics_linux.cc',
'process/process_metrics_mac.cc',
+ 'process/process_metrics_nacl.cc',
'process/process_metrics_openbsd.cc',
'process/process_metrics_posix.cc',
'process/process_metrics_win.cc',
@@ -641,6 +653,8 @@
'threading/platform_thread_win.cc',
'threading/post_task_and_reply_impl.cc',
'threading/post_task_and_reply_impl.h',
+ 'threading/sequenced_task_runner_handle.cc',
+ 'threading/sequenced_task_runner_handle.h',
'threading/sequenced_worker_pool.cc',
'threading/sequenced_worker_pool.h',
'threading/simple_thread.cc',
@@ -721,10 +735,10 @@
'win/iunknown_impl.h',
'win/message_window.cc',
'win/message_window.h',
- 'win/metro.cc',
- 'win/metro.h',
'win/object_watcher.cc',
'win/object_watcher.h',
+ 'win/process_startup_helper.cc',
+ 'win/process_startup_helper.h',
'win/registry.cc',
'win/registry.h',
'win/resource_util.cc',
@@ -856,9 +870,6 @@
],
}],
['OS == "android" and _toolset == "host" and host_os == "linux"', {
- 'defines': [
- 'OS_ANDROID_HOST=Linux',
- ],
'sources/': [
# Pull in specific files for host builds.
['include', '^threading/platform_thread_linux\\.cc$'],
@@ -873,7 +884,6 @@
'sources/': [
# Pull in specific Mac files for iOS (which have been filtered out
# by file name rules).
- ['include', '^atomicops_internals_mac\\.'],
['include', '^base_paths_mac\\.'],
['include', '^files/file_util_mac\\.'],
['include', '^file_version_info_mac\\.'],
@@ -1009,6 +1019,8 @@
],
'sources': [
'i18n/base_i18n_export.h',
+ 'i18n/base_i18n_switches.cc',
+ 'i18n/base_i18n_switches.h',
'i18n/bidi_line_iterator.cc',
'i18n/bidi_line_iterator.h',
'i18n/break_iterator.cc',
diff --git a/chromium/base/base64.cc b/chromium/base/base64.cc
index 8ed1249257d..ca8ee939079 100644
--- a/chromium/base/base64.cc
+++ b/chromium/base/base64.cc
@@ -4,6 +4,8 @@
#include "base/base64.h"
+#include <stddef.h>
+
#include "third_party/modp_b64/modp_b64.h"
namespace base {
diff --git a/chromium/base/base64url.cc b/chromium/base/base64url.cc
new file mode 100644
index 00000000000..0a2c04511fe
--- /dev/null
+++ b/chromium/base/base64url.cc
@@ -0,0 +1,101 @@
+// 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/base64url.h"
+
+#include <stddef.h>
+
+#include "base/base64.h"
+#include "base/macros.h"
+#include "base/numerics/safe_math.h"
+#include "base/strings/string_util.h"
+#include "third_party/modp_b64/modp_b64.h"
+
+namespace base {
+
+const char kPaddingChar = '=';
+
+// Base64url maps {+, /} to {-, _} in order for the encoded content to be safe
+// to use in a URL. These characters will be translated by this implementation.
+const char kBase64Chars[] = "+/";
+const char kBase64UrlSafeChars[] = "-_";
+
+void Base64UrlEncode(const StringPiece& input,
+ Base64UrlEncodePolicy policy,
+ std::string* output) {
+ Base64Encode(input, output);
+
+ ReplaceChars(*output, "+", "-", output);
+ ReplaceChars(*output, "/", "_", output);
+
+ switch (policy) {
+ case Base64UrlEncodePolicy::INCLUDE_PADDING:
+ // The padding included in |*output| will not be amended.
+ break;
+ case Base64UrlEncodePolicy::OMIT_PADDING:
+ // The padding included in |*output| will be removed.
+ const size_t last_non_padding_pos =
+ output->find_last_not_of(kPaddingChar);
+ if (last_non_padding_pos != std::string::npos)
+ output->resize(last_non_padding_pos + 1);
+
+ break;
+ }
+}
+
+bool Base64UrlDecode(const StringPiece& input,
+ Base64UrlDecodePolicy policy,
+ std::string* output) {
+ // Characters outside of the base64url alphabet are disallowed, which includes
+ // the {+, /} characters found in the conventional base64 alphabet.
+ if (input.find_first_of(kBase64Chars) != std::string::npos)
+ return false;
+
+ const size_t required_padding_characters = input.size() % 4;
+ const bool needs_replacement =
+ input.find_first_of(kBase64UrlSafeChars) != std::string::npos;
+
+ switch (policy) {
+ case Base64UrlDecodePolicy::REQUIRE_PADDING:
+ // Fail if the required padding is not included in |input|.
+ if (required_padding_characters > 0)
+ return false;
+ break;
+ case Base64UrlDecodePolicy::IGNORE_PADDING:
+ // Missing padding will be silently appended.
+ break;
+ case Base64UrlDecodePolicy::DISALLOW_PADDING:
+ // Fail if padding characters are included in |input|.
+ if (input.find_first_of(kPaddingChar) != std::string::npos)
+ return false;
+ break;
+ }
+
+ // If the string either needs replacement of URL-safe characters to normal
+ // base64 ones, or additional padding, a copy of |input| needs to be made in
+ // order to make these adjustments without side effects.
+ if (required_padding_characters > 0 || needs_replacement) {
+ std::string base64_input;
+
+ CheckedNumeric<size_t> base64_input_size = input.size();
+ if (required_padding_characters > 0)
+ base64_input_size += 4 - required_padding_characters;
+
+ base64_input.reserve(base64_input_size.ValueOrDie());
+ input.AppendToString(&base64_input);
+
+ // Substitute the base64url URL-safe characters to their base64 equivalents.
+ ReplaceChars(base64_input, "-", "+", &base64_input);
+ ReplaceChars(base64_input, "_", "/", &base64_input);
+
+ // Append the necessary padding characters.
+ base64_input.resize(base64_input_size.ValueOrDie(), '=');
+
+ return Base64Decode(base64_input, output);
+ }
+
+ return Base64Decode(input, output);
+}
+
+} // namespace base
diff --git a/chromium/base/base64url.h b/chromium/base/base64url.h
new file mode 100644
index 00000000000..66a482461b1
--- /dev/null
+++ b/chromium/base/base64url.h
@@ -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.
+
+#ifndef BASE_BASE64URL_H_
+#define BASE_BASE64URL_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+
+namespace base {
+
+enum class Base64UrlEncodePolicy {
+ // Include the trailing padding in the output, when necessary.
+ INCLUDE_PADDING,
+
+ // Remove the trailing padding from the output.
+ OMIT_PADDING
+};
+
+// Encodes the |input| string in base64url, defined in RFC 4648:
+// https://tools.ietf.org/html/rfc4648#section-5
+//
+// The |policy| defines whether padding should be included or omitted from the
+// encoded |*output|. |input| and |*output| may reference the same storage.
+BASE_EXPORT void Base64UrlEncode(const StringPiece& input,
+ Base64UrlEncodePolicy policy,
+ std::string* output);
+
+enum class Base64UrlDecodePolicy {
+ // Require inputs contain trailing padding if non-aligned.
+ REQUIRE_PADDING,
+
+ // Accept inputs regardless of whether or not they have the correct padding.
+ IGNORE_PADDING,
+
+ // Reject inputs if they contain any trailing padding.
+ DISALLOW_PADDING
+};
+
+// Decodes the |input| string in base64url, defined in RFC 4648:
+// https://tools.ietf.org/html/rfc4648#section-5
+//
+// The |policy| defines whether padding will be required, ignored or disallowed
+// altogether. |input| and |*output| may reference the same storage.
+BASE_EXPORT bool Base64UrlDecode(const StringPiece& input,
+ Base64UrlDecodePolicy policy,
+ std::string* output) WARN_UNUSED_RESULT;
+
+} // namespace base
+
+#endif // BASE_BASE64URL_H_
diff --git a/chromium/base/base64url_unittest.cc b/chromium/base/base64url_unittest.cc
new file mode 100644
index 00000000000..45aa4a8c5ef
--- /dev/null
+++ b/chromium/base/base64url_unittest.cc
@@ -0,0 +1,115 @@
+// 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/base64url.h"
+
+#include "base/macros.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+TEST(Base64UrlTest, EncodeIncludePaddingPolicy) {
+ std::string output;
+ Base64UrlEncode("hello?world", Base64UrlEncodePolicy::INCLUDE_PADDING,
+ &output);
+
+ // Base64 version: aGVsbG8/d29ybGQ=
+ EXPECT_EQ("aGVsbG8_d29ybGQ=", output);
+
+ // Test for behavior for very short and empty strings.
+ Base64UrlEncode("??", Base64UrlEncodePolicy::INCLUDE_PADDING, &output);
+ EXPECT_EQ("Pz8=", output);
+
+ Base64UrlEncode("", Base64UrlEncodePolicy::INCLUDE_PADDING, &output);
+ EXPECT_EQ("", output);
+}
+
+TEST(Base64UrlTest, EncodeOmitPaddingPolicy) {
+ std::string output;
+ Base64UrlEncode("hello?world", Base64UrlEncodePolicy::OMIT_PADDING, &output);
+
+ // base64 version: aGVsbG8/d29ybGQ=
+ EXPECT_EQ("aGVsbG8_d29ybGQ", output);
+
+ // Test for behavior for very short and empty strings.
+ Base64UrlEncode("??", Base64UrlEncodePolicy::OMIT_PADDING, &output);
+ EXPECT_EQ("Pz8", output);
+
+ Base64UrlEncode("", Base64UrlEncodePolicy::OMIT_PADDING, &output);
+ EXPECT_EQ("", output);
+}
+
+TEST(Base64UrlTest, DecodeRequirePaddingPolicy) {
+ std::string output;
+ ASSERT_TRUE(Base64UrlDecode("aGVsbG8_d29ybGQ=",
+ Base64UrlDecodePolicy::REQUIRE_PADDING, &output));
+
+ EXPECT_EQ("hello?world", output);
+
+ ASSERT_FALSE(Base64UrlDecode(
+ "aGVsbG8_d29ybGQ", Base64UrlDecodePolicy::REQUIRE_PADDING, &output));
+
+ // Test for behavior for very short and empty strings.
+ ASSERT_TRUE(
+ Base64UrlDecode("Pz8=", Base64UrlDecodePolicy::REQUIRE_PADDING, &output));
+ EXPECT_EQ("??", output);
+
+ ASSERT_TRUE(
+ Base64UrlDecode("", Base64UrlDecodePolicy::REQUIRE_PADDING, &output));
+ EXPECT_EQ("", output);
+}
+
+TEST(Base64UrlTest, DecodeIgnorePaddingPolicy) {
+ std::string output;
+ ASSERT_TRUE(Base64UrlDecode("aGVsbG8_d29ybGQ",
+ Base64UrlDecodePolicy::IGNORE_PADDING, &output));
+
+ EXPECT_EQ("hello?world", output);
+
+ // Including the padding is accepted as well.
+ ASSERT_TRUE(Base64UrlDecode("aGVsbG8_d29ybGQ=",
+ Base64UrlDecodePolicy::IGNORE_PADDING, &output));
+
+ EXPECT_EQ("hello?world", output);
+}
+
+TEST(Base64UrlTest, DecodeDisallowPaddingPolicy) {
+ std::string output;
+ ASSERT_FALSE(Base64UrlDecode(
+ "aGVsbG8_d29ybGQ=", Base64UrlDecodePolicy::DISALLOW_PADDING, &output));
+
+ // The policy will allow the input when padding has been omitted.
+ ASSERT_TRUE(Base64UrlDecode(
+ "aGVsbG8_d29ybGQ", Base64UrlDecodePolicy::DISALLOW_PADDING, &output));
+
+ EXPECT_EQ("hello?world", output);
+}
+
+TEST(Base64UrlTest, DecodeDisallowsBase64Alphabet) {
+ std::string output;
+
+ // The "/" character is part of the conventional base64 alphabet, but has been
+ // substituted with "_" in the base64url alphabet.
+ ASSERT_FALSE(Base64UrlDecode(
+ "aGVsbG8/d29ybGQ=", Base64UrlDecodePolicy::REQUIRE_PADDING, &output));
+}
+
+TEST(Base64UrlTest, DecodeDisallowsPaddingOnly) {
+ std::string output;
+
+ ASSERT_FALSE(Base64UrlDecode(
+ "=", Base64UrlDecodePolicy::IGNORE_PADDING, &output));
+ ASSERT_FALSE(Base64UrlDecode(
+ "==", Base64UrlDecodePolicy::IGNORE_PADDING, &output));
+ ASSERT_FALSE(Base64UrlDecode(
+ "===", Base64UrlDecodePolicy::IGNORE_PADDING, &output));
+ ASSERT_FALSE(Base64UrlDecode(
+ "====", Base64UrlDecodePolicy::IGNORE_PADDING, &output));
+}
+
+} // namespace
+
+} // namespace base
diff --git a/chromium/base/base_export.h b/chromium/base/base_export.h
index 723b38a60fd..cf7ebd78162 100644
--- a/chromium/base/base_export.h
+++ b/chromium/base/base_export.h
@@ -10,25 +10,20 @@
#if defined(BASE_IMPLEMENTATION)
#define BASE_EXPORT __declspec(dllexport)
-#define BASE_EXPORT_PRIVATE __declspec(dllexport)
#else
#define BASE_EXPORT __declspec(dllimport)
-#define BASE_EXPORT_PRIVATE __declspec(dllimport)
#endif // defined(BASE_IMPLEMENTATION)
#else // defined(WIN32)
#if defined(BASE_IMPLEMENTATION)
#define BASE_EXPORT __attribute__((visibility("default")))
-#define BASE_EXPORT_PRIVATE __attribute__((visibility("default")))
#else
#define BASE_EXPORT
-#define BASE_EXPORT_PRIVATE
#endif // defined(BASE_IMPLEMENTATION)
#endif
#else // defined(COMPONENT_BUILD)
#define BASE_EXPORT
-#define BASE_EXPORT_PRIVATE
#endif
#endif // BASE_BASE_EXPORT_H_
diff --git a/chromium/base/base_nacl.gyp b/chromium/base/base_nacl.gyp
index b2b4b7f76ea..675cbd6ebc4 100644
--- a/chromium/base/base_nacl.gyp
+++ b/chromium/base/base_nacl.gyp
@@ -39,6 +39,9 @@
'-fno-strict-aliasing',
],
},
+ 'dependencies': [
+ 'base.gyp:base_debugging_flags',
+ ],
},
{
'target_name': 'base_i18n_nacl',
@@ -114,7 +117,8 @@
'rand_util_nacl.cc',
],
'dependencies': [
- '../third_party/libevent/libevent_nacl_nonsfi.gyp:event_nacl_nonsfi',
+ 'base.gyp:base_debugging_flags',
+ 'third_party/libevent/libevent_nacl_nonsfi.gyp:event_nacl_nonsfi',
],
},
{
diff --git a/chromium/base/base_paths.cc b/chromium/base/base_paths.cc
index 7076ec3be15..31bc55401af 100644
--- a/chromium/base/base_paths.cc
+++ b/chromium/base/base_paths.cc
@@ -29,15 +29,18 @@ bool PathProvider(int key, FilePath* result) {
case base::DIR_HOME:
*result = GetHomeDir();
return true;
- case DIR_TEST_DATA:
- if (!PathService::Get(DIR_SOURCE_ROOT, result))
+ case DIR_TEST_DATA: {
+ FilePath test_data_path;
+ if (!PathService::Get(DIR_SOURCE_ROOT, &test_data_path))
return false;
- *result = result->Append(FILE_PATH_LITERAL("base"));
- *result = result->Append(FILE_PATH_LITERAL("test"));
- *result = result->Append(FILE_PATH_LITERAL("data"));
- if (!PathExists(*result)) // We don't want to create this.
+ test_data_path = test_data_path.Append(FILE_PATH_LITERAL("base"));
+ test_data_path = test_data_path.Append(FILE_PATH_LITERAL("test"));
+ test_data_path = test_data_path.Append(FILE_PATH_LITERAL("data"));
+ if (!PathExists(test_data_path)) // We don't want to create this.
return false;
+ *result = test_data_path;
return true;
+ }
default:
return false;
}
diff --git a/chromium/base/base_paths_android.cc b/chromium/base/base_paths_android.cc
index 56c6cc70f47..ca58179b678 100644
--- a/chromium/base/base_paths_android.cc
+++ b/chromium/base/base_paths_android.cc
@@ -5,6 +5,7 @@
// Defines base::PathProviderAndroid which replaces base::PathProviderPosix for
// Android in base/path_service.cc.
+#include <limits.h>
#include <unistd.h>
#include "base/android/jni_android.h"
diff --git a/chromium/base/base_paths_mac.mm b/chromium/base/base_paths_mac.mm
index af4bd1a89e3..839df0d7cc9 100644
--- a/chromium/base/base_paths_mac.mm
+++ b/chromium/base/base_paths_mac.mm
@@ -8,6 +8,7 @@
#include <dlfcn.h>
#import <Foundation/Foundation.h>
#include <mach-o/dyld.h>
+#include <stdint.h>
#include "base/base_paths.h"
#include "base/compiler_specific.h"
diff --git a/chromium/base/base_paths_posix.cc b/chromium/base/base_paths_posix.cc
index 048434f0ef7..a436a4dcfcc 100644
--- a/chromium/base/base_paths_posix.cc
+++ b/chromium/base/base_paths_posix.cc
@@ -6,6 +6,9 @@
// don't have their own base_paths_OS.cc implementation (i.e. all but Mac and
// Android).
+#include <limits.h>
+#include <stddef.h>
+
#include <ostream>
#include <string>
diff --git a/chromium/base/base_paths_win.h b/chromium/base/base_paths_win.h
index 454d67b7703..d9dbc39f99a 100644
--- a/chromium/base/base_paths_win.h
+++ b/chromium/base/base_paths_win.h
@@ -43,7 +43,7 @@ enum {
// on all user's Desktop).
DIR_USER_QUICK_LAUNCH, // Directory for the quick launch shortcuts.
DIR_TASKBAR_PINS, // Directory for the shortcuts pinned to taskbar
- // (Win7+) via base::win::PinShortcutToTaskbar().
+ // (Win7-8) via base::win::PinShortcutToTaskbar().
DIR_WINDOWS_FONTS, // Usually C:\Windows\Fonts.
PATH_WIN_END
diff --git a/chromium/base/base_switches.cc b/chromium/base/base_switches.cc
index 76827b850a1..02b22298850 100644
--- a/chromium/base/base_switches.cc
+++ b/chromium/base/base_switches.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "base/base_switches.h"
+#include "build/build_config.h"
namespace switches {
@@ -14,6 +15,11 @@ const char kDisableBreakpad[] = "disable-breakpad";
// generated internally.
const char kEnableCrashReporter[] = "enable-crash-reporter";
+// Makes memory allocators keep track of their allocations and context, so a
+// detailed breakdown of memory usage can be presented in chrome://tracing when
+// the memory-infra category is enabled.
+const char kEnableHeapProfiling[] = "enable-heap-profiling";
+
// Generates full memory crash dump.
const char kFullMemoryCrashReport[] = "full-memory-crash-report";
@@ -58,9 +64,6 @@ const char kVModule[] = "vmodule";
// Will wait for 60 seconds for a debugger to come to attach to the process.
const char kWaitForDebugger[] = "wait-for-debugger";
-// Sends a pretty-printed version of tracing info to the console.
-const char kTraceToConsole[] = "trace-to-console";
-
// Sends trace events from these categories to a file.
// --trace-to-file on its own sends to default categories.
const char kTraceToFile[] = "trace-to-file";
diff --git a/chromium/base/base_switches.h b/chromium/base/base_switches.h
index 95f6bffb23d..c97a629d9fb 100644
--- a/chromium/base/base_switches.h
+++ b/chromium/base/base_switches.h
@@ -12,16 +12,16 @@
namespace switches {
extern const char kDisableBreakpad[];
+extern const char kDisableLowEndDeviceMode[];
extern const char kEnableCrashReporter[];
+extern const char kEnableHeapProfiling[];
+extern const char kEnableLowEndDeviceMode[];
extern const char kForceFieldTrials[];
extern const char kFullMemoryCrashReport[];
-extern const char kEnableLowEndDeviceMode[];
-extern const char kDisableLowEndDeviceMode[];
extern const char kNoErrorDialogs[];
extern const char kProfilerTiming[];
extern const char kProfilerTimingDisabledValue[];
extern const char kTestChildProcess[];
-extern const char kTraceToConsole[];
extern const char kTraceToFile[];
extern const char kTraceToFileName[];
extern const char kV[];
diff --git a/chromium/base/basictypes.h b/chromium/base/basictypes.h
deleted file mode 100644
index e167466ffe2..00000000000
--- a/chromium/base/basictypes.h
+++ /dev/null
@@ -1,46 +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.
-
-// This file contains definitions of our old basic integral types
-// ((u)int{8,16,32,64}) and further includes. I recommend that you use the C99
-// standard types instead, and include <stdint.h>/<stddef.h>/etc. as needed.
-// Note that the macros and macro-like constructs that were formerly defined in
-// this file are now available separately in base/macros.h.
-
-#ifndef BASE_BASICTYPES_H_
-#define BASE_BASICTYPES_H_
-
-#include <limits.h> // So we can set the bounds of our types.
-#include <stddef.h> // For size_t.
-#include <stdint.h> // For intptr_t.
-
-#include "base/macros.h"
-#include "build/build_config.h"
-
-// DEPRECATED: Please use (u)int{8,16,32,64}_t instead (and include <stdint.h>).
-typedef int8_t int8;
-typedef uint8_t uint8;
-typedef int16_t int16;
-typedef uint16_t uint16;
-typedef int32_t int32;
-typedef uint32_t uint32;
-typedef int64_t int64;
-typedef uint64_t uint64;
-
-// DEPRECATED: Please use std::numeric_limits (from <limits>) or
-// (U)INT{8,16,32,64}_{MIN,MAX} in case of globals (and include <stdint.h>).
-const uint8 kuint8max = 0xFF;
-const uint16 kuint16max = 0xFFFF;
-const uint32 kuint32max = 0xFFFFFFFF;
-const uint64 kuint64max = 0xFFFFFFFFFFFFFFFFULL;
-const int8 kint8min = -0x7F - 1;
-const int8 kint8max = 0x7F;
-const int16 kint16min = -0x7FFF - 1;
-const int16 kint16max = 0x7FFF;
-const int32 kint32min = -0x7FFFFFFF - 1;
-const int32 kint32max = 0x7FFFFFFF;
-const int64 kint64min = -0x7FFFFFFFFFFFFFFFLL - 1;
-const int64 kint64max = 0x7FFFFFFFFFFFFFFFLL;
-
-#endif // BASE_BASICTYPES_H_
diff --git a/chromium/base/big_endian.cc b/chromium/base/big_endian.cc
index 9b69147a316..514581fe415 100644
--- a/chromium/base/big_endian.cc
+++ b/chromium/base/big_endian.cc
@@ -43,19 +43,19 @@ bool BigEndianReader::Read(T* value) {
return true;
}
-bool BigEndianReader::ReadU8(uint8* value) {
+bool BigEndianReader::ReadU8(uint8_t* value) {
return Read(value);
}
-bool BigEndianReader::ReadU16(uint16* value) {
+bool BigEndianReader::ReadU16(uint16_t* value) {
return Read(value);
}
-bool BigEndianReader::ReadU32(uint32* value) {
+bool BigEndianReader::ReadU32(uint32_t* value) {
return Read(value);
}
-bool BigEndianReader::ReadU64(uint64* value) {
+bool BigEndianReader::ReadU64(uint64_t* value) {
return Read(value);
}
@@ -86,19 +86,19 @@ bool BigEndianWriter::Write(T value) {
return true;
}
-bool BigEndianWriter::WriteU8(uint8 value) {
+bool BigEndianWriter::WriteU8(uint8_t value) {
return Write(value);
}
-bool BigEndianWriter::WriteU16(uint16 value) {
+bool BigEndianWriter::WriteU16(uint16_t value) {
return Write(value);
}
-bool BigEndianWriter::WriteU32(uint32 value) {
+bool BigEndianWriter::WriteU32(uint32_t value) {
return Write(value);
}
-bool BigEndianWriter::WriteU64(uint64 value) {
+bool BigEndianWriter::WriteU64(uint64_t value) {
return Write(value);
}
diff --git a/chromium/base/big_endian.h b/chromium/base/big_endian.h
index 914767f4286..b1466e2b6b7 100644
--- a/chromium/base/big_endian.h
+++ b/chromium/base/big_endian.h
@@ -5,8 +5,10 @@
#ifndef BASE_BIG_ENDIAN_H_
#define BASE_BIG_ENDIAN_H_
+#include <stddef.h>
+#include <stdint.h>
+
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/strings/string_piece.h"
namespace base {
@@ -21,8 +23,8 @@ inline void ReadBigEndian(const char buf[], T* out) {
*out = buf[0];
for (size_t i = 1; i < sizeof(T); ++i) {
*out <<= 8;
- // Must cast to uint8 to avoid clobbering by sign extension.
- *out |= static_cast<uint8>(buf[i]);
+ // Must cast to uint8_t to avoid clobbering by sign extension.
+ *out |= static_cast<uint8_t>(buf[i]);
}
}
@@ -37,13 +39,13 @@ inline void WriteBigEndian(char buf[], T val) {
}
// Specializations to make clang happy about the (dead code) shifts above.
-template<>
-inline void ReadBigEndian<uint8>(const char buf[], uint8* out) {
+template <>
+inline void ReadBigEndian<uint8_t>(const char buf[], uint8_t* out) {
*out = buf[0];
}
-template<>
-inline void WriteBigEndian<uint8>(char buf[], uint8 val) {
+template <>
+inline void WriteBigEndian<uint8_t>(char buf[], uint8_t val) {
buf[0] = static_cast<char>(val);
}
@@ -60,10 +62,10 @@ class BASE_EXPORT BigEndianReader {
bool ReadBytes(void* out, size_t len);
// Creates a StringPiece in |out| that points to the underlying buffer.
bool ReadPiece(base::StringPiece* out, size_t len);
- bool ReadU8(uint8* value);
- bool ReadU16(uint16* value);
- bool ReadU32(uint32* value);
- bool ReadU64(uint64* value);
+ bool ReadU8(uint8_t* value);
+ bool ReadU16(uint16_t* value);
+ bool ReadU32(uint32_t* value);
+ bool ReadU64(uint64_t* value);
private:
// Hidden to promote type safety.
@@ -85,10 +87,10 @@ class BASE_EXPORT BigEndianWriter {
bool Skip(size_t len);
bool WriteBytes(const void* buf, size_t len);
- bool WriteU8(uint8 value);
- bool WriteU16(uint16 value);
- bool WriteU32(uint32 value);
- bool WriteU64(uint64 value);
+ bool WriteU8(uint8_t value);
+ bool WriteU16(uint16_t value);
+ bool WriteU32(uint32_t value);
+ bool WriteU64(uint64_t value);
private:
// Hidden to promote type safety.
diff --git a/chromium/base/big_endian_unittest.cc b/chromium/base/big_endian_unittest.cc
index 0e4b3f1812b..4e1e7cea307 100644
--- a/chromium/base/big_endian_unittest.cc
+++ b/chromium/base/big_endian_unittest.cc
@@ -4,6 +4,8 @@
#include "base/big_endian.h"
+#include <stdint.h>
+
#include "base/strings/string_piece.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -13,10 +15,10 @@ TEST(BigEndianReaderTest, ReadsValues) {
char data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF,
0x1A, 0x2B, 0x3C, 0x4D, 0x5E };
char buf[2];
- uint8 u8;
- uint16 u16;
- uint32 u32;
- uint64 u64;
+ uint8_t u8;
+ uint16_t u16;
+ uint32_t u32;
+ uint64_t u64;
base::StringPiece piece;
BigEndianReader reader(data, sizeof(data));
@@ -43,10 +45,10 @@ TEST(BigEndianReaderTest, ReadsValues) {
TEST(BigEndianReaderTest, RespectsLength) {
char data[8];
char buf[2];
- uint8 u8;
- uint16 u16;
- uint32 u32;
- uint64 u64;
+ uint8_t u8;
+ uint16_t u16;
+ uint32_t u32;
+ uint64_t u64;
base::StringPiece piece;
BigEndianReader reader(data, sizeof(data));
// 8 left
@@ -88,10 +90,10 @@ TEST(BigEndianWriterTest, WritesValues) {
TEST(BigEndianWriterTest, RespectsLength) {
char data[8];
char buf[2];
- uint8 u8 = 0;
- uint16 u16 = 0;
- uint32 u32 = 0;
- uint64 u64 = 0;
+ uint8_t u8 = 0;
+ uint16_t u16 = 0;
+ uint32_t u32 = 0;
+ uint64_t u64 = 0;
BigEndianWriter writer(data, sizeof(data));
// 8 left
EXPECT_FALSE(writer.Skip(9));
diff --git a/chromium/base/bind.h b/chromium/base/bind.h
index 51be10dd7e6..770e45706b0 100644
--- a/chromium/base/bind.h
+++ b/chromium/base/bind.h
@@ -47,49 +47,34 @@
namespace base {
-template <typename Functor>
-base::Callback<
- typename internal::BindState<
- typename internal::FunctorTraits<Functor>::RunnableType,
- typename internal::FunctorTraits<Functor>::RunType,
- 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,
- internal::TypeList<>> BindState;
-
- return Callback<typename BindState::UnboundRunType>(
- new BindState(internal::MakeRunnable(functor)));
-}
-
template <typename Functor, typename... Args>
base::Callback<
typename internal::BindState<
typename internal::FunctorTraits<Functor>::RunnableType,
typename internal::FunctorTraits<Functor>::RunType,
- internal::TypeList<
- typename internal::CallbackParamTraits<Args>::StorageType...>>
+ typename internal::CallbackParamTraits<Args>::StorageType...>
::UnboundRunType>
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;
+ // Type aliases for how to store and run the functor.
+ using RunnableType = typename internal::FunctorTraits<Functor>::RunnableType;
+ using RunType = typename internal::FunctorTraits<Functor>::RunType;
// Use RunnableType::RunType instead of RunType above because our
- // checks should below for bound references need to know what the actual
+ // checks below for bound references need to know what the actual
// functor is going to interpret the argument as.
- typedef typename RunnableType::RunType BoundRunType;
+ using BoundRunType = typename RunnableType::RunType;
+
+ using BoundArgs =
+ internal::TakeTypeListItem<sizeof...(Args),
+ internal::ExtractArgs<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.
- static_assert(!internal::HasNonConstReferenceParam<BoundRunType>::value,
- "do_not_bind_functions_with_nonconst_ref");
+ static_assert(!internal::HasNonConstReferenceItem<BoundArgs>::value,
+ "do not bind functions with nonconst ref");
const bool is_method = internal::HasIsMethodTag<RunnableType>::value;
@@ -98,16 +83,14 @@ Bind(Functor functor, const Args&... args) {
// methods. We also disallow binding of an array as the method's target
// object.
static_assert(!internal::BindsArrayToFirstArg<is_method, Args...>::value,
- "first_bound_argument_to_method_cannot_be_array");
+ "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");
+ "a parameter is a refcounted type and needs scoped_refptr");
- typedef internal::BindState<
+ using BindState = internal::BindState<
RunnableType, RunType,
- internal::TypeList<
- typename internal::CallbackParamTraits<Args>::StorageType...>>
- BindState;
+ typename internal::CallbackParamTraits<Args>::StorageType...>;
return Callback<typename BindState::UnboundRunType>(
new BindState(internal::MakeRunnable(functor), args...));
diff --git a/chromium/base/bind_helpers.h b/chromium/base/bind_helpers.h
index 24063ad1ce5..2add755b426 100644
--- a/chromium/base/bind_helpers.h
+++ b/chromium/base/bind_helpers.h
@@ -111,7 +111,7 @@
// scoped_ptr<Foo> f(new Foo());
//
// // |cb| is given ownership of Foo(). |f| is now NULL.
-// // You can use f.Pass() in place of &f, but it's more verbose.
+// // You can use std::move(f) in place of &f, but it's more verbose.
// Closure cb = Bind(&TakesOwnership, Passed(&f));
//
// // Run was never called so |cb| still owns Foo() and deletes
@@ -143,10 +143,15 @@
#ifndef BASE_BIND_HELPERS_H_
#define BASE_BIND_HELPERS_H_
-#include "base/basictypes.h"
+#include <stddef.h>
+
+#include <type_traits>
+#include <utility>
+
#include "base/callback.h"
#include "base/memory/weak_ptr.h"
#include "base/template_util.h"
+#include "build/build_config.h"
namespace base {
namespace internal {
@@ -185,7 +190,7 @@ namespace internal {
// want to probe for. Then we create a class Base that inherits from both T
// (the class we wish to probe) and BaseMixin. Note that the function
// signature in BaseMixin does not need to match the signature of the function
-// we are probing for; thus it's easiest to just use void(void).
+// we are probing for; thus it's easiest to just use void().
//
// Now, if TargetFunc exists somewhere in T, then &Base::TargetFunc has an
// ambiguous resolution between BaseMixin and T. This lets us write the
@@ -222,8 +227,8 @@ namespace internal {
// See http://crbug.com/82038.
template <typename T>
class SupportsAddRefAndRelease {
- typedef char Yes[1];
- typedef char No[2];
+ using Yes = char[1];
+ using No = char[2];
struct BaseMixin {
void AddRef();
@@ -242,7 +247,7 @@ class SupportsAddRefAndRelease {
#pragma warning(pop)
#endif
- template <void(BaseMixin::*)(void)> struct Helper {};
+ template <void(BaseMixin::*)()> struct Helper {};
template <typename C>
static No& Check(Helper<&C::AddRef>*);
@@ -276,8 +281,8 @@ struct UnsafeBindtoRefCountedArg<T*>
template <typename T>
class HasIsMethodTag {
- typedef char Yes[1];
- typedef char No[2];
+ using Yes = char[1];
+ using No = char[2];
template <typename U>
static Yes& Check(typename U::IsMethod*);
@@ -359,22 +364,24 @@ class OwnedWrapper {
// created when we are explicitly trying to do a destructive move.
//
// Two notes:
-// 1) PassedWrapper supports any type that has a "Pass()" function.
-// This is intentional. The whitelisting of which specific types we
-// support is maintained by CallbackParamTraits<>.
+// 1) PassedWrapper supports any type that has a move constructor, however
+// the type will need to be specifically whitelisted in order for it to be
+// bound to a Callback. We guard this explicitly at the call of Passed()
+// to make for clear errors. Things not given to Passed() will be forwarded
+// and stored by value which will not work for general move-only types.
// 2) is_valid_ is distinct from NULL because it is valid to bind a "NULL"
// scoper to a Callback and allow the Callback to execute once.
template <typename T>
class PassedWrapper {
public:
- explicit PassedWrapper(T scoper) : is_valid_(true), scoper_(scoper.Pass()) {}
+ explicit PassedWrapper(T&& scoper)
+ : is_valid_(true), scoper_(std::move(scoper)) {}
PassedWrapper(const PassedWrapper& other)
- : is_valid_(other.is_valid_), scoper_(other.scoper_.Pass()) {
- }
+ : is_valid_(other.is_valid_), scoper_(std::move(other.scoper_)) {}
T Pass() const {
CHECK(is_valid_);
is_valid_ = false;
- return scoper_.Pass();
+ return std::move(scoper_);
}
private:
@@ -385,13 +392,13 @@ class PassedWrapper {
// Unwrap the stored parameters for the wrappers above.
template <typename T>
struct UnwrapTraits {
- typedef const T& ForwardType;
+ using ForwardType = const T&;
static ForwardType Unwrap(const T& o) { return o; }
};
template <typename T>
struct UnwrapTraits<UnretainedWrapper<T> > {
- typedef T* ForwardType;
+ using ForwardType = T*;
static ForwardType Unwrap(UnretainedWrapper<T> unretained) {
return unretained.get();
}
@@ -399,7 +406,7 @@ struct UnwrapTraits<UnretainedWrapper<T> > {
template <typename T>
struct UnwrapTraits<ConstRefWrapper<T> > {
- typedef const T& ForwardType;
+ using ForwardType = const T&;
static ForwardType Unwrap(ConstRefWrapper<T> const_ref) {
return const_ref.get();
}
@@ -407,19 +414,19 @@ struct UnwrapTraits<ConstRefWrapper<T> > {
template <typename T>
struct UnwrapTraits<scoped_refptr<T> > {
- typedef T* ForwardType;
+ using ForwardType = T*;
static ForwardType Unwrap(const scoped_refptr<T>& o) { return o.get(); }
};
template <typename T>
struct UnwrapTraits<WeakPtr<T> > {
- typedef const WeakPtr<T>& ForwardType;
+ using ForwardType = const WeakPtr<T>&;
static ForwardType Unwrap(const WeakPtr<T>& o) { return o; }
};
template <typename T>
struct UnwrapTraits<OwnedWrapper<T> > {
- typedef T* ForwardType;
+ using ForwardType = T*;
static ForwardType Unwrap(const OwnedWrapper<T>& o) {
return o.get();
}
@@ -427,7 +434,7 @@ struct UnwrapTraits<OwnedWrapper<T> > {
template <typename T>
struct UnwrapTraits<PassedWrapper<T> > {
- typedef T ForwardType;
+ using ForwardType = T;
static T Unwrap(PassedWrapper<T>& o) {
return o.Pass();
}
@@ -510,25 +517,50 @@ struct DropTypeListItemImpl<n, TypeList<T, List...>>
template <typename T, typename... List>
struct DropTypeListItemImpl<0, TypeList<T, List...>> {
- typedef TypeList<T, List...> Type;
+ using Type = TypeList<T, List...>;
};
template <>
struct DropTypeListItemImpl<0, TypeList<>> {
- typedef TypeList<> Type;
+ using Type = TypeList<>;
};
// 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 TakeTypeListItem implementation.
+template <size_t n, typename List, typename... Accum>
+struct TakeTypeListItemImpl;
+
+// Do not use enable_if and SFINAE here to avoid MSVC2013 compile failure.
+template <size_t n, typename T, typename... List, typename... Accum>
+struct TakeTypeListItemImpl<n, TypeList<T, List...>, Accum...>
+ : TakeTypeListItemImpl<n - 1, TypeList<List...>, Accum..., T> {};
+
+template <typename T, typename... List, typename... Accum>
+struct TakeTypeListItemImpl<0, TypeList<T, List...>, Accum...> {
+ using Type = TypeList<Accum...>;
+};
+
+template <typename... Accum>
+struct TakeTypeListItemImpl<0, TypeList<>, Accum...> {
+ using Type = TypeList<Accum...>;
+};
+
+// A type-level function that takes first |n| list item from given TypeList.
+// E.g. TakeTypeListItem<3, TypeList<A, B, C, D>> is evaluated to
+// TypeList<A, B, C>.
+template <size_t n, typename List>
+using TakeTypeListItem = typename TakeTypeListItemImpl<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;
+ using Type = TypeList<Types1..., Types2...>;
};
// A type-level function that concats two TypeLists.
@@ -541,7 +573,9 @@ struct MakeFunctionTypeImpl;
template <typename R, typename... Args>
struct MakeFunctionTypeImpl<R, TypeList<Args...>> {
- typedef R(Type)(Args...);
+ // MSVC 2013 doesn't support Type Alias of function types.
+ // Revisit this after we update it to newer version.
+ typedef R Type(Args...);
};
// A type-level function that constructs a function type that has |R| as its
@@ -549,6 +583,20 @@ struct MakeFunctionTypeImpl<R, TypeList<Args...>> {
template <typename R, typename ArgList>
using MakeFunctionType = typename MakeFunctionTypeImpl<R, ArgList>::Type;
+// Used for ExtractArgs.
+template <typename Signature>
+struct ExtractArgsImpl;
+
+template <typename R, typename... Args>
+struct ExtractArgsImpl<R(Args...)> {
+ using Type = TypeList<Args...>;
+};
+
+// A type-level function that extracts function arguments into a TypeList.
+// E.g. ExtractArgs<R(A, B, C)> is evaluated to TypeList<A, B, C>.
+template <typename Signature>
+using ExtractArgs = typename ExtractArgsImpl<Signature>::Type;
+
} // namespace internal
template <typename T>
@@ -566,17 +614,25 @@ static inline internal::OwnedWrapper<T> Owned(T* o) {
return internal::OwnedWrapper<T>(o);
}
-// We offer 2 syntaxes for calling Passed(). The first takes a temporary and
-// is best suited for use with the return value of a function. The second
-// takes a pointer to the scoper and is just syntactic sugar to avoid having
-// to write Passed(scoper.Pass()).
-template <typename T>
-static inline internal::PassedWrapper<T> Passed(T scoper) {
- return internal::PassedWrapper<T>(scoper.Pass());
+// We offer 2 syntaxes for calling Passed(). The first takes an rvalue and
+// is best suited for use with the return value of a function or other temporary
+// rvalues. The second takes a pointer to the scoper and is just syntactic sugar
+// to avoid having to write Passed(std::move(scoper)).
+//
+// Both versions of Passed() prevent T from being an lvalue reference. The first
+// via use of enable_if, and the second takes a T* which will not bind to T&.
+template <typename T,
+ typename std::enable_if<internal::IsMoveOnlyType<T>::value &&
+ !std::is_lvalue_reference<T>::value>::type* =
+ nullptr>
+static inline internal::PassedWrapper<T> Passed(T&& scoper) {
+ return internal::PassedWrapper<T>(std::move(scoper));
}
-template <typename T>
+template <typename T,
+ typename std::enable_if<internal::IsMoveOnlyType<T>::value>::type* =
+ nullptr>
static inline internal::PassedWrapper<T> Passed(T* scoper) {
- return internal::PassedWrapper<T>(scoper->Pass());
+ return internal::PassedWrapper<T>(std::move(*scoper));
}
template <typename T>
diff --git a/chromium/base/bind_internal.h b/chromium/base/bind_internal.h
index e0532188622..ac7cd009878 100644
--- a/chromium/base/bind_internal.h
+++ b/chromium/base/bind_internal.h
@@ -5,6 +5,10 @@
#ifndef BASE_BIND_INTERNAL_H_
#define BASE_BIND_INTERNAL_H_
+#include <stddef.h>
+
+#include <type_traits>
+
#include "base/bind_helpers.h"
#include "base/callback_internal.h"
#include "base/memory/raw_scoped_refptr_mismatch_checker.h"
@@ -37,12 +41,7 @@ namespace internal {
// 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.
+// (Bound)Args -- A set of types that stores the arguments.
//
// Types:
// RunnableAdapter<> -- Wraps the various "function" pointer types into an
@@ -54,7 +53,6 @@ namespace internal {
// signature adapters are applied.
// 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
@@ -69,17 +67,17 @@ namespace internal {
// |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 {};
+template <typename List>
+struct HasNonConstReferenceItem : 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 {};
+template <typename T, typename... Args>
+struct HasNonConstReferenceItem<TypeList<T, Args...>>
+ : std::conditional<is_non_const_reference<T>::value,
+ true_type,
+ HasNonConstReferenceItem<TypeList<Args...>>>::type {};
// HasRefCountedTypeAsRawPtr selects true_type when any of the |Args| is a raw
// pointer to a RefCounted type.
@@ -93,9 +91,9 @@ struct HasRefCountedTypeAsRawPtr : false_type {};
// parameters recursively.
template <typename T, typename... Args>
struct HasRefCountedTypeAsRawPtr<T, Args...>
- : SelectType<NeedsScopedRefptrButGetsRawPtr<T>::value,
- true_type,
- HasRefCountedTypeAsRawPtr<Args...>>::Type {};
+ : std::conditional<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.
@@ -147,7 +145,9 @@ class RunnableAdapter;
template <typename R, typename... Args>
class RunnableAdapter<R(*)(Args...)> {
public:
- typedef R (RunType)(Args...);
+ // MSVC 2013 doesn't support Type Alias of function types.
+ // Revisit this after we update it to newer version.
+ typedef R RunType(Args...);
explicit RunnableAdapter(R(*function)(Args...))
: function_(function) {
@@ -165,8 +165,10 @@ class RunnableAdapter<R(*)(Args...)> {
template <typename R, typename T, typename... Args>
class RunnableAdapter<R(T::*)(Args...)> {
public:
- typedef R (RunType)(T*, Args...);
- typedef true_type IsMethod;
+ // MSVC 2013 doesn't support Type Alias of function types.
+ // Revisit this after we update it to newer version.
+ typedef R RunType(T*, Args...);
+ using IsMethod = true_type;
explicit RunnableAdapter(R(T::*method)(Args...))
: method_(method) {
@@ -184,8 +186,8 @@ class RunnableAdapter<R(T::*)(Args...)> {
template <typename R, typename T, typename... Args>
class RunnableAdapter<R(T::*)(Args...) const> {
public:
- typedef R (RunType)(const T*, Args...);
- typedef true_type IsMethod;
+ using RunType = R(const T*, Args...);
+ using IsMethod = true_type;
explicit RunnableAdapter(R(T::*method)(Args...) const)
: method_(method) {
@@ -209,7 +211,9 @@ struct ForceVoidReturn;
template <typename R, typename... Args>
struct ForceVoidReturn<R(Args...)> {
- typedef void(RunType)(Args...);
+ // MSVC 2013 doesn't support Type Alias of function types.
+ // Revisit this after we update it to newer version.
+ typedef void RunType(Args...);
};
@@ -218,21 +222,21 @@ struct ForceVoidReturn<R(Args...)> {
// See description at top of file.
template <typename T>
struct FunctorTraits {
- typedef RunnableAdapter<T> RunnableType;
- typedef typename RunnableType::RunType RunType;
+ using RunnableType = RunnableAdapter<T>;
+ using RunType = typename RunnableType::RunType;
};
template <typename T>
struct FunctorTraits<IgnoreResultHelper<T>> {
- typedef typename FunctorTraits<T>::RunnableType RunnableType;
- typedef typename ForceVoidReturn<
- typename RunnableType::RunType>::RunType RunType;
+ using RunnableType = typename FunctorTraits<T>::RunnableType;
+ using RunType =
+ typename ForceVoidReturn<typename RunnableType::RunType>::RunType;
};
template <typename T>
struct FunctorTraits<Callback<T>> {
- typedef Callback<T> RunnableType;
- typedef typename Callback<T>::RunType RunType;
+ using RunnableType = Callback<T> ;
+ using RunType = typename Callback<T>::RunType;
};
@@ -311,8 +315,8 @@ 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);
+ static_assert(is_void<ReturnType>::value,
+ "weak_ptrs can only bind to methods without return values");
};
#endif
@@ -358,19 +362,18 @@ struct Invoker<IndexSequence<bound_indices...>,
// 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 BoundArgList>
+// BoundArgs contains the storage type for all the bound arguments.
+template <typename Runnable, typename RunType, typename... BoundArgs>
struct BindState;
template <typename Runnable,
typename R,
typename... Args,
typename... BoundArgs>
-struct BindState<Runnable, R(Args...), TypeList<BoundArgs...>> final
+struct BindState<Runnable, R(Args...), BoundArgs...> final
: public BindStateBase {
private:
- using StorageType = BindState<Runnable, R(Args...), TypeList<BoundArgs...>>;
+ using StorageType = BindState<Runnable, R(Args...), BoundArgs...>;
using RunnableType = Runnable;
// true_type if Runnable is a method invocation and the first bound argument
diff --git a/chromium/base/bind_internal_win.h b/chromium/base/bind_internal_win.h
index c3f7477668e..2ee12ef214d 100644
--- a/chromium/base/bind_internal_win.h
+++ b/chromium/base/bind_internal_win.h
@@ -8,6 +8,8 @@
#ifndef BASE_BIND_INTERNAL_WIN_H_
#define BASE_BIND_INTERNAL_WIN_H_
+#include "build/build_config.h"
+
// In the x64 architecture in Windows, __fastcall, __stdcall, etc, are all
// the same as __cdecl which would turn the following specializations into
// multiple definitions.
@@ -23,7 +25,9 @@ class RunnableAdapter;
template <typename R, typename... Args>
class RunnableAdapter<R(__stdcall *)(Args...)> {
public:
- typedef R (RunType)(Args...);
+ // MSVC 2013 doesn't support Type Alias of function types.
+ // Revisit this after we update it to newer version.
+ typedef R RunType(Args...);
explicit RunnableAdapter(R(__stdcall *function)(Args...))
: function_(function) {
@@ -41,7 +45,9 @@ class RunnableAdapter<R(__stdcall *)(Args...)> {
template <typename R, typename... Args>
class RunnableAdapter<R(__fastcall *)(Args...)> {
public:
- typedef R (RunType)(Args...);
+ // MSVC 2013 doesn't support Type Alias of function types.
+ // Revisit this after we update it to newer version.
+ typedef R RunType(Args...);
explicit RunnableAdapter(R(__fastcall *function)(Args...))
: function_(function) {
diff --git a/chromium/base/bind_unittest.cc b/chromium/base/bind_unittest.cc
index f885403c92d..7850ea6b740 100644
--- a/chromium/base/bind_unittest.cc
+++ b/chromium/base/bind_unittest.cc
@@ -4,10 +4,15 @@
#include "base/bind.h"
+#include <memory>
+#include <utility>
+
#include "base/callback.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
+#include "build/build_config.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -24,11 +29,11 @@ class NoRef {
public:
NoRef() {}
- MOCK_METHOD0(VoidMethod0, void(void));
- MOCK_CONST_METHOD0(VoidConstMethod0, void(void));
+ MOCK_METHOD0(VoidMethod0, void());
+ MOCK_CONST_METHOD0(VoidConstMethod0, void());
- MOCK_METHOD0(IntMethod0, int(void));
- MOCK_CONST_METHOD0(IntConstMethod0, int(void));
+ MOCK_METHOD0(IntMethod0, int());
+ MOCK_CONST_METHOD0(IntConstMethod0, int());
private:
// Particularly important in this test to ensure no copies are made.
@@ -39,8 +44,8 @@ class HasRef : public NoRef {
public:
HasRef() {}
- MOCK_CONST_METHOD0(AddRef, void(void));
- MOCK_CONST_METHOD0(Release, bool(void));
+ MOCK_CONST_METHOD0(AddRef, void());
+ MOCK_CONST_METHOD0(Release, bool());
private:
// Particularly important in this test to ensure no copies are made.
@@ -57,8 +62,8 @@ static const int kChildValue = 2;
class Parent {
public:
- void AddRef(void) const {}
- void Release(void) const {}
+ void AddRef() const {}
+ void Release() const {}
virtual void VirtualSet() { value = kParentValue; }
void NonVirtualSet() { value = kParentValue; }
int value;
@@ -150,7 +155,7 @@ class DeleteCounter {
template <typename T>
T PassThru(T scoper) {
- return scoper.Pass();
+ return scoper;
}
// Some test functions that we can Bind to.
@@ -159,9 +164,10 @@ T PolymorphicIdentity(T t) {
return t;
}
-template <typename T>
-void VoidPolymorphic1(T t) {
-}
+template <typename... Ts>
+struct VoidPolymorphic {
+ static void Run(Ts... t) {}
+};
int Identity(int n) {
return n;
@@ -226,11 +232,11 @@ class BindTest : public ::testing::Test {
virtual ~BindTest() {
}
- static void VoidFunc0(void) {
+ static void VoidFunc0() {
static_func_mock_ptr->VoidMethod0();
}
- static int IntFunc0(void) { return static_func_mock_ptr->IntMethod0(); }
+ static int IntFunc0() { return static_func_mock_ptr->IntMethod0(); }
protected:
StrictMock<NoRef> no_ref_;
@@ -250,7 +256,7 @@ StrictMock<NoRef>* BindTest::static_func_mock_ptr;
// Sanity check that we can instantiate a callback for each arity.
TEST_F(BindTest, ArityTest) {
- Callback<int(void)> c0 = Bind(&Sum, 32, 16, 8, 4, 2, 1);
+ Callback<int()> c0 = Bind(&Sum, 32, 16, 8, 4, 2, 1);
EXPECT_EQ(63, c0.Run());
Callback<int(int)> c1 = Bind(&Sum, 32, 16, 8, 4, 2);
@@ -292,7 +298,7 @@ TEST_F(BindTest, CurryingTest) {
Callback<int(int)> c1 = Bind(c2, 2);
EXPECT_EQ(75, c1.Run(13));
- Callback<int(void)> c0 = Bind(c1, 1);
+ Callback<int()> c0 = Bind(c1, 1);
EXPECT_EQ(63, c0.Run());
}
@@ -333,7 +339,7 @@ TEST_F(BindTest, FunctionTypeSupport) {
EXPECT_CALL(has_ref_, VoidConstMethod0()).Times(2);
Closure normal_cb = Bind(&VoidFunc0);
- Callback<NoRef*(void)> normal_non_refcounted_cb =
+ Callback<NoRef*()> normal_non_refcounted_cb =
Bind(&PolymorphicIdentity<NoRef*>, &no_ref_);
normal_cb.Run();
EXPECT_EQ(&no_ref_, normal_non_refcounted_cb.Run());
@@ -375,11 +381,11 @@ TEST_F(BindTest, ReturnValues) {
.WillOnce(Return(41337))
.WillOnce(Return(51337));
- Callback<int(void)> normal_cb = Bind(&IntFunc0);
- Callback<int(void)> method_cb = Bind(&HasRef::IntMethod0, &has_ref_);
- Callback<int(void)> const_method_nonconst_obj_cb =
+ Callback<int()> normal_cb = Bind(&IntFunc0);
+ Callback<int()> method_cb = Bind(&HasRef::IntMethod0, &has_ref_);
+ Callback<int()> const_method_nonconst_obj_cb =
Bind(&HasRef::IntConstMethod0, &has_ref_);
- Callback<int(void)> const_method_const_obj_cb =
+ Callback<int()> const_method_const_obj_cb =
Bind(&HasRef::IntConstMethod0, const_has_ref_ptr_);
EXPECT_EQ(1337, normal_cb.Run());
EXPECT_EQ(31337, method_cb.Run());
@@ -443,46 +449,46 @@ TEST_F(BindTest, IgnoreResult) {
TEST_F(BindTest, ArgumentBinding) {
int n = 2;
- Callback<int(void)> bind_primitive_cb = Bind(&Identity, n);
+ Callback<int()> bind_primitive_cb = Bind(&Identity, n);
EXPECT_EQ(n, bind_primitive_cb.Run());
- Callback<int*(void)> bind_primitive_pointer_cb =
+ Callback<int*()> bind_primitive_pointer_cb =
Bind(&PolymorphicIdentity<int*>, &n);
EXPECT_EQ(&n, bind_primitive_pointer_cb.Run());
- Callback<int(void)> bind_int_literal_cb = Bind(&Identity, 3);
+ Callback<int()> bind_int_literal_cb = Bind(&Identity, 3);
EXPECT_EQ(3, bind_int_literal_cb.Run());
- Callback<const char*(void)> bind_string_literal_cb =
+ Callback<const char*()> bind_string_literal_cb =
Bind(&CStringIdentity, "hi");
EXPECT_STREQ("hi", bind_string_literal_cb.Run());
- Callback<int(void)> bind_template_function_cb =
+ Callback<int()> bind_template_function_cb =
Bind(&PolymorphicIdentity<int>, 4);
EXPECT_EQ(4, bind_template_function_cb.Run());
NoRefParent p;
p.value = 5;
- Callback<int(void)> bind_object_cb = Bind(&UnwrapNoRefParent, p);
+ Callback<int()> bind_object_cb = Bind(&UnwrapNoRefParent, p);
EXPECT_EQ(5, bind_object_cb.Run());
IncompleteType* incomplete_ptr = reinterpret_cast<IncompleteType*>(123);
- Callback<IncompleteType*(void)> bind_incomplete_ptr_cb =
+ Callback<IncompleteType*()> bind_incomplete_ptr_cb =
Bind(&PolymorphicIdentity<IncompleteType*>, incomplete_ptr);
EXPECT_EQ(incomplete_ptr, bind_incomplete_ptr_cb.Run());
NoRefChild c;
c.value = 6;
- Callback<int(void)> bind_promotes_cb = Bind(&UnwrapNoRefParent, c);
+ Callback<int()> bind_promotes_cb = Bind(&UnwrapNoRefParent, c);
EXPECT_EQ(6, bind_promotes_cb.Run());
c.value = 7;
- Callback<int(void)> bind_pointer_promotes_cb =
+ Callback<int()> bind_pointer_promotes_cb =
Bind(&UnwrapNoRefParentPtr, &c);
EXPECT_EQ(7, bind_pointer_promotes_cb.Run());
c.value = 8;
- Callback<int(void)> bind_const_reference_promotes_cb =
+ Callback<int()> bind_const_reference_promotes_cb =
Bind(&UnwrapNoRefParentConstRef, c);
EXPECT_EQ(8, bind_const_reference_promotes_cb.Run());
}
@@ -496,17 +502,20 @@ TEST_F(BindTest, ArgumentBinding) {
// - Unbound sized array.
// - Unbound array-of-arrays.
TEST_F(BindTest, UnboundArgumentTypeSupport) {
- Callback<void(int)> unbound_value_cb = Bind(&VoidPolymorphic1<int>);
- Callback<void(int*)> unbound_pointer_cb = Bind(&VoidPolymorphic1<int*>);
- Callback<void(int&)> unbound_ref_cb = Bind(&VoidPolymorphic1<int&>);
+ Callback<void(int)> unbound_value_cb = Bind(&VoidPolymorphic<int>::Run);
+ Callback<void(int*)> unbound_pointer_cb = Bind(&VoidPolymorphic<int*>::Run);
+ Callback<void(int&)> unbound_ref_cb = Bind(&VoidPolymorphic<int&>::Run);
Callback<void(const int&)> unbound_const_ref_cb =
- Bind(&VoidPolymorphic1<const int&>);
+ Bind(&VoidPolymorphic<const int&>::Run);
Callback<void(int[])> unbound_unsized_array_cb =
- Bind(&VoidPolymorphic1<int[]>);
+ Bind(&VoidPolymorphic<int[]>::Run);
Callback<void(int[2])> unbound_sized_array_cb =
- Bind(&VoidPolymorphic1<int[2]>);
+ Bind(&VoidPolymorphic<int[2]>::Run);
Callback<void(int[][2])> unbound_array_of_arrays_cb =
- Bind(&VoidPolymorphic1<int[][2]>);
+ Bind(&VoidPolymorphic<int[][2]>::Run);
+
+ Callback<void(int&)> unbound_ref_with_bound_arg =
+ Bind(&VoidPolymorphic<int, int&>::Run, 1);
}
// Function with unbound reference parameter.
@@ -526,12 +535,12 @@ TEST_F(BindTest, ReferenceArgumentBinding) {
int& ref_n = n;
const int& const_ref_n = n;
- Callback<int(void)> ref_copies_cb = Bind(&Identity, ref_n);
+ Callback<int()> ref_copies_cb = Bind(&Identity, ref_n);
EXPECT_EQ(n, ref_copies_cb.Run());
n++;
EXPECT_EQ(n - 1, ref_copies_cb.Run());
- Callback<int(void)> const_ref_copies_cb = Bind(&Identity, const_ref_n);
+ Callback<int()> const_ref_copies_cb = Bind(&Identity, const_ref_n);
EXPECT_EQ(n, const_ref_copies_cb.Run());
n++;
EXPECT_EQ(n - 1, const_ref_copies_cb.Run());
@@ -544,10 +553,10 @@ TEST_F(BindTest, ArrayArgumentBinding) {
int array[4] = {1, 1, 1, 1};
const int (*const_array_ptr)[4] = &array;
- Callback<int(void)> array_cb = Bind(&ArrayGet, array, 1);
+ Callback<int()> array_cb = Bind(&ArrayGet, array, 1);
EXPECT_EQ(1, array_cb.Run());
- Callback<int(void)> const_array_cb = Bind(&ArrayGet, *const_array_ptr, 1);
+ Callback<int()> const_array_cb = Bind(&ArrayGet, *const_array_ptr, 1);
EXPECT_EQ(1, const_array_cb.Run());
array[1] = 3;
@@ -585,15 +594,15 @@ TEST_F(BindTest, Unretained) {
EXPECT_CALL(no_ref_, VoidMethod0());
EXPECT_CALL(no_ref_, VoidConstMethod0()).Times(2);
- Callback<void(void)> method_cb =
+ Callback<void()> method_cb =
Bind(&NoRef::VoidMethod0, Unretained(&no_ref_));
method_cb.Run();
- Callback<void(void)> const_method_cb =
+ Callback<void()> const_method_cb =
Bind(&NoRef::VoidConstMethod0, Unretained(&no_ref_));
const_method_cb.Run();
- Callback<void(void)> const_method_const_ptr_cb =
+ Callback<void()> const_method_const_ptr_cb =
Bind(&NoRef::VoidConstMethod0, Unretained(const_no_ref_ptr_));
const_method_const_ptr_cb.Run();
}
@@ -645,8 +654,8 @@ TEST_F(BindTest, WeakPtr) {
TEST_F(BindTest, ConstRef) {
int n = 1;
- Callback<int(void)> copy_cb = Bind(&Identity, n);
- Callback<int(void)> const_ref_cb = Bind(&Identity, ConstRef(n));
+ Callback<int()> copy_cb = Bind(&Identity, n);
+ Callback<int()> const_ref_cb = Bind(&Identity, ConstRef(n));
EXPECT_EQ(n, copy_cb.Run());
EXPECT_EQ(n, const_ref_cb.Run());
n++;
@@ -656,7 +665,7 @@ TEST_F(BindTest, ConstRef) {
int copies = 0;
int assigns = 0;
CopyCounter counter(&copies, &assigns);
- Callback<int(void)> all_const_ref_cb =
+ Callback<int()> all_const_ref_cb =
Bind(&GetCopies, ConstRef(counter));
EXPECT_EQ(0, all_const_ref_cb.Run());
EXPECT_EQ(0, copies);
@@ -673,7 +682,7 @@ TEST_F(BindTest, ScopedRefptr) {
const scoped_refptr<StrictMock<HasRef> > refptr(&has_ref_);
- Callback<int(void)> scoped_refptr_const_ref_cb =
+ Callback<int()> scoped_refptr_const_ref_cb =
Bind(&FunctionWithScopedRefptrFirstParam, base::ConstRef(refptr), 1);
EXPECT_EQ(1, scoped_refptr_const_ref_cb.Run());
}
@@ -685,7 +694,7 @@ TEST_F(BindTest, Owned) {
// If we don't capture, delete happens on Callback destruction/reset.
// return the same value.
- Callback<DeleteCounter*(void)> no_capture_cb =
+ Callback<DeleteCounter*()> no_capture_cb =
Bind(&PolymorphicIdentity<DeleteCounter*>, Owned(counter));
ASSERT_EQ(counter, no_capture_cb.Run());
ASSERT_EQ(counter, no_capture_cb.Run());
@@ -714,7 +723,7 @@ TEST_F(BindTest, ScopedPtr) {
// Tests the Passed() function's support for pointers.
scoped_ptr<DeleteCounter> ptr(new DeleteCounter(&deletes));
- Callback<scoped_ptr<DeleteCounter>(void)> unused_callback =
+ Callback<scoped_ptr<DeleteCounter>()> unused_callback =
Bind(&PassThru<scoped_ptr<DeleteCounter> >, Passed(&ptr));
EXPECT_FALSE(ptr.get());
EXPECT_EQ(0, deletes);
@@ -726,7 +735,7 @@ TEST_F(BindTest, ScopedPtr) {
// Tests the Passed() function's support for rvalues.
deletes = 0;
DeleteCounter* counter = new DeleteCounter(&deletes);
- Callback<scoped_ptr<DeleteCounter>(void)> callback =
+ Callback<scoped_ptr<DeleteCounter>()> callback =
Bind(&PassThru<scoped_ptr<DeleteCounter> >,
Passed(scoped_ptr<DeleteCounter>(counter)));
EXPECT_FALSE(ptr.get());
@@ -749,7 +758,50 @@ TEST_F(BindTest, ScopedPtr) {
Callback<scoped_ptr<DeleteCounter>(scoped_ptr<DeleteCounter>)> cb_unbound =
Bind(&PassThru<scoped_ptr<DeleteCounter> >);
ptr.reset(new DeleteCounter(&deletes));
- cb_unbound.Run(ptr.Pass());
+ cb_unbound.Run(std::move(ptr));
+}
+
+TEST_F(BindTest, UniquePtr) {
+ int deletes = 0;
+
+ // Tests the Passed() function's support for pointers.
+ std::unique_ptr<DeleteCounter> ptr(new DeleteCounter(&deletes));
+ Callback<std::unique_ptr<DeleteCounter>()> unused_callback =
+ Bind(&PassThru<std::unique_ptr<DeleteCounter>>, Passed(&ptr));
+ EXPECT_FALSE(ptr.get());
+ EXPECT_EQ(0, deletes);
+
+ // If we never invoke the Callback, it retains ownership and deletes.
+ unused_callback.Reset();
+ EXPECT_EQ(1, deletes);
+
+ // Tests the Passed() function's support for rvalues.
+ deletes = 0;
+ DeleteCounter* counter = new DeleteCounter(&deletes);
+ Callback<std::unique_ptr<DeleteCounter>()> callback =
+ Bind(&PassThru<std::unique_ptr<DeleteCounter>>,
+ Passed(std::unique_ptr<DeleteCounter>(counter)));
+ EXPECT_FALSE(ptr.get());
+ EXPECT_EQ(0, deletes);
+
+ // Check that ownership can be transferred back out.
+ std::unique_ptr<DeleteCounter> result = callback.Run();
+ ASSERT_EQ(counter, result.get());
+ EXPECT_EQ(0, deletes);
+
+ // Resetting does not delete since ownership was transferred.
+ callback.Reset();
+ EXPECT_EQ(0, deletes);
+
+ // Ensure that we actually did get ownership.
+ result.reset();
+ EXPECT_EQ(1, deletes);
+
+ // Test unbound argument forwarding.
+ Callback<std::unique_ptr<DeleteCounter>(std::unique_ptr<DeleteCounter>)>
+ cb_unbound = Bind(&PassThru<std::unique_ptr<DeleteCounter>>);
+ ptr.reset(new DeleteCounter(&deletes));
+ cb_unbound.Run(std::move(ptr));
}
// Argument Copy-constructor usage for non-reference parameters.
@@ -763,15 +815,15 @@ TEST_F(BindTest, ArgumentCopies) {
CopyCounter counter(&copies, &assigns);
- Callback<void(void)> copy_cb =
- Bind(&VoidPolymorphic1<CopyCounter>, counter);
+ Callback<void()> copy_cb =
+ Bind(&VoidPolymorphic<CopyCounter>::Run, counter);
EXPECT_GE(1, copies);
EXPECT_EQ(0, assigns);
copies = 0;
assigns = 0;
Callback<void(CopyCounter)> forward_cb =
- Bind(&VoidPolymorphic1<CopyCounter>);
+ Bind(&VoidPolymorphic<CopyCounter>::Run);
forward_cb.Run(counter);
EXPECT_GE(1, copies);
EXPECT_EQ(0, assigns);
@@ -780,7 +832,7 @@ TEST_F(BindTest, ArgumentCopies) {
assigns = 0;
DerivedCopyCounter derived(&copies, &assigns);
Callback<void(CopyCounter)> coerce_cb =
- Bind(&VoidPolymorphic1<CopyCounter>);
+ Bind(&VoidPolymorphic<CopyCounter>::Run);
coerce_cb.Run(CopyCounter(derived));
EXPECT_GE(2, copies);
EXPECT_EQ(0, assigns);
@@ -805,10 +857,10 @@ int __stdcall StdCallFunc(int n) {
// - Can bind a __fastcall function.
// - Can bind a __stdcall function.
TEST_F(BindTest, WindowsCallingConventions) {
- Callback<int(void)> fastcall_cb = Bind(&FastCallFunc, 1);
+ Callback<int()> fastcall_cb = Bind(&FastCallFunc, 1);
EXPECT_EQ(1, fastcall_cb.Run());
- Callback<int(void)> stdcall_cb = Bind(&StdCallFunc, 2);
+ Callback<int()> stdcall_cb = Bind(&StdCallFunc, 2);
EXPECT_EQ(2, stdcall_cb.Run());
}
#endif
diff --git a/chromium/base/bind_unittest.nc b/chromium/base/bind_unittest.nc
index 259638673a9..9569be476a2 100644
--- a/chromium/base/bind_unittest.nc
+++ b/chromium/base/bind_unittest.nc
@@ -2,8 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/callback.h"
+// This is a "No Compile Test" suite.
+// http://dev.chromium.org/developers/testing/no-compile-tests
+
#include "base/bind.h"
+#include "base/callback.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
namespace base {
@@ -26,8 +30,8 @@ class HasRef : public NoRef, public base::RefCounted<HasRef> {
class Parent {
public:
- void AddRef(void) const {}
- void Release(void) const {}
+ void AddRef() const {}
+ void Release() const {}
virtual void VirtualSet() { value = kParentValue; }
void NonVirtualSet() { value = kParentValue; }
int value;
@@ -64,7 +68,7 @@ template <typename T>
void VoidPolymorphic1(T t) {
}
-#if defined(NCTEST_METHOD_ON_CONST_OBJECT) // [r"fatal error: cannot initialize a parameter of type 'base::NoRef \*' with an lvalue of type 'typename enable_if<!IsMoveOnlyType<const HasRef \*const>::value, const HasRef \*const>::type' \(aka 'const base::HasRef \*const'\)"]
+#if defined(NCTEST_METHOD_ON_CONST_OBJECT) // [r"fatal error: cannot initialize a parameter of type 'base::NoRef \*' with an lvalue of type 'typename std::enable_if<!IsMoveOnlyType<const HasRef \*const>::value, const HasRef \*const>::type' \(aka 'const base::HasRef \*const'\)"]
// Method bound to const-object.
//
@@ -72,7 +76,7 @@ void VoidPolymorphic1(T t) {
void WontCompile() {
HasRef has_ref;
const HasRef* const_has_ref_ptr_ = &has_ref;
- Callback<void(void)> method_to_const_cb =
+ Callback<void()> method_to_const_cb =
Bind(&HasRef::VoidMethod0, const_has_ref_ptr_);
method_to_const_cb.Run();
}
@@ -84,7 +88,7 @@ void WontCompile() {
// We require refcounts unless you have Unretained().
void WontCompile() {
NoRef no_ref;
- Callback<void(void)> no_ref_cb =
+ Callback<void()> no_ref_cb =
Bind(&NoRef::VoidMethod0, &no_ref);
no_ref_cb.Run();
}
@@ -96,31 +100,31 @@ void WontCompile() {
// We require refcounts unless you have Unretained().
void WontCompile() {
NoRef no_ref;
- Callback<void(void)> no_ref_const_cb =
+ Callback<void()> no_ref_const_cb =
Bind(&NoRef::VoidConstMethod0, &no_ref);
no_ref_const_cb.Run();
}
-#elif defined(NCTEST_CONST_POINTER) // [r"fatal error: reference to type 'base::NoRef \*const' could not bind to an lvalue of type 'typename enable_if<!IsMoveOnlyType<const NoRef \*const>::value, const NoRef \*const>::type' \(aka 'const base::NoRef \*const'\)"]
+#elif defined(NCTEST_CONST_POINTER) // [r"fatal error: reference to type 'base::NoRef \*const' could not bind to an lvalue of type 'typename std::enable_if<!IsMoveOnlyType<const NoRef \*const>::value, const NoRef \*const>::type' \(aka 'const base::NoRef \*const'\)"]
// Const argument used with non-const pointer parameter of same type.
//
// This is just a const-correctness check.
void WontCompile() {
const NoRef* const_no_ref_ptr;
- Callback<NoRef*(void)> pointer_same_cb =
+ Callback<NoRef*()> pointer_same_cb =
Bind(&PolymorphicIdentity<NoRef*>, const_no_ref_ptr);
pointer_same_cb.Run();
}
-#elif defined(NCTEST_CONST_POINTER_SUBTYPE) // [r"fatal error: reference to type 'base::NoRefParent \*const' could not bind to an lvalue of type 'typename enable_if<!IsMoveOnlyType<const NoRefChild \*const>::value, const NoRefChild \*const>::type' \(aka 'const base::NoRefChild \*const'\)"]
+#elif defined(NCTEST_CONST_POINTER_SUBTYPE) // [r"fatal error: reference to type 'base::NoRefParent \*const' could not bind to an lvalue of type 'typename std::enable_if<!IsMoveOnlyType<const NoRefChild \*const>::value, const NoRefChild \*const>::type' \(aka 'const base::NoRefChild \*const'\)"]
// Const argument used with non-const pointer parameter of super type.
//
// This is just a const-correctness check.
void WontCompile() {
const NoRefChild* const_child_ptr;
- Callback<NoRefParent*(void)> pointer_super_cb =
+ Callback<NoRefParent*()> pointer_super_cb =
Bind(&PolymorphicIdentity<NoRefParent*>, const_child_ptr);
pointer_super_cb.Run();
}
@@ -142,18 +146,18 @@ void WontCompile() {
ref_arg_cb.Run(p);
}
-#elif defined(NCTEST_DISALLOW_BIND_TO_NON_CONST_REF_PARAM) // [r"fatal error: static_assert failed \"do_not_bind_functions_with_nonconst_ref\""]
+#elif defined(NCTEST_DISALLOW_BIND_TO_NON_CONST_REF_PARAM) // [r"fatal error: static_assert failed \"do not bind functions with nonconst ref\""]
// Binding functions with reference parameters, unsupported.
//
// See comment in NCTEST_DISALLOW_NON_CONST_REF_PARAM
void WontCompile() {
Parent p;
- Callback<int(void)> ref_cb = Bind(&UnwrapParentRef, p);
+ Callback<int()> ref_cb = Bind(&UnwrapParentRef, p);
ref_cb.Run();
}
-#elif defined(NCTEST_NO_IMPLICIT_ARRAY_PTR_CONVERSION) // [r"fatal error: static_assert failed \"first_bound_argument_to_method_cannot_be_array\""]
+#elif defined(NCTEST_NO_IMPLICIT_ARRAY_PTR_CONVERSION) // [r"fatal error: static_assert failed \"first bound argument to method cannot be array\""]
// A method should not be bindable with an array of objects.
//
@@ -162,35 +166,35 @@ void WontCompile() {
// implicitly convert an array type to a pointer type.
void WontCompile() {
HasRef p[10];
- Callback<void(void)> method_bound_to_array_cb =
+ Callback<void()> method_bound_to_array_cb =
Bind(&HasRef::VoidMethod0, p);
method_bound_to_array_cb.Run();
}
-#elif defined(NCTEST_NO_RAW_PTR_FOR_REFCOUNTED_TYPES) // [r"fatal error: static_assert failed \"a_parameter_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 a refcounted type and needs scoped_refptr\""]
// Refcounted types should not be bound as a raw pointer.
void WontCompile() {
HasRef for_raw_ptr;
int a;
- Callback<void(void)> ref_count_as_raw_ptr_a =
+ Callback<void()> ref_count_as_raw_ptr_a =
Bind(&VoidPolymorphic1<int*>, &a);
- Callback<void(void)> ref_count_as_raw_ptr =
+ Callback<void()> ref_count_as_raw_ptr =
Bind(&VoidPolymorphic1<HasRef*>, &for_raw_ptr);
}
-#elif defined(NCTEST_WEAKPTR_BIND_MUST_RETURN_VOID) // [r"fatal error: static_assert failed \"weak_ptrs_can_only_bind_to_methods_without_return_values\""]
+#elif defined(NCTEST_WEAKPTR_BIND_MUST_RETURN_VOID) // [r"fatal error: static_assert failed \"weak_ptrs can only bind to methods without return values\""]
// WeakPtrs cannot be bound to methods with return types.
void WontCompile() {
NoRef no_ref;
WeakPtrFactory<NoRef> weak_factory(&no_ref);
- Callback<int(void)> weak_ptr_with_non_void_return_type =
+ Callback<int()> weak_ptr_with_non_void_return_type =
Bind(&NoRef::IntMethod0, weak_factory.GetWeakPtr());
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, internal::TypeList<> >::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>::UnboundRunType>' to 'Callback<void \(\)>'"]
// Bind result cannot be assigned to Callbacks with a mismatching type.
void WontCompile() {
diff --git a/chromium/base/bit_cast.h b/chromium/base/bit_cast.h
new file mode 100644
index 00000000000..b548467e7b8
--- /dev/null
+++ b/chromium/base/bit_cast.h
@@ -0,0 +1,71 @@
+// Copyright 2016 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_BIT_CAST_H_
+#define BASE_BIT_CAST_H_
+
+#include <string.h>
+
+// bit_cast<Dest,Source> is a template function that implements the equivalent
+// of "*reinterpret_cast<Dest*>(&source)". We need this in very low-level
+// functions like the protobuf library and fast math support.
+//
+// float f = 3.14159265358979;
+// int i = bit_cast<int32_t>(f);
+// // i = 0x40490fdb
+//
+// The classical address-casting method is:
+//
+// // WRONG
+// float f = 3.14159265358979; // WRONG
+// int i = * reinterpret_cast<int*>(&f); // WRONG
+//
+// The address-casting method actually produces undefined behavior according to
+// the ISO C++98 specification, section 3.10 ("basic.lval"), paragraph 15.
+// (This did not substantially change in C++11.) Roughly, this section says: if
+// an object in memory has one type, and a program accesses it with a different
+// type, then the result is undefined behavior for most values of "different
+// type".
+//
+// This is true for any cast syntax, either *(int*)&f or
+// *reinterpret_cast<int*>(&f). And it is particularly true for conversions
+// between integral lvalues and floating-point lvalues.
+//
+// The purpose of this paragraph is to allow optimizing compilers to assume that
+// expressions with different types refer to different memory. Compilers are
+// known to take advantage of this. So a non-conforming program quietly
+// produces wildly incorrect output.
+//
+// The problem is not the use of reinterpret_cast. The problem is type punning:
+// holding an object in memory of one type and reading its bits back using a
+// different type.
+//
+// The C++ standard is more subtle and complex than this, but that is the basic
+// idea.
+//
+// Anyways ...
+//
+// bit_cast<> calls memcpy() which is blessed by the standard, especially by the
+// example in section 3.9 . Also, of course, bit_cast<> wraps up the nasty
+// logic in one place.
+//
+// Fortunately memcpy() is very fast. In optimized mode, compilers replace
+// calls to memcpy() with inline object code when the size argument is a
+// compile-time constant. On a 32-bit system, memcpy(d,s,4) compiles to one
+// load and one store, and memcpy(d,s,8) compiles to two loads and two stores.
+//
+// WARNING: if Dest or Source is a non-POD type, the result of the memcpy
+// is likely to surprise you.
+
+template <class Dest, class Source>
+inline Dest bit_cast(const Source& source) {
+ static_assert(sizeof(Dest) == sizeof(Source),
+ "bit_cast requires source and destination to be the same size");
+
+ Dest dest;
+ memcpy(&dest, &source, sizeof(dest));
+ return dest;
+}
+
+#endif // BASE_BIT_CAST_H_
diff --git a/chromium/base/bits.h b/chromium/base/bits.h
index 505d2c8f75d..a3a59d1dfad 100644
--- a/chromium/base/bits.h
+++ b/chromium/base/bits.h
@@ -7,21 +7,23 @@
#ifndef BASE_BITS_H_
#define BASE_BITS_H_
-#include "base/basictypes.h"
+#include <stddef.h>
+#include <stdint.h>
+
#include "base/logging.h"
namespace base {
namespace bits {
// Returns the integer i such as 2^i <= n < 2^(i+1)
-inline int Log2Floor(uint32 n) {
+inline int Log2Floor(uint32_t n) {
if (n == 0)
return -1;
int log = 0;
- uint32 value = n;
+ uint32_t value = n;
for (int i = 4; i >= 0; --i) {
int shift = (1 << i);
- uint32 x = value >> shift;
+ uint32_t x = value >> shift;
if (x != 0) {
value = x;
log += shift;
@@ -32,7 +34,7 @@ inline int Log2Floor(uint32 n) {
}
// Returns the integer i such as 2^(i-1) < n <= 2^i
-inline int Log2Ceiling(uint32 n) {
+inline int Log2Ceiling(uint32_t n) {
if (n == 0) {
return -1;
} else {
diff --git a/chromium/base/bits_unittest.cc b/chromium/base/bits_unittest.cc
index 1dad0f45319..4f5b6ea49e5 100644
--- a/chromium/base/bits_unittest.cc
+++ b/chromium/base/bits_unittest.cc
@@ -6,6 +6,8 @@
#include "base/bits.h"
+#include <stddef.h>
+
#include <limits>
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/base/callback.h b/chromium/base/callback.h
index 00669dd83d1..3bf0008b6d3 100644
--- a/chromium/base/callback.h
+++ b/chromium/base/callback.h
@@ -26,7 +26,7 @@
// 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)>)
+// A callback with no unbound input parameters (base::Callback<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.
@@ -48,7 +48,7 @@
// BINDING A BARE FUNCTION
//
// int Return5() { return 5; }
-// base::Callback<int(void)> func_cb = base::Bind(&Return5);
+// base::Callback<int()> func_cb = base::Bind(&Return5);
// LOG(INFO) << func_cb.Run(); // Prints 5.
//
// BINDING A CLASS METHOD
@@ -62,7 +62,7 @@
// void PrintBye() { LOG(INFO) << "bye."; }
// };
// scoped_refptr<Ref> ref = new Ref();
-// base::Callback<void(void)> ref_cb = base::Bind(&Ref::Foo, ref);
+// base::Callback<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
@@ -104,10 +104,10 @@
// calling.
//
// void MyFunc(int i, const std::string& str) {}
-// base::Callback<void(void)> cb = base::Bind(&MyFunc, 23, "hello world");
+// base::Callback<void()> cb = base::Bind(&MyFunc, 23, "hello world");
// cb.Run();
//
-// A callback with no unbound input parameters (base::Callback<void(void)>)
+// A callback with no unbound input parameters (base::Callback<void()>)
// is called a base::Closure. So we could have also written:
//
// base::Closure cb = base::Bind(&MyFunc, 23, "hello world");
@@ -165,7 +165,7 @@
// that doesn't expect a return value.
//
// int DoSomething(int arg) { cout << arg << endl; }
-// base::Callback<void<int>) cb =
+// base::Callback<void(int)> cb =
// base::Bind(base::IgnoreResult(&DoSomething));
//
//
@@ -175,7 +175,7 @@
//
// 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).
+// Closure (base::Callback<void()> and base::Closure are the same thing).
//
// PASSING PARAMETERS OWNED BY THE CALLBACK
//
@@ -354,32 +354,30 @@ namespace base {
//
// 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>
+template <typename Runnable, typename RunType, typename... BoundArgsType>
struct BindState;
} // namespace internal
template <typename R, typename... Args>
class Callback<R(Args...)> : public internal::CallbackBase {
public:
- typedef R(RunType)(Args...);
+ // MSVC 2013 doesn't support Type Alias of function types.
+ // Revisit this after we update it to newer version.
+ typedef R RunType(Args...);
- Callback() : CallbackBase(NULL) { }
+ Callback() : CallbackBase(nullptr) { }
- // 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)
+ template <typename Runnable, typename BindRunType, typename... BoundArgsType>
+ explicit 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>
+ &internal::BindState<Runnable, BindRunType, BoundArgsType...>
::InvokerType::Run;
polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
}
@@ -397,15 +395,11 @@ class Callback<R(Args...)> : public internal::CallbackBase {
}
private:
- typedef R(*PolymorphicInvoke)(
- internal::BindStateBase*,
- typename internal::CallbackParamTraits<Args>::ForwardType...);
+ using PolymorphicInvoke =
+ R(*)(internal::BindStateBase*,
+ typename internal::CallbackParamTraits<Args>::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_
diff --git a/chromium/base/callback_forward.h b/chromium/base/callback_forward.h
index 262c3065300..a9a263a50ea 100644
--- a/chromium/base/callback_forward.h
+++ b/chromium/base/callback_forward.h
@@ -10,7 +10,9 @@ namespace base {
template <typename Sig>
class Callback;
-typedef Callback<void(void)> Closure;
+// Syntactic sugar to make Callback<void()> easier to declare since it
+// will be used in a lot of APIs with delayed execution.
+using Closure = Callback<void()>;
} // namespace base
diff --git a/chromium/base/callback_helpers.h b/chromium/base/callback_helpers.h
index 8481e3e71c0..860803989f4 100644
--- a/chromium/base/callback_helpers.h
+++ b/chromium/base/callback_helpers.h
@@ -14,9 +14,9 @@
#ifndef BASE_CALLBACK_HELPERS_H_
#define BASE_CALLBACK_HELPERS_H_
-#include "base/basictypes.h"
#include "base/callback.h"
#include "base/compiler_specific.h"
+#include "base/macros.h"
namespace base {
diff --git a/chromium/base/callback_internal.h b/chromium/base/callback_internal.h
index b6353dc8e56..d1d8ab8ec65 100644
--- a/chromium/base/callback_internal.h
+++ b/chromium/base/callback_internal.h
@@ -9,6 +9,8 @@
#define BASE_CALLBACK_INTERNAL_H_
#include <stddef.h>
+#include <memory>
+#include <type_traits>
#include "base/atomic_ref_count.h"
#include "base/base_export.h"
@@ -71,7 +73,7 @@ class BASE_EXPORT CallbackBase {
// another type. It is not okay to use void*. We create a InvokeFuncStorage
// that that can store our function pointer, and then cast it back to
// the original type on usage.
- typedef void(*InvokeFuncStorage)(void);
+ using InvokeFuncStorage = void(*)();
// Returns true if this callback equals |other|. |other| may be null.
bool Equals(const CallbackBase& other) const;
@@ -92,8 +94,14 @@ class BASE_EXPORT CallbackBase {
};
// A helper template to determine if given type is non-const move-only-type,
-// i.e. if a value of the given type should be passed via .Pass() in a
-// destructive way.
+// i.e. if a value of the given type should be passed via std::move() in a
+// destructive way. Types are considered to be move-only if they have a
+// sentinel MoveOnlyTypeForCPP03 member: a class typically gets this from using
+// the DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND macro.
+// It would be easy to generalize this trait to all move-only types... but this
+// confuses template deduction in VS2013 with certain types such as
+// std::unique_ptr.
+// TODO(dcheng): Revisit this when Windows switches to VS2015 by default.
template <typename T> struct IsMoveOnlyType {
template <typename U>
static YesType Test(const typename U::MoveOnlyTypeForCPP03*);
@@ -105,17 +113,10 @@ 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;
-};
+// Specialization of IsMoveOnlyType so that std::unique_ptr is still considered
+// move-only, even without the sentinel member.
+template <typename T>
+struct IsMoveOnlyType<std::unique_ptr<T>> : std::true_type {};
template <typename>
struct CallbackParamTraitsForMoveOnlyType;
@@ -140,15 +141,15 @@ struct CallbackParamTraitsForNonMoveOnlyType;
// break passing of C-string literals.
template <typename T>
struct CallbackParamTraits
- : SelectType<IsMoveOnlyType<T>::value,
+ : std::conditional<IsMoveOnlyType<T>::value,
CallbackParamTraitsForMoveOnlyType<T>,
- CallbackParamTraitsForNonMoveOnlyType<T> >::Type {
+ CallbackParamTraitsForNonMoveOnlyType<T>>::type {
};
template <typename T>
struct CallbackParamTraitsForNonMoveOnlyType {
- typedef const T& ForwardType;
- typedef T StorageType;
+ using ForwardType = const T&;
+ using StorageType = T;
};
// The Storage should almost be impossible to trigger unless someone manually
@@ -158,8 +159,8 @@ struct CallbackParamTraitsForNonMoveOnlyType {
// The ForwardType should only be used for unbound arguments.
template <typename T>
struct CallbackParamTraitsForNonMoveOnlyType<T&> {
- typedef T& ForwardType;
- typedef T StorageType;
+ using ForwardType = T&;
+ using StorageType = T;
};
// Note that for array types, we implicitly add a const in the conversion. This
@@ -169,15 +170,15 @@ struct CallbackParamTraitsForNonMoveOnlyType<T&> {
// restriction.
template <typename T, size_t n>
struct CallbackParamTraitsForNonMoveOnlyType<T[n]> {
- typedef const T* ForwardType;
- typedef const T* StorageType;
+ using ForwardType = const T*;
+ using StorageType = const T*;
};
// See comment for CallbackParamTraits<T[n]>.
template <typename T>
struct CallbackParamTraitsForNonMoveOnlyType<T[]> {
- typedef const T* ForwardType;
- typedef const T* StorageType;
+ using ForwardType = const T*;
+ using StorageType = const T*;
};
// Parameter traits for movable-but-not-copyable scopers.
@@ -195,8 +196,8 @@ struct CallbackParamTraitsForNonMoveOnlyType<T[]> {
// function or a cast would not be usable with Callback<> or Bind().
template <typename T>
struct CallbackParamTraitsForMoveOnlyType {
- typedef T ForwardType;
- typedef T StorageType;
+ using ForwardType = T;
+ using StorageType = T;
};
// CallbackForward() is a very limited simulation of C++11's std::forward()
@@ -208,7 +209,7 @@ struct CallbackParamTraitsForMoveOnlyType {
// default template compiles out to be a no-op.
//
// In C++11, std::forward would replace all uses of this function. However, it
-// is impossible to implement a general std::forward with C++11 due to a lack
+// is impossible to implement a general std::forward without C++11 due to a lack
// of rvalue references.
//
// In addition to Callback/Bind, this is used by PostTaskAndReplyWithResult to
@@ -216,13 +217,15 @@ struct CallbackParamTraitsForMoveOnlyType {
// parameter to another callback. This is to support Callbacks that return
// the movable-but-not-copyable types whitelisted above.
template <typename T>
-typename enable_if<!IsMoveOnlyType<T>::value, T>::type& CallbackForward(T& t) {
+typename std::enable_if<!IsMoveOnlyType<T>::value, T>::type& CallbackForward(
+ T& t) {
return t;
}
template <typename T>
-typename enable_if<IsMoveOnlyType<T>::value, T>::type CallbackForward(T& t) {
- return t.Pass();
+typename std::enable_if<IsMoveOnlyType<T>::value, T>::type CallbackForward(
+ T& t) {
+ return std::move(t);
}
} // namespace internal
diff --git a/chromium/base/callback_list.h b/chromium/base/callback_list.h
index aeed5f1e221..7d6a478e8ce 100644
--- a/chromium/base/callback_list.h
+++ b/chromium/base/callback_list.h
@@ -7,11 +7,11 @@
#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/macros.h"
#include "base/memory/scoped_ptr.h"
// OVERVIEW:
@@ -185,10 +185,10 @@ class CallbackListBase {
} else {
++it;
}
-
- if (updated && !removal_callback_.is_null())
- removal_callback_.Run();
}
+
+ if (updated && !removal_callback_.is_null())
+ removal_callback_.Run();
}
private:
diff --git a/chromium/base/callback_list_unittest.cc b/chromium/base/callback_list_unittest.cc
index 9adbabb0931..010efc54f74 100644
--- a/chromium/base/callback_list_unittest.cc
+++ b/chromium/base/callback_list_unittest.cc
@@ -4,9 +4,11 @@
#include "base/callback_list.h"
-#include "base/basictypes.h"
+#include <utility>
+
#include "base/bind.h"
#include "base/bind_helpers.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -37,7 +39,7 @@ class Remover {
}
void SetSubscriptionToRemove(
scoped_ptr<CallbackList<void(void)>::Subscription> sub) {
- removal_subscription_ = sub.Pass();
+ removal_subscription_ = std::move(sub);
}
int total() const { return total_; }
@@ -98,6 +100,19 @@ class Summer {
DISALLOW_COPY_AND_ASSIGN(Summer);
};
+class Counter {
+ public:
+ Counter() : value_(0) {}
+
+ void Increment() { value_++; }
+
+ int value() const { return value_; }
+
+ private:
+ int value_;
+ DISALLOW_COPY_AND_ASSIGN(Counter);
+};
+
// Sanity check that we can instantiate a CallbackList for each arity.
TEST(CallbackListTest, ArityTest) {
Summer s;
@@ -234,9 +249,9 @@ TEST(CallbackListTest, RemoveCallbacksDuringIteration) {
cb_reg.Add(Bind(&Listener::IncrementTotal, Unretained(&b)));
// |remover_1| will remove itself.
- remover_1.SetSubscriptionToRemove(remover_1_sub.Pass());
+ remover_1.SetSubscriptionToRemove(std::move(remover_1_sub));
// |remover_2| will remove a.
- remover_2.SetSubscriptionToRemove(a_subscription.Pass());
+ remover_2.SetSubscriptionToRemove(std::move(a_subscription));
cb_reg.Notify();
@@ -287,5 +302,37 @@ TEST(CallbackListTest, EmptyList) {
cb_reg.Notify();
}
+TEST(CallbackList, RemovalCallback) {
+ Counter remove_count;
+ CallbackList<void(void)> cb_reg;
+ cb_reg.set_removal_callback(
+ Bind(&Counter::Increment, Unretained(&remove_count)));
+
+ scoped_ptr<CallbackList<void(void)>::Subscription> subscription =
+ cb_reg.Add(Bind(&DoNothing));
+
+ // Removing a subscription outside of iteration signals the callback.
+ EXPECT_EQ(0, remove_count.value());
+ subscription.reset();
+ EXPECT_EQ(1, remove_count.value());
+
+ // Configure two subscriptions to remove themselves.
+ Remover remover_1, remover_2;
+ scoped_ptr<CallbackList<void(void)>::Subscription> remover_1_sub =
+ cb_reg.Add(Bind(&Remover::IncrementTotalAndRemove,
+ Unretained(&remover_1)));
+ scoped_ptr<CallbackList<void(void)>::Subscription> remover_2_sub =
+ cb_reg.Add(Bind(&Remover::IncrementTotalAndRemove,
+ Unretained(&remover_2)));
+ remover_1.SetSubscriptionToRemove(std::move(remover_1_sub));
+ remover_2.SetSubscriptionToRemove(std::move(remover_2_sub));
+
+ // The callback should be signaled exactly once.
+ EXPECT_EQ(1, remove_count.value());
+ cb_reg.Notify();
+ EXPECT_EQ(2, remove_count.value());
+ EXPECT_TRUE(cb_reg.empty());
+}
+
} // namespace
} // namespace base
diff --git a/chromium/base/callback_list_unittest.nc b/chromium/base/callback_list_unittest.nc
index 2d464cf1f1b..ef193f4ee36 100644
--- a/chromium/base/callback_list_unittest.nc
+++ b/chromium/base/callback_list_unittest.nc
@@ -2,11 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// This is a "No Compile Test" suite.
+// http://dev.chromium.org/developers/testing/no-compile-tests
+
#include "base/callback_list.h"
-#include "base/basictypes.h"
+#include <utility>
+
#include "base/bind.h"
#include "base/bind_helpers.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
namespace base {
@@ -21,7 +26,7 @@ class FooListener {
public:
FooListener() {}
- void GotAScopedFoo(scoped_ptr<Foo> f) { foo_ = f.Pass(); }
+ void GotAScopedFoo(scoped_ptr<Foo> f) { foo_ = std::move(f); }
scoped_ptr<Foo> foo_;
@@ -30,7 +35,7 @@ class FooListener {
};
-#if defined(NCTEST_MOVE_ONLY_TYPE_PARAMETER) // [r"calling a private constructor of class"]
+#if defined(NCTEST_MOVE_ONLY_TYPE_PARAMETER) // [r"fatal error: call to deleted constructor"]
// Callbacks run with a move-only typed parameter.
//
diff --git a/chromium/base/callback_unittest.cc b/chromium/base/callback_unittest.cc
index 2844aa98a29..1f492d42096 100644
--- a/chromium/base/callback_unittest.cc
+++ b/chromium/base/callback_unittest.cc
@@ -15,7 +15,9 @@ namespace base {
namespace {
struct FakeInvoker {
- typedef void(RunType)(internal::BindStateBase*);
+ // MSVC 2013 doesn't support Type Alias of function types.
+ // Revisit this after we update it to newer version.
+ typedef void RunType(internal::BindStateBase*);
static void Run(internal::BindStateBase*) {
}
};
@@ -23,8 +25,6 @@ struct FakeInvoker {
} // namespace
namespace internal {
-template <typename Runnable, typename RunType, typename BoundArgsType>
-struct BindState;
// White-box testpoints to inject into a Callback<> object for checking
// comparators and emptiness APIs. Use a BindState that is specialized
@@ -32,11 +32,11 @@ struct BindState;
// chance of colliding with another instantiation and breaking the
// one-definition-rule.
template <>
-struct BindState<void(void), void(void), void(FakeInvoker)>
+struct BindState<void(), void(), FakeInvoker>
: public BindStateBase {
public:
BindState() : BindStateBase(&Destroy) {}
- typedef FakeInvoker InvokerType;
+ using InvokerType = FakeInvoker;
private:
~BindState() {}
static void Destroy(BindStateBase* self) {
@@ -45,12 +45,11 @@ struct BindState<void(void), void(void), void(FakeInvoker)>
};
template <>
-struct BindState<void(void), void(void),
- void(FakeInvoker, FakeInvoker)>
+struct BindState<void(), void(), FakeInvoker, FakeInvoker>
: public BindStateBase {
public:
BindState() : BindStateBase(&Destroy) {}
- typedef FakeInvoker InvokerType;
+ using InvokerType = FakeInvoker;
private:
~BindState() {}
static void Destroy(BindStateBase* self) {
@@ -61,11 +60,9 @@ struct BindState<void(void), void(void),
namespace {
-typedef internal::BindState<void(void), void(void), void(FakeInvoker)>
- FakeBindState1;
-typedef internal::BindState<void(void), void(void),
- void(FakeInvoker, FakeInvoker)>
- FakeBindState2;
+using FakeBindState1 = internal::BindState<void(), void(), FakeInvoker>;
+using FakeBindState2 =
+ internal::BindState<void(), void(), FakeInvoker, FakeInvoker>;
class CallbackTest : public ::testing::Test {
public:
@@ -77,15 +74,15 @@ class CallbackTest : public ::testing::Test {
~CallbackTest() override {}
protected:
- Callback<void(void)> callback_a_;
- const Callback<void(void)> callback_b_; // Ensure APIs work with const.
- Callback<void(void)> null_callback_;
+ Callback<void()> callback_a_;
+ const Callback<void()> callback_b_; // Ensure APIs work with const.
+ Callback<void()> null_callback_;
};
// Ensure we can create unbound callbacks. We need this to be able to store
// them in class members that can be initialized later.
TEST_F(CallbackTest, DefaultConstruction) {
- Callback<void(void)> c0;
+ Callback<void()> c0;
Callback<void(int)> c1;
Callback<void(int,int)> c2;
Callback<void(int,int,int)> c3;
@@ -114,13 +111,13 @@ TEST_F(CallbackTest, Equals) {
EXPECT_FALSE(callback_b_.Equals(callback_a_));
// We should compare based on instance, not type.
- Callback<void(void)> callback_c(new FakeBindState1());
- Callback<void(void)> callback_a2 = callback_a_;
+ Callback<void()> callback_c(new FakeBindState1());
+ Callback<void()> callback_a2 = callback_a_;
EXPECT_TRUE(callback_a_.Equals(callback_a2));
EXPECT_FALSE(callback_a_.Equals(callback_c));
// Empty, however, is always equal to empty.
- Callback<void(void)> empty2;
+ Callback<void()> empty2;
EXPECT_TRUE(null_callback_.Equals(empty2));
}
diff --git a/chromium/base/callback_unittest.nc b/chromium/base/callback_unittest.nc
index e7607d98e7d..a8967b62b01 100644
--- a/chromium/base/callback_unittest.nc
+++ b/chromium/base/callback_unittest.nc
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// This is a "No Compile Test" suite.
+// http://dev.chromium.org/developers/testing/no-compile-tests
+
#include "base/callback.h"
namespace base {
@@ -20,7 +23,7 @@ class Child : Parent {
// considered distinct.
void WontCompile() {
Closure c1;
- Callback<int(void)> c2;
+ Callback<int()> c2;
c1.Equals(c2);
}
@@ -31,8 +34,8 @@ void WontCompile() {
// While this is technically safe, most people aren't used to it when coding
// C++ so if this is happening, it is almost certainly an error.
void WontCompile() {
- Callback<Parent(void)> cb_a;
- Callback<Child(void)> cb_b = cb_a;
+ Callback<Parent()> cb_a;
+ Callback<Child()> cb_b = cb_a;
}
#elif defined(NCTEST_ASSIGNMENT_FROM_SUBTYPE) // [r"fatal error: no viable overloaded '='"]
@@ -40,8 +43,8 @@ void WontCompile() {
// Assignment of Callback<A> from Callback<B> if A is supertype of B.
// See explanation for NCTEST_CONSTRUCTION_FROM_SUBTYPE
void WontCompile() {
- Callback<Parent(void)> cb_a;
- Callback<Child(void)> cb_b;
+ Callback<Parent()> cb_a;
+ Callback<Child()> cb_b;
cb_a = cb_b;
}
diff --git a/chromium/base/cancelable_callback.h b/chromium/base/cancelable_callback.h
index 2b9d2609464..47dfb2d5c7c 100644
--- a/chromium/base/cancelable_callback.h
+++ b/chromium/base/cancelable_callback.h
@@ -48,6 +48,7 @@
#include "base/callback_internal.h"
#include "base/compiler_specific.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/weak_ptr.h"
namespace base {
diff --git a/chromium/base/command_line.cc b/chromium/base/command_line.cc
index c2ce33db5d2..c991959d691 100644
--- a/chromium/base/command_line.cc
+++ b/chromium/base/command_line.cc
@@ -7,9 +7,9 @@
#include <algorithm>
#include <ostream>
-#include "base/basictypes.h"
#include "base/files/file_path.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
@@ -75,7 +75,11 @@ void AppendSwitchesAndArguments(CommandLine* command_line,
bool parse_switches = true;
for (size_t i = 1; i < argv.size(); ++i) {
CommandLine::StringType arg = argv[i];
+#if defined(OS_WIN)
TrimWhitespace(arg, TRIM_ALL, &arg);
+#else
+ TrimWhitespaceASCII(arg, TRIM_ALL, &arg);
+#endif
CommandLine::StringType switch_string;
CommandLine::StringType switch_value;
@@ -263,7 +267,11 @@ FilePath CommandLine::GetProgram() const {
}
void CommandLine::SetProgram(const FilePath& program) {
+#if defined(OS_WIN)
TrimWhitespace(program.value(), TRIM_ALL, &argv_[0]);
+#else
+ TrimWhitespaceASCII(program.value(), TRIM_ALL, &argv_[0]);
+#endif
}
bool CommandLine::HasSwitch(const base::StringPiece& switch_string) const {
diff --git a/chromium/base/command_line_unittest.cc b/chromium/base/command_line_unittest.cc
index ac8a39567c3..967ce1c5d5b 100644
--- a/chromium/base/command_line_unittest.cc
+++ b/chromium/base/command_line_unittest.cc
@@ -5,11 +5,12 @@
#include <string>
#include <vector>
-#include "base/basictypes.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
diff --git a/chromium/base/compiler_specific.h b/chromium/base/compiler_specific.h
index 02603df5845..339e9b74e9c 100644
--- a/chromium/base/compiler_specific.h
+++ b/chromium/base/compiler_specific.h
@@ -9,6 +9,9 @@
#if defined(COMPILER_MSVC)
+// For _Printf_format_string_.
+#include <sal.h>
+
// Macros for suppressing and disabling warnings on MSVC.
//
// Warning numbers are enumerated at:
@@ -57,6 +60,7 @@
#else // Not MSVC
+#define _Printf_format_string_
#define MSVC_SUPPRESS_WARNING(n)
#define MSVC_PUSH_DISABLE_WARNING(n)
#define MSVC_PUSH_WARNING_LEVEL(n)
@@ -108,7 +112,7 @@
// Return the byte alignment of the given type (available at compile time).
// Use like:
-// ALIGNOF(int32) // this would be 4
+// ALIGNOF(int32_t) // this would be 4
#if defined(COMPILER_MSVC)
#define ALIGNOF(type) __alignof(type)
#elif defined(COMPILER_GCC)
@@ -119,7 +123,8 @@
// Use like:
// int foo() WARN_UNUSED_RESULT;
// To explicitly ignore a result, see |ignore_result()| in base/macros.h.
-#if defined(COMPILER_GCC)
+#undef WARN_UNUSED_RESULT
+#if defined(COMPILER_GCC) || defined(__clang__)
#define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
#else
#define WARN_UNUSED_RESULT
diff --git a/chromium/base/containers/adapters.h b/chromium/base/containers/adapters.h
index cc151fc2468..fa671b46d99 100644
--- a/chromium/base/containers/adapters.h
+++ b/chromium/base/containers/adapters.h
@@ -5,6 +5,10 @@
#ifndef BASE_CONTAINERS_ADAPTERS_H_
#define BASE_CONTAINERS_ADAPTERS_H_
+#include <stddef.h>
+
+#include <iterator>
+
#include "base/macros.h"
namespace base {
@@ -15,11 +19,13 @@ namespace internal {
template <typename T>
class ReversedAdapter {
public:
- typedef decltype(static_cast<T*>(nullptr)->rbegin()) Iterator;
+ using Iterator = decltype(static_cast<T*>(nullptr)->rbegin());
explicit ReversedAdapter(T& t) : t_(t) {}
ReversedAdapter(const ReversedAdapter& ra) : t_(ra.t_) {}
+ // TODO(mdempsky): Once we can use C++14 library features, use std::rbegin
+ // and std::rend instead, so we can remove the specialization below.
Iterator begin() const { return t_.rbegin(); }
Iterator end() const { return t_.rend(); }
@@ -29,6 +35,23 @@ class ReversedAdapter {
DISALLOW_ASSIGN(ReversedAdapter);
};
+template <typename T, size_t N>
+class ReversedAdapter<T[N]> {
+ public:
+ using Iterator = std::reverse_iterator<T*>;
+
+ explicit ReversedAdapter(T (&t)[N]) : t_(t) {}
+ ReversedAdapter(const ReversedAdapter& ra) : t_(ra.t_) {}
+
+ Iterator begin() const { return Iterator(&t_[N]); }
+ Iterator end() const { return Iterator(&t_[0]); }
+
+ private:
+ T (&t_)[N];
+
+ DISALLOW_ASSIGN(ReversedAdapter);
+};
+
} // namespace internal
// Reversed returns a container adapter usable in a range-based "for" statement
diff --git a/chromium/base/containers/adapters_unittest.cc b/chromium/base/containers/adapters_unittest.cc
index 4c874722b3f..92554b7e1e1 100644
--- a/chromium/base/containers/adapters_unittest.cc
+++ b/chromium/base/containers/adapters_unittest.cc
@@ -25,7 +25,19 @@ TEST(AdaptersTest, Reversed) {
EXPECT_EQ(101, v[2]);
}
-TEST(AdaptersTest, ConstReversed) {
+TEST(AdaptersTest, ReversedArray) {
+ int v[3] = {3, 2, 1};
+ int j = 0;
+ for (int& i : base::Reversed(v)) {
+ EXPECT_EQ(++j, i);
+ i += 100;
+ }
+ EXPECT_EQ(103, v[0]);
+ EXPECT_EQ(102, v[1]);
+ EXPECT_EQ(101, v[2]);
+}
+
+TEST(AdaptersTest, ReversedConst) {
std::vector<int> v;
v.push_back(3);
v.push_back(2);
diff --git a/chromium/base/containers/hash_tables.h b/chromium/base/containers/hash_tables.h
index 5ce91619172..c421dddf3e7 100644
--- a/chromium/base/containers/hash_tables.h
+++ b/chromium/base/containers/hash_tables.h
@@ -21,9 +21,11 @@
#ifndef BASE_CONTAINERS_HASH_TABLES_H_
#define BASE_CONTAINERS_HASH_TABLES_H_
+#include <stddef.h>
+#include <stdint.h>
+
#include <utility>
-#include "base/basictypes.h"
#include "base/strings/string16.h"
#include "build/build_config.h"
@@ -196,19 +198,19 @@ using hash_set = BASE_HASH_IMPL_NAMESPACE::hash_set<Key, Hash, Pred, Alloc>;
// h32(x32, y32) = (h64(x32, y32) * rand_odd64 + rand16 * 2^16) % 2^64 / 2^32
//
// Contact danakj@chromium.org for any questions.
-inline std::size_t HashInts32(uint32 value1, uint32 value2) {
- uint64 value1_64 = value1;
- uint64 hash64 = (value1_64 << 32) | value2;
+inline std::size_t HashInts32(uint32_t value1, uint32_t value2) {
+ uint64_t value1_64 = value1;
+ uint64_t hash64 = (value1_64 << 32) | value2;
- if (sizeof(std::size_t) >= sizeof(uint64))
+ if (sizeof(std::size_t) >= sizeof(uint64_t))
return static_cast<std::size_t>(hash64);
- uint64 odd_random = 481046412LL << 32 | 1025306955LL;
- uint32 shift_random = 10121U << 16;
+ uint64_t odd_random = 481046412LL << 32 | 1025306955LL;
+ uint32_t shift_random = 10121U << 16;
hash64 = hash64 * odd_random + shift_random;
std::size_t high_bits = static_cast<std::size_t>(
- hash64 >> (8 * (sizeof(uint64) - sizeof(std::size_t))));
+ hash64 >> (8 * (sizeof(uint64_t) - sizeof(std::size_t))));
return high_bits;
}
@@ -217,87 +219,46 @@ inline std::size_t HashInts32(uint32 value1, uint32 value2) {
// breaking the two 64-bit inputs into 4 32-bit values:
// http://opendatastructures.org/versions/edition-0.1d/ods-java/node33.html#SECTION00832000000000000000
// Then we reduce our result to 32 bits if required, similar to above.
-inline std::size_t HashInts64(uint64 value1, uint64 value2) {
- uint32 short_random1 = 842304669U;
- uint32 short_random2 = 619063811U;
- uint32 short_random3 = 937041849U;
- uint32 short_random4 = 3309708029U;
+inline std::size_t HashInts64(uint64_t value1, uint64_t value2) {
+ uint32_t short_random1 = 842304669U;
+ uint32_t short_random2 = 619063811U;
+ uint32_t short_random3 = 937041849U;
+ uint32_t short_random4 = 3309708029U;
- uint32 value1a = static_cast<uint32>(value1 & 0xffffffff);
- uint32 value1b = static_cast<uint32>((value1 >> 32) & 0xffffffff);
- uint32 value2a = static_cast<uint32>(value2 & 0xffffffff);
- uint32 value2b = static_cast<uint32>((value2 >> 32) & 0xffffffff);
+ uint32_t value1a = static_cast<uint32_t>(value1 & 0xffffffff);
+ uint32_t value1b = static_cast<uint32_t>((value1 >> 32) & 0xffffffff);
+ uint32_t value2a = static_cast<uint32_t>(value2 & 0xffffffff);
+ uint32_t value2b = static_cast<uint32_t>((value2 >> 32) & 0xffffffff);
- uint64 product1 = static_cast<uint64>(value1a) * short_random1;
- uint64 product2 = static_cast<uint64>(value1b) * short_random2;
- uint64 product3 = static_cast<uint64>(value2a) * short_random3;
- uint64 product4 = static_cast<uint64>(value2b) * short_random4;
+ uint64_t product1 = static_cast<uint64_t>(value1a) * short_random1;
+ uint64_t product2 = static_cast<uint64_t>(value1b) * short_random2;
+ uint64_t product3 = static_cast<uint64_t>(value2a) * short_random3;
+ uint64_t product4 = static_cast<uint64_t>(value2b) * short_random4;
- uint64 hash64 = product1 + product2 + product3 + product4;
+ uint64_t hash64 = product1 + product2 + product3 + product4;
- if (sizeof(std::size_t) >= sizeof(uint64))
+ if (sizeof(std::size_t) >= sizeof(uint64_t))
return static_cast<std::size_t>(hash64);
- uint64 odd_random = 1578233944LL << 32 | 194370989LL;
- uint32 shift_random = 20591U << 16;
+ uint64_t odd_random = 1578233944LL << 32 | 194370989LL;
+ uint32_t shift_random = 20591U << 16;
hash64 = hash64 * odd_random + shift_random;
std::size_t high_bits = static_cast<std::size_t>(
- hash64 >> (8 * (sizeof(uint64) - sizeof(std::size_t))));
+ hash64 >> (8 * (sizeof(uint64_t) - sizeof(std::size_t))));
return high_bits;
}
-#define DEFINE_32BIT_PAIR_HASH(Type1, Type2) \
-inline std::size_t HashPair(Type1 value1, Type2 value2) { \
- return HashInts32(value1, value2); \
-}
+template<typename T1, typename T2>
+inline std::size_t HashPair(T1 value1, T2 value2) {
+ // This condition is expected to be compile-time evaluated and optimised away
+ // in release builds.
+ if (sizeof(T1) > sizeof(uint32_t) || (sizeof(T2) > sizeof(uint32_t)))
+ return HashInts64(value1, value2);
-DEFINE_32BIT_PAIR_HASH(int16, int16);
-DEFINE_32BIT_PAIR_HASH(int16, uint16);
-DEFINE_32BIT_PAIR_HASH(int16, int32);
-DEFINE_32BIT_PAIR_HASH(int16, uint32);
-DEFINE_32BIT_PAIR_HASH(uint16, int16);
-DEFINE_32BIT_PAIR_HASH(uint16, uint16);
-DEFINE_32BIT_PAIR_HASH(uint16, int32);
-DEFINE_32BIT_PAIR_HASH(uint16, uint32);
-DEFINE_32BIT_PAIR_HASH(int32, int16);
-DEFINE_32BIT_PAIR_HASH(int32, uint16);
-DEFINE_32BIT_PAIR_HASH(int32, int32);
-DEFINE_32BIT_PAIR_HASH(int32, uint32);
-DEFINE_32BIT_PAIR_HASH(uint32, int16);
-DEFINE_32BIT_PAIR_HASH(uint32, uint16);
-DEFINE_32BIT_PAIR_HASH(uint32, int32);
-DEFINE_32BIT_PAIR_HASH(uint32, uint32);
-
-#undef DEFINE_32BIT_PAIR_HASH
-
-#define DEFINE_64BIT_PAIR_HASH(Type1, Type2) \
-inline std::size_t HashPair(Type1 value1, Type2 value2) { \
- return HashInts64(value1, value2); \
+ return HashInts32(value1, value2);
}
-DEFINE_64BIT_PAIR_HASH(int16, int64);
-DEFINE_64BIT_PAIR_HASH(int16, uint64);
-DEFINE_64BIT_PAIR_HASH(uint16, int64);
-DEFINE_64BIT_PAIR_HASH(uint16, uint64);
-DEFINE_64BIT_PAIR_HASH(int32, int64);
-DEFINE_64BIT_PAIR_HASH(int32, uint64);
-DEFINE_64BIT_PAIR_HASH(uint32, int64);
-DEFINE_64BIT_PAIR_HASH(uint32, uint64);
-DEFINE_64BIT_PAIR_HASH(int64, int16);
-DEFINE_64BIT_PAIR_HASH(int64, uint16);
-DEFINE_64BIT_PAIR_HASH(int64, int32);
-DEFINE_64BIT_PAIR_HASH(int64, uint32);
-DEFINE_64BIT_PAIR_HASH(int64, int64);
-DEFINE_64BIT_PAIR_HASH(int64, uint64);
-DEFINE_64BIT_PAIR_HASH(uint64, int16);
-DEFINE_64BIT_PAIR_HASH(uint64, uint16);
-DEFINE_64BIT_PAIR_HASH(uint64, int32);
-DEFINE_64BIT_PAIR_HASH(uint64, uint32);
-DEFINE_64BIT_PAIR_HASH(uint64, int64);
-DEFINE_64BIT_PAIR_HASH(uint64, uint64);
-
-#undef DEFINE_64BIT_PAIR_HASH
} // namespace base
namespace BASE_HASH_NAMESPACE {
diff --git a/chromium/base/containers/hash_tables_unittest.cc b/chromium/base/containers/hash_tables_unittest.cc
index f775dff15a8..6072e5dc91e 100644
--- a/chromium/base/containers/hash_tables_unittest.cc
+++ b/chromium/base/containers/hash_tables_unittest.cc
@@ -7,7 +7,6 @@
#include <stdint.h>
#include <string>
-#include "base/basictypes.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
@@ -25,27 +24,27 @@ class HashPairTest : public testing::Test {
// Verify that a hash_map can be constructed for pairs of integers of various
// sizes.
TEST_F(HashPairTest, IntegerPairs) {
- typedef std::pair<int16, int16> Int16Int16Pair;
- typedef std::pair<int16, int32> Int16Int32Pair;
- typedef std::pair<int16, int64> Int16Int64Pair;
+ typedef std::pair<int16_t, int16_t> Int16Int16Pair;
+ typedef std::pair<int16_t, int32_t> Int16Int32Pair;
+ typedef std::pair<int16_t, int64_t> Int16Int64Pair;
INSERT_PAIR_TEST(Int16Int16Pair, 4, 6);
INSERT_PAIR_TEST(Int16Int32Pair, 9, (1 << 29) + 378128932);
INSERT_PAIR_TEST(Int16Int64Pair, 10,
(INT64_C(1) << 60) + INT64_C(78931732321));
- typedef std::pair<int32, int16> Int32Int16Pair;
- typedef std::pair<int32, int32> Int32Int32Pair;
- typedef std::pair<int32, int64> Int32Int64Pair;
+ typedef std::pair<int32_t, int16_t> Int32Int16Pair;
+ typedef std::pair<int32_t, int32_t> Int32Int32Pair;
+ typedef std::pair<int32_t, int64_t> Int32Int64Pair;
INSERT_PAIR_TEST(Int32Int16Pair, 4, 6);
INSERT_PAIR_TEST(Int32Int32Pair, 9, (1 << 29) + 378128932);
INSERT_PAIR_TEST(Int32Int64Pair, 10,
(INT64_C(1) << 60) + INT64_C(78931732321));
- typedef std::pair<int64, int16> Int64Int16Pair;
- typedef std::pair<int64, int32> Int64Int32Pair;
- typedef std::pair<int64, int64> Int64Int64Pair;
+ typedef std::pair<int64_t, int16_t> Int64Int16Pair;
+ typedef std::pair<int64_t, int32_t> Int64Int32Pair;
+ typedef std::pair<int64_t, int64_t> Int64Int64Pair;
INSERT_PAIR_TEST(Int64Int16Pair, 4, 6);
INSERT_PAIR_TEST(Int64Int32Pair, 9, (1 << 29) + 378128932);
diff --git a/chromium/base/containers/linked_list_unittest.cc b/chromium/base/containers/linked_list_unittest.cc
index 93a9f385084..f4ecc71066f 100644
--- a/chromium/base/containers/linked_list_unittest.cc
+++ b/chromium/base/containers/linked_list_unittest.cc
@@ -2,8 +2,8 @@
// 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/containers/linked_list.h"
+#include "base/macros.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
diff --git a/chromium/base/containers/mru_cache.h b/chromium/base/containers/mru_cache.h
index ed1ad251a2f..272a773c883 100644
--- a/chromium/base/containers/mru_cache.h
+++ b/chromium/base/containers/mru_cache.h
@@ -16,13 +16,16 @@
#ifndef BASE_CONTAINERS_MRU_CACHE_H_
#define BASE_CONTAINERS_MRU_CACHE_H_
+#include <stddef.h>
+
+#include <algorithm>
#include <list>
#include <map>
#include <utility>
-#include "base/basictypes.h"
#include "base/containers/hash_tables.h"
#include "base/logging.h"
+#include "base/macros.h"
namespace base {
@@ -137,6 +140,14 @@ class MRUCacheBase {
return index_iter->second;
}
+ // Exchanges the contents of |this| by the contents of the |other|.
+ void Swap(MRUCacheBase& other) {
+ ordering_.swap(other.ordering_);
+ index_.swap(other.index_);
+ std::swap(deletor_, other.deletor_);
+ std::swap(max_size_, other.max_size_);
+ }
+
// Erases the item referenced by the given iterator. An iterator to the item
// following it will be returned. The iterator must be valid.
iterator Erase(iterator pos) {
diff --git a/chromium/base/containers/mru_cache_unittest.cc b/chromium/base/containers/mru_cache_unittest.cc
index a8e893213cc..8ebecdb7b62 100644
--- a/chromium/base/containers/mru_cache_unittest.cc
+++ b/chromium/base/containers/mru_cache_unittest.cc
@@ -2,7 +2,8 @@
// 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 <stddef.h>
+
#include "base/containers/mru_cache.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -269,3 +270,107 @@ TEST(MRUCacheTest, HashingMRUCache) {
EXPECT_EQ(two.value, cache.Get("Second")->second.value);
EXPECT_TRUE(cache.Get("First") == cache.end());
}
+
+TEST(MRUCacheTest, Swap) {
+ typedef base::MRUCache<int, CachedItem> Cache;
+ Cache cache1(Cache::NO_AUTO_EVICT);
+
+ // Insert two items into cache1.
+ static const int kItem1Key = 1;
+ CachedItem item1(2);
+ Cache::iterator inserted_item = cache1.Put(kItem1Key, item1);
+ EXPECT_EQ(1U, cache1.size());
+
+ static const int kItem2Key = 3;
+ CachedItem item2(4);
+ cache1.Put(kItem2Key, item2);
+ EXPECT_EQ(2U, cache1.size());
+
+ // Verify cache1's elements.
+ {
+ Cache::iterator iter = cache1.begin();
+ ASSERT_TRUE(iter != cache1.end());
+ EXPECT_EQ(kItem2Key, iter->first);
+ EXPECT_EQ(item2.value, iter->second.value);
+
+ ++iter;
+ ASSERT_TRUE(iter != cache1.end());
+ EXPECT_EQ(kItem1Key, iter->first);
+ EXPECT_EQ(item1.value, iter->second.value);
+ }
+
+ // Create another cache2.
+ Cache cache2(Cache::NO_AUTO_EVICT);
+
+ // Insert three items into cache2.
+ static const int kItem3Key = 5;
+ CachedItem item3(6);
+ inserted_item = cache2.Put(kItem3Key, item3);
+ EXPECT_EQ(1U, cache2.size());
+
+ static const int kItem4Key = 7;
+ CachedItem item4(8);
+ cache2.Put(kItem4Key, item4);
+ EXPECT_EQ(2U, cache2.size());
+
+ static const int kItem5Key = 9;
+ CachedItem item5(10);
+ cache2.Put(kItem5Key, item5);
+ EXPECT_EQ(3U, cache2.size());
+
+ // Verify cache2's elements.
+ {
+ Cache::iterator iter = cache2.begin();
+ ASSERT_TRUE(iter != cache2.end());
+ EXPECT_EQ(kItem5Key, iter->first);
+ EXPECT_EQ(item5.value, iter->second.value);
+
+ ++iter;
+ ASSERT_TRUE(iter != cache2.end());
+ EXPECT_EQ(kItem4Key, iter->first);
+ EXPECT_EQ(item4.value, iter->second.value);
+
+ ++iter;
+ ASSERT_TRUE(iter != cache2.end());
+ EXPECT_EQ(kItem3Key, iter->first);
+ EXPECT_EQ(item3.value, iter->second.value);
+ }
+
+ // Swap cache1 and cache2 and verify cache2 has cache1's elements and cache1
+ // has cache2's elements.
+ cache2.Swap(cache1);
+
+ EXPECT_EQ(3U, cache1.size());
+ EXPECT_EQ(2U, cache2.size());
+
+ // Verify cache1's elements.
+ {
+ Cache::iterator iter = cache1.begin();
+ ASSERT_TRUE(iter != cache1.end());
+ EXPECT_EQ(kItem5Key, iter->first);
+ EXPECT_EQ(item5.value, iter->second.value);
+
+ ++iter;
+ ASSERT_TRUE(iter != cache1.end());
+ EXPECT_EQ(kItem4Key, iter->first);
+ EXPECT_EQ(item4.value, iter->second.value);
+
+ ++iter;
+ ASSERT_TRUE(iter != cache1.end());
+ EXPECT_EQ(kItem3Key, iter->first);
+ EXPECT_EQ(item3.value, iter->second.value);
+ }
+
+ // Verify cache2's elements.
+ {
+ Cache::iterator iter = cache2.begin();
+ ASSERT_TRUE(iter != cache2.end());
+ EXPECT_EQ(kItem2Key, iter->first);
+ EXPECT_EQ(item2.value, iter->second.value);
+
+ ++iter;
+ ASSERT_TRUE(iter != cache2.end());
+ EXPECT_EQ(kItem1Key, iter->first);
+ EXPECT_EQ(item1.value, iter->second.value);
+ }
+}
diff --git a/chromium/base/containers/scoped_ptr_hash_map.h b/chromium/base/containers/scoped_ptr_hash_map.h
index 8fe550e7317..189c3149f3a 100644
--- a/chromium/base/containers/scoped_ptr_hash_map.h
+++ b/chromium/base/containers/scoped_ptr_hash_map.h
@@ -5,12 +5,14 @@
#ifndef BASE_CONTAINERS_SCOPED_PTR_HASH_MAP_H_
#define BASE_CONTAINERS_SCOPED_PTR_HASH_MAP_H_
+#include <stddef.h>
+
#include <algorithm>
#include <utility>
-#include "base/basictypes.h"
#include "base/containers/hash_tables.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/stl_util.h"
@@ -57,7 +59,7 @@ class ScopedPtrHashMap {
std::pair<iterator, bool> result =
data_.insert(std::make_pair(key, data.get()));
if (result.second)
- ignore_result(data.release());
+ ::ignore_result(data.release());
return result;
}
@@ -82,7 +84,7 @@ class ScopedPtrHashMap {
ScopedPtr ret(it->second);
it->second = NULL;
- return ret.Pass();
+ return ret;
}
ScopedPtr take(const Key& k) {
@@ -100,7 +102,7 @@ class ScopedPtrHashMap {
ScopedPtr ret(it->second);
data_.erase(it);
- return ret.Pass();
+ return ret;
}
ScopedPtr take_and_erase(const Key& k) {
diff --git a/chromium/base/containers/scoped_ptr_hash_map_unittest.cc b/chromium/base/containers/scoped_ptr_hash_map_unittest.cc
index 88fe41f9a0d..38fc91a3840 100644
--- a/chromium/base/containers/scoped_ptr_hash_map_unittest.cc
+++ b/chromium/base/containers/scoped_ptr_hash_map_unittest.cc
@@ -10,6 +10,15 @@
namespace base {
namespace {
+namespace namespace_with_ignore_result {
+
+class Value {};
+
+template <typename T>
+void ignore_result(const T&) {}
+
+} // namespace namespace_with_ignore_result
+
struct DeleteCounter {
public:
DeleteCounter() {}
@@ -81,5 +90,13 @@ TEST(ScopedPtrHashMapTest, CustomDeleter) {
EXPECT_EQ(3, CountingDeleter::count());
}
+// Test that using a value type from a namespace containing an ignore_result
+// function compiles correctly.
+TEST(ScopedPtrHashMapTest, IgnoreResultCompile) {
+ ScopedPtrHashMap<int, scoped_ptr<namespace_with_ignore_result::Value>>
+ scoped_map;
+ scoped_map.add(1, make_scoped_ptr(new namespace_with_ignore_result::Value));
+}
+
} // namespace
} // namespace base
diff --git a/chromium/base/containers/scoped_ptr_map.h b/chromium/base/containers/scoped_ptr_map.h
deleted file mode 100644
index 622a39d121e..00000000000
--- a/chromium/base/containers/scoped_ptr_map.h
+++ /dev/null
@@ -1,144 +0,0 @@
-// 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_CONTAINERS_SCOPED_PTR_MAP_H_
-#define BASE_CONTAINERS_SCOPED_PTR_MAP_H_
-
-#include <functional>
-#include <map>
-#include <utility>
-
-#include "base/basictypes.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/move.h"
-#include "base/stl_util.h"
-
-namespace base {
-
-// ScopedPtrMap provides a std::map that supports scoped_ptr values. It ensures
-// that the map's values are properly deleted when removed from the map, or when
-// the map is destroyed.
-//
-// |ScopedPtr| must be a type scoped_ptr<T>. This is for compatibility with
-// std::map in C++11.
-template <class Key, class ScopedPtr, class Compare = std::less<Key>>
-class ScopedPtrMap {
- MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(ScopedPtrMap)
-
- using Container = std::map<Key, typename ScopedPtr::element_type*, Compare>;
-
- public:
- using allocator_type = typename Container::allocator_type;
- using size_type = typename Container::size_type;
- using difference_type = typename Container::difference_type;
- using reference = typename Container::reference;
- using const_reference = typename Container::const_reference;
- using key_type = typename Container::key_type;
- using mapped_type = ScopedPtr;
- using key_compare = typename Container::key_compare;
- using const_iterator = typename Container::const_iterator;
- using const_reverse_iterator = typename Container::const_reverse_iterator;
-
- ScopedPtrMap() {}
- ~ScopedPtrMap() { clear(); }
- ScopedPtrMap(ScopedPtrMap&& other) { swap(other); }
-
- ScopedPtrMap& operator=(ScopedPtrMap&& rhs) {
- swap(rhs);
- return *this;
- }
-
- const_iterator find(const Key& k) const { return data_.find(k); }
- size_type count(const Key& k) const { return data_.count(k); }
-
- bool empty() const { return data_.empty(); }
- size_t size() const { return data_.size(); }
-
- const_reverse_iterator rbegin() const { return data_.rbegin(); }
- const_reverse_iterator rend() const { return data_.rend(); }
-
- const_iterator begin() const { return data_.begin(); }
- const_iterator end() const { return data_.end(); }
-
- void swap(ScopedPtrMap& other) { data_.swap(other.data_); }
-
- void clear() { STLDeleteValues(&data_); }
-
- // Inserts |val| into the map, associated with |key|.
- std::pair<const_iterator, bool> insert(const Key& key, ScopedPtr val) {
- auto result = data_.insert(std::make_pair(key, val.get()));
- if (result.second)
- ignore_result(val.release());
- return result;
- }
-
- // Inserts |val| into the map, associated with |key|. Overwrites any existing
- // element at |key|.
- void set(const Key& key, ScopedPtr val) {
- typename ScopedPtr::element_type*& val_ref = data_[key];
- delete val_ref;
- val_ref = val.release();
- }
-
- void erase(const_iterator position) {
- DCHECK(position != end());
- delete position->second;
- // Key-based lookup (cannot use const_iterator overload in C++03 library).
- data_.erase(position->first);
- }
-
- size_type erase(const Key& k) {
- typename Container::iterator it = data_.find(k);
- if (it == end())
- return 0;
-
- delete it->second;
- data_.erase(it);
- return 1;
- }
-
- void erase(const_iterator first, const_iterator last) {
- STLDeleteContainerPairSecondPointers(first, last);
- // Need non-const iterators as required by the C++03 library.
- data_.erase(ConstIteratorToIterator(first), ConstIteratorToIterator(last));
- }
-
- // Like |erase()|, but returns the element instead of deleting it.
- ScopedPtr take_and_erase(const_iterator position) {
- DCHECK(position != end());
- if (position == end())
- return ScopedPtr();
-
- ScopedPtr ret(position->second);
- // Key-based lookup (cannot use const_iterator overload in C++03 library).
- data_.erase(position->first);
- return ret.Pass();
- }
-
- // Like |erase()|, but returns the element instead of deleting it.
- ScopedPtr take_and_erase(const Key& k) {
- typename Container::iterator it = data_.find(k);
- if (it == end())
- return ScopedPtr();
-
- ScopedPtr ret(it->second);
- data_.erase(it);
- return ret.Pass();
- }
-
- private:
- Container data_;
-
- typename Container::iterator ConstIteratorToIterator(const_iterator it) {
- // This is the only way to convert a const iterator to a non-const iterator
- // in C++03 (get the key and do the lookup again).
- if (it == data_.end())
- return data_.end();
- return data_.find(it->first);
- };
-};
-
-} // namespace base
-
-#endif // BASE_CONTAINERS_SCOPED_PTR_MAP_H_
diff --git a/chromium/base/containers/scoped_ptr_map_unittest.cc b/chromium/base/containers/scoped_ptr_map_unittest.cc
deleted file mode 100644
index 706b2edfb18..00000000000
--- a/chromium/base/containers/scoped_ptr_map_unittest.cc
+++ /dev/null
@@ -1,255 +0,0 @@
-// 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_map.h"
-
-#include <functional>
-#include <map>
-#include <utility>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/memory/scoped_ptr.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace base {
-namespace {
-
-// A ScopedDestroyer sets a Boolean to true upon destruction.
-class ScopedDestroyer {
- public:
- ScopedDestroyer(bool* destroyed) : destroyed_(destroyed) {
- *destroyed_ = false;
- }
-
- ~ScopedDestroyer() { *destroyed_ = true; }
-
- private:
- bool* destroyed_;
-};
-
-TEST(ScopedPtrMapTest, Insert) {
- bool destroyed1 = false;
- bool destroyed2 = false;
- {
- ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
-
- // Insert to new key.
- ScopedDestroyer* elem1 = new ScopedDestroyer(&destroyed1);
- EXPECT_FALSE(destroyed1);
- EXPECT_TRUE(scoped_map.insert(0, make_scoped_ptr(elem1)).second);
- EXPECT_EQ(elem1, scoped_map.find(0)->second);
- EXPECT_FALSE(destroyed1);
-
- // Insert to existing key.
- ScopedDestroyer* elem2 = new ScopedDestroyer(&destroyed2);
- EXPECT_FALSE(destroyed2);
- EXPECT_FALSE(scoped_map.insert(0, make_scoped_ptr(elem2)).second);
- EXPECT_EQ(elem1, scoped_map.find(0)->second);
-
- EXPECT_FALSE(destroyed1);
- EXPECT_TRUE(destroyed2);
- }
- EXPECT_TRUE(destroyed1);
-}
-
-TEST(ScopedPtrMapTest, Set) {
- bool destroyed1 = false;
- bool destroyed2 = false;
- {
- ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
-
- // Set a new key.
- ScopedDestroyer* elem1 = new ScopedDestroyer(&destroyed1);
- EXPECT_FALSE(destroyed1);
- scoped_map.set(0, make_scoped_ptr(elem1));
- EXPECT_EQ(elem1, scoped_map.find(0)->second);
- EXPECT_FALSE(destroyed1);
-
- // Set to replace an existing key.
- ScopedDestroyer* elem2 = new ScopedDestroyer(&destroyed2);
- EXPECT_FALSE(destroyed2);
- scoped_map.set(0, make_scoped_ptr(elem2));
- EXPECT_EQ(elem2, scoped_map.find(0)->second);
-
- EXPECT_TRUE(destroyed1);
- EXPECT_FALSE(destroyed2);
- }
- EXPECT_TRUE(destroyed1);
- EXPECT_TRUE(destroyed2);
-}
-
-TEST(ScopedPtrMapTest, EraseIterator) {
- bool destroyed = false;
- ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
- scoped_map.insert(0, make_scoped_ptr(new ScopedDestroyer(&destroyed)));
- EXPECT_FALSE(destroyed);
- scoped_map.erase(scoped_map.find(0));
- EXPECT_TRUE(destroyed);
- EXPECT_TRUE(scoped_map.empty());
-}
-
-TEST(ScopedPtrMapTest, EraseKey) {
- bool destroyed = false;
- ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
- scoped_map.insert(0, make_scoped_ptr(new ScopedDestroyer(&destroyed)));
- EXPECT_FALSE(destroyed);
- EXPECT_EQ(1u, scoped_map.erase(0));
- EXPECT_TRUE(destroyed);
- EXPECT_TRUE(scoped_map.empty());
-
- // Test erase of a non-existent key.
- EXPECT_EQ(0u, scoped_map.erase(7));
-}
-
-TEST(ScopedPtrMapTest, EraseRange) {
- bool destroyed1 = false;
- bool destroyed2 = false;
- ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
-
- scoped_map.insert(0, make_scoped_ptr(new ScopedDestroyer(&destroyed1)));
- EXPECT_FALSE(destroyed1);
-
- scoped_map.insert(1, make_scoped_ptr(new ScopedDestroyer(&destroyed2)));
- EXPECT_FALSE(destroyed2);
-
- scoped_map.erase(scoped_map.find(0), scoped_map.end());
- EXPECT_TRUE(destroyed1);
- EXPECT_TRUE(destroyed2);
- EXPECT_TRUE(scoped_map.empty());
-}
-
-TEST(ScopedPtrMapTest, TakeAndErase) {
- bool destroyed = false;
- ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
- ScopedDestroyer* elem = new ScopedDestroyer(&destroyed);
- scoped_map.insert(0, make_scoped_ptr(elem));
- EXPECT_EQ(elem, scoped_map.find(0)->second);
- EXPECT_FALSE(destroyed);
- scoped_ptr<ScopedDestroyer> object = scoped_map.take_and_erase(0);
- EXPECT_EQ(elem, object.get());
- EXPECT_FALSE(destroyed);
- EXPECT_TRUE(scoped_map.empty());
- object.reset();
- EXPECT_TRUE(destroyed);
-}
-
-TEST(ScopedPtrMapTest, Clear) {
- bool destroyed = false;
- ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
- scoped_map.insert(0, make_scoped_ptr(new ScopedDestroyer(&destroyed)));
- EXPECT_FALSE(destroyed);
- scoped_map.clear();
- EXPECT_TRUE(destroyed);
- EXPECT_TRUE(scoped_map.empty());
-}
-
-TEST(ScopedPtrMapTest, Compare) {
- // Construct a ScopedPtrMap with a custom comparison function.
- ScopedPtrMap<int, scoped_ptr<int>, std::greater<int>> scoped_map1;
- scoped_map1.insert(0, make_scoped_ptr(new int(0)));
- scoped_map1.insert(1, make_scoped_ptr(new int(0)));
-
- auto it = scoped_map1.begin();
- EXPECT_EQ(1, it->first);
- ++it;
- EXPECT_EQ(0, it->first);
-
- // Test the move constructor.
- ScopedPtrMap<int, scoped_ptr<int>, std::greater<int>> scoped_map2(
- scoped_map1.Pass());
- EXPECT_EQ(2u, scoped_map2.size());
- EXPECT_TRUE(scoped_map1.empty());
-
- // Test move assignment.
- scoped_map1 = scoped_map2.Pass();
- EXPECT_EQ(2u, scoped_map1.size());
- EXPECT_TRUE(scoped_map2.empty());
-
- // Test swap.
- scoped_map2.swap(scoped_map1);
- EXPECT_EQ(2u, scoped_map2.size());
- EXPECT_TRUE(scoped_map1.empty());
-}
-
-TEST(ScopedPtrMapTest, Scope) {
- bool destroyed = false;
- {
- ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
- scoped_map.insert(0, make_scoped_ptr(new ScopedDestroyer(&destroyed)));
- EXPECT_FALSE(destroyed);
- }
- EXPECT_TRUE(destroyed);
-}
-
-TEST(ScopedPtrMapTest, MoveConstruct) {
- bool destroyed = false;
- {
- ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
- ScopedDestroyer* elem = new ScopedDestroyer(&destroyed);
- scoped_map.insert(0, make_scoped_ptr(elem));
- EXPECT_EQ(elem, scoped_map.find(0)->second);
- EXPECT_FALSE(destroyed);
- EXPECT_FALSE(scoped_map.empty());
-
- ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map_copy(
- scoped_map.Pass());
- EXPECT_TRUE(scoped_map.empty());
- EXPECT_FALSE(scoped_map_copy.empty());
- EXPECT_EQ(elem, scoped_map_copy.find(0)->second);
- EXPECT_FALSE(destroyed);
- }
- EXPECT_TRUE(destroyed);
-}
-
-TEST(ScopedPtrMapTest, MoveAssign) {
- bool destroyed = false;
- {
- ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
- ScopedDestroyer* elem = new ScopedDestroyer(&destroyed);
- scoped_map.insert(0, make_scoped_ptr(elem));
- EXPECT_EQ(elem, scoped_map.find(0)->second);
- EXPECT_FALSE(destroyed);
- EXPECT_FALSE(scoped_map.empty());
-
- ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map_assign;
- scoped_map_assign = scoped_map.Pass();
- EXPECT_TRUE(scoped_map.empty());
- EXPECT_FALSE(scoped_map_assign.empty());
- EXPECT_EQ(elem, scoped_map_assign.find(0)->second);
- EXPECT_FALSE(destroyed);
- }
- EXPECT_TRUE(destroyed);
-}
-
-template <typename Key, typename ScopedPtr>
-ScopedPtrMap<Key, ScopedPtr> PassThru(ScopedPtrMap<Key, ScopedPtr> scoper) {
- return scoper;
-}
-
-TEST(ScopedPtrMapTest, Passed) {
- bool destroyed = false;
- ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> scoped_map;
- ScopedDestroyer* elem = new ScopedDestroyer(&destroyed);
- scoped_map.insert(0, make_scoped_ptr(elem));
- EXPECT_EQ(elem, scoped_map.find(0)->second);
- EXPECT_FALSE(destroyed);
-
- base::Callback<ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>>(void)>
- callback = base::Bind(&PassThru<int, scoped_ptr<ScopedDestroyer>>,
- base::Passed(&scoped_map));
- EXPECT_TRUE(scoped_map.empty());
- EXPECT_FALSE(destroyed);
-
- ScopedPtrMap<int, scoped_ptr<ScopedDestroyer>> result = callback.Run();
- EXPECT_TRUE(scoped_map.empty());
- EXPECT_EQ(elem, result.find(0)->second);
- EXPECT_FALSE(destroyed);
-
- result.clear();
- EXPECT_TRUE(destroyed);
-};
-
-} // namespace
-} // namespace base
diff --git a/chromium/base/containers/small_map.h b/chromium/base/containers/small_map.h
index df3d22ae9ab..427736ca8c2 100644
--- a/chromium/base/containers/small_map.h
+++ b/chromium/base/containers/small_map.h
@@ -5,11 +5,12 @@
#ifndef BASE_CONTAINERS_SMALL_MAP_H_
#define BASE_CONTAINERS_SMALL_MAP_H_
+#include <stddef.h>
+
#include <map>
#include <string>
#include <utility>
-#include "base/basictypes.h"
#include "base/containers/hash_tables.h"
#include "base/logging.h"
#include "base/memory/manual_constructor.h"
@@ -187,7 +188,7 @@ class SmallMap {
// particular, gcc 2.95.3 does it but later versions allow 0-length
// arrays. Therefore, we explicitly reject non-positive kArraySize
// here.
- COMPILE_ASSERT(kArraySize > 0, default_initial_size_should_be_positive);
+ static_assert(kArraySize > 0, "default initial size should be positive");
public:
typedef typename NormalMap::key_type key_type;
diff --git a/chromium/base/containers/stack_container.h b/chromium/base/containers/stack_container.h
index 54090d3cd99..9e0efc13b41 100644
--- a/chromium/base/containers/stack_container.h
+++ b/chromium/base/containers/stack_container.h
@@ -5,10 +5,12 @@
#ifndef BASE_CONTAINERS_STACK_CONTAINER_H_
#define BASE_CONTAINERS_STACK_CONTAINER_H_
+#include <stddef.h>
+
#include <string>
#include <vector>
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/memory/aligned_memory.h"
#include "base/strings/string16.h"
#include "build/build_config.h"
@@ -57,7 +59,7 @@ class StackAllocator : public std::allocator<T> {
// buffer of the right size instead.
base::AlignedMemory<sizeof(T[stack_capacity]), ALIGNOF(T)> stack_buffer_;
#if defined(__GNUC__) && !defined(ARCH_CPU_X86_FAMILY)
- COMPILE_ASSERT(ALIGNOF(T) <= 16, crbug_115612);
+ static_assert(ALIGNOF(T) <= 16, "http://crbug.com/115612");
#endif
// Set when the stack buffer is used for an allocation. We do not track
diff --git a/chromium/base/containers/stack_container_unittest.cc b/chromium/base/containers/stack_container_unittest.cc
index e6c19145bf6..05c733a4a79 100644
--- a/chromium/base/containers/stack_container_unittest.cc
+++ b/chromium/base/containers/stack_container_unittest.cc
@@ -4,10 +4,13 @@
#include "base/containers/stack_container.h"
+#include <stddef.h>
+
#include <algorithm>
#include "base/memory/aligned_memory.h"
#include "base/memory/ref_counted.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
diff --git a/chromium/base/cpu.cc b/chromium/base/cpu.cc
index edba2c21988..71354456643 100644
--- a/chromium/base/cpu.cc
+++ b/chromium/base/cpu.cc
@@ -4,12 +4,15 @@
#include "base/cpu.h"
+#include <limits.h>
+#include <stddef.h>
+#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/strings/string_piece.h"
#include "build/build_config.h"
@@ -43,7 +46,6 @@ CPU::CPU()
has_sse41_(false),
has_sse42_(false),
has_avx_(false),
- has_avx_hardware_(false),
has_avx2_(false),
has_aesni_(false),
has_non_stop_time_stamp_counter_(false),
@@ -83,12 +85,12 @@ void __cpuid(int cpu_info[4], int info_type) {
// _xgetbv returns the value of an Intel Extended Control Register (XCR).
// Currently only XCR0 is defined by Intel so |xcr| should always be zero.
-uint64 _xgetbv(uint32 xcr) {
- uint32 eax, edx;
+uint64_t _xgetbv(uint32_t xcr) {
+ uint32_t eax, edx;
__asm__ volatile (
"xgetbv" : "=a"(eax), "=d"(edx) : "c"(xcr));
- return (static_cast<uint64>(edx) << 32) | eax;
+ return (static_cast<uint64_t>(edx) << 32) | eax;
}
#endif // !_MSC_VER
@@ -232,8 +234,6 @@ void CPU::Initialize() {
has_ssse3_ = (cpu_info[2] & 0x00000200) != 0;
has_sse41_ = (cpu_info[2] & 0x00080000) != 0;
has_sse42_ = (cpu_info[2] & 0x00100000) != 0;
- has_avx_hardware_ =
- (cpu_info[2] & 0x10000000) != 0;
// AVX instructions will generate an illegal instruction exception unless
// a) they are supported by the CPU,
// b) XSAVE is supported by the CPU and
@@ -245,7 +245,7 @@ void CPU::Initialize() {
// Because of that, we also test the XSAVE bit because its description in
// the CPUID documentation suggests that it signals xgetbv support.
has_avx_ =
- has_avx_hardware_ &&
+ (cpu_info[2] & 0x10000000) != 0 &&
(cpu_info[2] & 0x04000000) != 0 /* XSAVE */ &&
(cpu_info[2] & 0x08000000) != 0 /* OSXSAVE */ &&
(_xgetbv(0) & 6) == 6 /* XSAVE enabled by kernel */;
diff --git a/chromium/base/cpu.h b/chromium/base/cpu.h
index b3960782706..8c3c06c0444 100644
--- a/chromium/base/cpu.h
+++ b/chromium/base/cpu.h
@@ -48,12 +48,6 @@ class BASE_EXPORT CPU {
bool has_sse42() const { return has_sse42_; }
bool has_avx() const { return has_avx_; }
bool has_avx2() const { return has_avx2_; }
- // has_avx_hardware returns true when AVX is present in the CPU. This might
- // differ from the value of |has_avx()| because |has_avx()| also tests for
- // operating system support needed to actually call AVX instuctions.
- // Note: you should never need to call this function. It was added in order
- // to workaround a bug in NSS but |has_avx()| is what you want.
- bool has_avx_hardware() const { return has_avx_hardware_; }
bool has_aesni() const { return has_aesni_; }
bool has_non_stop_time_stamp_counter() const {
return has_non_stop_time_stamp_counter_;
@@ -85,7 +79,6 @@ class BASE_EXPORT CPU {
bool has_sse41_;
bool has_sse42_;
bool has_avx_;
- bool has_avx_hardware_;
bool has_avx2_;
bool has_aesni_;
bool has_non_stop_time_stamp_counter_;
diff --git a/chromium/base/cpu_unittest.cc b/chromium/base/cpu_unittest.cc
index 931509738fe..ec14620f98c 100644
--- a/chromium/base/cpu_unittest.cc
+++ b/chromium/base/cpu_unittest.cc
@@ -26,7 +26,7 @@ TEST(CPU, RunExtendedInstructions) {
ASSERT_TRUE(cpu.has_sse());
ASSERT_TRUE(cpu.has_sse2());
-// TODO(fbarchard): consider enabling for clangcl.
+// GCC and clang instruction test.
#if defined(COMPILER_GCC)
// Execute an MMX instruction.
__asm__ __volatile__("emms\n" : : : "mm0");
@@ -67,8 +67,9 @@ TEST(CPU, RunExtendedInstructions) {
__asm__ __volatile__("vpunpcklbw %%ymm0, %%ymm0, %%ymm0\n" : : : "xmm0");
}
-// TODO(jschuh): crbug.com/168866 Find a way to enable this on Win64.
-#elif defined(COMPILER_MSVC) && defined(ARCH_CPU_32_BITS)
+// Visual C 32 bit and ClangCL 32/64 bit test.
+#elif defined(COMPILER_MSVC) && (defined(ARCH_CPU_32_BITS) || \
+ (defined(ARCH_CPU_64_BITS) && defined(__clang__)))
// Execute an MMX instruction.
__asm emms;
diff --git a/chromium/base/critical_closure.h b/chromium/base/critical_closure.h
index 75e37045a77..6ebd7afa503 100644
--- a/chromium/base/critical_closure.h
+++ b/chromium/base/critical_closure.h
@@ -6,6 +6,8 @@
#define BASE_CRITICAL_CLOSURE_H_
#include "base/callback.h"
+#include "base/macros.h"
+#include "build/build_config.h"
#if defined(OS_IOS)
#include "base/bind.h"
diff --git a/chromium/base/debug/BUILD.gn b/chromium/base/debug/BUILD.gn
deleted file mode 100644
index 8ed623b03f9..00000000000
--- a/chromium/base/debug/BUILD.gn
+++ /dev/null
@@ -1,76 +0,0 @@
-# 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/asan_invalid_access.cc b/chromium/base/debug/asan_invalid_access.cc
index cee21066265..0abde8c0a32 100644
--- a/chromium/base/debug/asan_invalid_access.cc
+++ b/chromium/base/debug/asan_invalid_access.cc
@@ -2,14 +2,17 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#if defined(OS_WIN)
-#include <windows.h>
-#endif
+#include <stddef.h>
#include "base/debug/alias.h"
#include "base/debug/asan_invalid_access.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
namespace base {
namespace debug {
diff --git a/chromium/base/debug/close_handle_hook_win.cc b/chromium/base/debug/close_handle_hook_win.cc
new file mode 100644
index 00000000000..6ff6fa2d815
--- /dev/null
+++ b/chromium/base/debug/close_handle_hook_win.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/debug/close_handle_hook_win.h"
+
+#include <Windows.h>
+#include <psapi.h>
+#include <stddef.h>
+
+#include <algorithm>
+#include <vector>
+
+#include "base/lazy_instance.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/win/iat_patch_function.h"
+#include "base/win/pe_image.h"
+#include "base/win/scoped_handle.h"
+#include "build/build_config.h"
+
+namespace {
+
+typedef BOOL (WINAPI* CloseHandleType) (HANDLE handle);
+
+typedef BOOL (WINAPI* DuplicateHandleType)(HANDLE source_process,
+ HANDLE source_handle,
+ HANDLE target_process,
+ HANDLE* target_handle,
+ DWORD desired_access,
+ BOOL inherit_handle,
+ DWORD options);
+
+CloseHandleType g_close_function = NULL;
+DuplicateHandleType g_duplicate_function = NULL;
+
+// The entry point for CloseHandle interception. This function notifies the
+// verifier about the handle that is being closed, and calls the original
+// function.
+BOOL WINAPI CloseHandleHook(HANDLE handle) {
+ base::win::OnHandleBeingClosed(handle);
+ return g_close_function(handle);
+}
+
+BOOL WINAPI DuplicateHandleHook(HANDLE source_process,
+ HANDLE source_handle,
+ HANDLE target_process,
+ HANDLE* target_handle,
+ DWORD desired_access,
+ BOOL inherit_handle,
+ DWORD options) {
+ if ((options & DUPLICATE_CLOSE_SOURCE) &&
+ (GetProcessId(source_process) == ::GetCurrentProcessId())) {
+ base::win::OnHandleBeingClosed(source_handle);
+ }
+
+ return g_duplicate_function(source_process, source_handle, target_process,
+ target_handle, desired_access, inherit_handle,
+ options);
+}
+
+} // namespace
+
+namespace base {
+namespace debug {
+
+namespace {
+
+// Provides a simple way to temporarily change the protection of a memory page.
+class AutoProtectMemory {
+ public:
+ AutoProtectMemory()
+ : changed_(false), address_(NULL), bytes_(0), old_protect_(0) {}
+
+ ~AutoProtectMemory() {
+ RevertProtection();
+ }
+
+ // Grants write access to a given memory range.
+ bool ChangeProtection(void* address, size_t bytes);
+
+ // Restores the original page protection.
+ void RevertProtection();
+
+ private:
+ bool changed_;
+ void* address_;
+ size_t bytes_;
+ DWORD old_protect_;
+
+ DISALLOW_COPY_AND_ASSIGN(AutoProtectMemory);
+};
+
+bool AutoProtectMemory::ChangeProtection(void* address, size_t bytes) {
+ DCHECK(!changed_);
+ DCHECK(address);
+
+ // Change the page protection so that we can write.
+ MEMORY_BASIC_INFORMATION memory_info;
+ if (!VirtualQuery(address, &memory_info, sizeof(memory_info)))
+ return false;
+
+ DWORD is_executable = (PAGE_EXECUTE | PAGE_EXECUTE_READ |
+ PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY) &
+ memory_info.Protect;
+
+ DWORD protect = is_executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
+ if (!VirtualProtect(address, bytes, protect, &old_protect_))
+ return false;
+
+ changed_ = true;
+ address_ = address;
+ bytes_ = bytes;
+ return true;
+}
+
+void AutoProtectMemory::RevertProtection() {
+ if (!changed_)
+ return;
+
+ DCHECK(address_);
+ DCHECK(bytes_);
+
+ VirtualProtect(address_, bytes_, old_protect_, &old_protect_);
+ changed_ = false;
+ address_ = NULL;
+ bytes_ = 0;
+ old_protect_ = 0;
+}
+
+// Performs an EAT interception.
+void EATPatch(HMODULE module, const char* function_name,
+ void* new_function, void** old_function) {
+ if (!module)
+ return;
+
+ base::win::PEImage pe(module);
+ if (!pe.VerifyMagic())
+ return;
+
+ DWORD* eat_entry = pe.GetExportEntry(function_name);
+ if (!eat_entry)
+ return;
+
+ if (!(*old_function))
+ *old_function = pe.RVAToAddr(*eat_entry);
+
+ AutoProtectMemory memory;
+ if (!memory.ChangeProtection(eat_entry, sizeof(DWORD)))
+ return;
+
+ // Perform the patch.
+#pragma warning(push)
+#pragma warning(disable : 4311 4302)
+ // These casts generate truncation warnings because they are 32 bit specific.
+ *eat_entry = reinterpret_cast<DWORD>(new_function) -
+ reinterpret_cast<DWORD>(module);
+#pragma warning(pop)
+}
+
+// Performs an IAT interception.
+base::win::IATPatchFunction* IATPatch(HMODULE module, const char* function_name,
+ void* new_function, void** old_function) {
+ if (!module)
+ return NULL;
+
+ base::win::IATPatchFunction* patch = new base::win::IATPatchFunction;
+ __try {
+ // There is no guarantee that |module| is still loaded at this point.
+ if (patch->PatchFromModule(module, "kernel32.dll", function_name,
+ new_function)) {
+ delete patch;
+ return NULL;
+ }
+ } __except((GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ||
+ GetExceptionCode() == EXCEPTION_GUARD_PAGE ||
+ GetExceptionCode() == EXCEPTION_IN_PAGE_ERROR) ?
+ EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
+ // Leak the patch.
+ return NULL;
+ }
+
+ if (!(*old_function)) {
+ // Things are probably messed up if each intercepted function points to
+ // a different place, but we need only one function to call.
+ *old_function = patch->original_function();
+ }
+ return patch;
+}
+
+// Keeps track of all the hooks needed to intercept functions which could
+// possibly close handles.
+class HandleHooks {
+ public:
+ HandleHooks() {}
+ ~HandleHooks() {}
+
+ void AddIATPatch(HMODULE module);
+ void AddEATPatch();
+ void Unpatch();
+
+ private:
+ std::vector<base::win::IATPatchFunction*> hooks_;
+ DISALLOW_COPY_AND_ASSIGN(HandleHooks);
+};
+base::LazyInstance<HandleHooks> g_hooks = LAZY_INSTANCE_INITIALIZER;
+
+void HandleHooks::AddIATPatch(HMODULE module) {
+ if (!module)
+ return;
+
+ base::win::IATPatchFunction* patch = NULL;
+ patch = IATPatch(module, "CloseHandle", &CloseHandleHook,
+ reinterpret_cast<void**>(&g_close_function));
+ if (!patch)
+ return;
+ hooks_.push_back(patch);
+
+ patch = IATPatch(module, "DuplicateHandle", &DuplicateHandleHook,
+ reinterpret_cast<void**>(&g_duplicate_function));
+ if (!patch)
+ return;
+ hooks_.push_back(patch);
+}
+
+void HandleHooks::AddEATPatch() {
+ // An attempt to restore the entry on the table at destruction is not safe.
+ EATPatch(GetModuleHandleA("kernel32.dll"), "CloseHandle",
+ &CloseHandleHook, reinterpret_cast<void**>(&g_close_function));
+ EATPatch(GetModuleHandleA("kernel32.dll"), "DuplicateHandle",
+ &DuplicateHandleHook,
+ reinterpret_cast<void**>(&g_duplicate_function));
+}
+
+void HandleHooks::Unpatch() {
+ for (std::vector<base::win::IATPatchFunction*>::iterator it = hooks_.begin();
+ it != hooks_.end(); ++it) {
+ (*it)->Unpatch();
+ delete *it;
+ }
+}
+
+void PatchLoadedModules(HandleHooks* hooks) {
+ const DWORD kSize = 256;
+ DWORD returned;
+ scoped_ptr<HMODULE[]> modules(new HMODULE[kSize]);
+ if (!EnumProcessModules(GetCurrentProcess(), modules.get(),
+ kSize * sizeof(HMODULE), &returned)) {
+ return;
+ }
+ returned /= sizeof(HMODULE);
+ returned = std::min(kSize, returned);
+
+ for (DWORD current = 0; current < returned; current++) {
+ hooks->AddIATPatch(modules[current]);
+ }
+}
+
+} // namespace
+
+void InstallHandleHooks() {
+ HandleHooks* hooks = g_hooks.Pointer();
+
+ // Performing EAT interception first is safer in the presence of other
+ // threads attempting to call CloseHandle.
+ hooks->AddEATPatch();
+ PatchLoadedModules(hooks);
+}
+
+void RemoveHandleHooks() {
+ // We are partching all loaded modules without forcing them to stay in memory,
+ // removing patches is not safe.
+}
+
+} // namespace debug
+} // namespace base
diff --git a/chromium/base/debug/close_handle_hook_win.h b/chromium/base/debug/close_handle_hook_win.h
new file mode 100644
index 00000000000..a0424677ab2
--- /dev/null
+++ b/chromium/base/debug/close_handle_hook_win.h
@@ -0,0 +1,22 @@
+// 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_DEBUG_CLOSE_HANDLE_HOOK_WIN_H_
+#define BASE_DEBUG_CLOSE_HANDLE_HOOK_WIN_H_
+
+#include "base/base_export.h"
+
+namespace base {
+namespace debug {
+
+// Installs the hooks required to debug use of improper handles.
+BASE_EXPORT void InstallHandleHooks();
+
+// Removes the hooks installed by InstallHandleHooks().
+BASE_EXPORT void RemoveHandleHooks();
+
+} // namespace debug
+} // namespace base
+
+#endif // BASE_DEBUG_CLOSE_HANDLE_HOOK_WIN_H_
diff --git a/chromium/base/debug/crash_logging.h b/chromium/base/debug/crash_logging.h
index 90e6687bec8..7a6bbcd5405 100644
--- a/chromium/base/debug/crash_logging.h
+++ b/chromium/base/debug/crash_logging.h
@@ -5,11 +5,13 @@
#ifndef BASE_DEBUG_CRASH_LOGGING_H_
#define BASE_DEBUG_CRASH_LOGGING_H_
+#include <stddef.h>
+
#include <string>
#include <vector>
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/strings/string_piece.h"
// These functions add metadata to the upload payload when sending crash reports
diff --git a/chromium/base/debug/crash_logging_unittest.cc b/chromium/base/debug/crash_logging_unittest.cc
index 4cd9f3e3b09..5197c03e272 100644
--- a/chromium/base/debug/crash_logging_unittest.cc
+++ b/chromium/base/debug/crash_logging_unittest.cc
@@ -4,10 +4,13 @@
#include "base/debug/crash_logging.h"
+#include <stddef.h>
+
#include <map>
#include <string>
#include "base/bind.h"
+#include "base/macros.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
diff --git a/chromium/base/debug/debugger.cc b/chromium/base/debug/debugger.cc
index 79233c58c57..1ccee1c2c2f 100644
--- a/chromium/base/debug/debugger.cc
+++ b/chromium/base/debug/debugger.cc
@@ -5,6 +5,7 @@
#include "base/debug/debugger.h"
#include "base/logging.h"
#include "base/threading/platform_thread.h"
+#include "build/build_config.h"
namespace base {
namespace debug {
diff --git a/chromium/base/debug/debugger_posix.cc b/chromium/base/debug/debugger_posix.cc
index a2e804f2e63..cd6dc765b43 100644
--- a/chromium/base/debug/debugger_posix.cc
+++ b/chromium/base/debug/debugger_posix.cc
@@ -3,10 +3,12 @@
// found in the LICENSE file.
#include "base/debug/debugger.h"
+#include "base/macros.h"
#include "build/build_config.h"
#include <errno.h>
#include <fcntl.h>
+#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/param.h>
@@ -34,7 +36,6 @@
#include <ostream>
-#include "base/basictypes.h"
#include "base/debug/alias.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
diff --git a/chromium/base/debug/gdi_debug_util_win.cc b/chromium/base/debug/gdi_debug_util_win.cc
index 2db10d17822..ce339559ead 100644
--- a/chromium/base/debug/gdi_debug_util_win.cc
+++ b/chromium/base/debug/gdi_debug_util_win.cc
@@ -6,6 +6,7 @@
#include <cmath>
#include <psapi.h>
+#include <stddef.h>
#include <TlHelp32.h>
#include "base/debug/alias.h"
diff --git a/chromium/base/debug/leak_annotations.h b/chromium/base/debug/leak_annotations.h
index ef37959aadc..dc502461d07 100644
--- a/chromium/base/debug/leak_annotations.h
+++ b/chromium/base/debug/leak_annotations.h
@@ -5,7 +5,7 @@
#ifndef BASE_DEBUG_LEAK_ANNOTATIONS_H_
#define BASE_DEBUG_LEAK_ANNOTATIONS_H_
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "build/build_config.h"
// This file defines macros which can be used to annotate intentional memory
diff --git a/chromium/base/debug/leak_tracker.h b/chromium/base/debug/leak_tracker.h
index 8c5aaf31c2f..9dd16229393 100644
--- a/chromium/base/debug/leak_tracker.h
+++ b/chromium/base/debug/leak_tracker.h
@@ -5,6 +5,8 @@
#ifndef BASE_DEBUG_LEAK_TRACKER_H_
#define BASE_DEBUG_LEAK_TRACKER_H_
+#include <stddef.h>
+
#include "build/build_config.h"
// Only enable leak tracking in non-uClibc debug builds.
diff --git a/chromium/base/debug/proc_maps_linux.cc b/chromium/base/debug/proc_maps_linux.cc
index 8c8965b8f15..0bb44b45ac3 100644
--- a/chromium/base/debug/proc_maps_linux.cc
+++ b/chromium/base/debug/proc_maps_linux.cc
@@ -5,14 +5,16 @@
#include "base/debug/proc_maps_linux.h"
#include <fcntl.h>
-
-#if defined(OS_LINUX) || defined(OS_ANDROID)
-#include <inttypes.h>
-#endif
+#include <stddef.h>
#include "base/files/file_util.h"
#include "base/files/scoped_file.h"
#include "base/strings/string_split.h"
+#include "build/build_config.h"
+
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+#include <inttypes.h>
+#endif
#if defined(OS_ANDROID) && !defined(__LP64__)
// In 32-bit mode, Bionic's inttypes.h defines PRI/SCNxPTR as an
@@ -112,8 +114,8 @@ bool ParseProcMaps(const std::string& input,
MappedMemoryRegion region;
const char* line = lines[i].c_str();
char permissions[5] = {'\0'}; // Ensure NUL-terminated string.
- uint8 dev_major = 0;
- uint8 dev_minor = 0;
+ uint8_t dev_major = 0;
+ uint8_t dev_minor = 0;
long inode = 0;
int path_index = 0;
diff --git a/chromium/base/debug/proc_maps_linux.h b/chromium/base/debug/proc_maps_linux.h
index 9fbd47898d3..38e92314c8f 100644
--- a/chromium/base/debug/proc_maps_linux.h
+++ b/chromium/base/debug/proc_maps_linux.h
@@ -5,11 +5,12 @@
#ifndef BASE_DEBUG_PROC_MAPS_LINUX_H_
#define BASE_DEBUG_PROC_MAPS_LINUX_H_
+#include <stdint.h>
+
#include <string>
#include <vector>
#include "base/base_export.h"
-#include "base/basictypes.h"
namespace base {
namespace debug {
@@ -31,7 +32,7 @@ struct MappedMemoryRegion {
unsigned long long offset;
// Bitmask of read/write/execute/private/shared permissions.
- uint8 permissions;
+ uint8_t permissions;
// Name of the file mapped into memory.
//
diff --git a/chromium/base/debug/proc_maps_linux_unittest.cc b/chromium/base/debug/proc_maps_linux_unittest.cc
index cbc0dd036ad..2e35ca64c01 100644
--- a/chromium/base/debug/proc_maps_linux_unittest.cc
+++ b/chromium/base/debug/proc_maps_linux_unittest.cc
@@ -2,12 +2,17 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
+#include <stdint.h>
+
#include "base/debug/proc_maps_linux.h"
#include "base/files/file_path.h"
+#include "base/macros.h"
#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 "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
@@ -142,7 +147,7 @@ TEST(ProcMapsTest, Multiple) {
TEST(ProcMapsTest, Permissions) {
static struct {
const char* input;
- uint8 permissions;
+ uint8_t permissions;
} kTestCases[] = {
{"00400000-0040b000 ---s 00000000 fc:00 794418 /bin/cat\n", 0},
{"00400000-0040b000 ---S 00000000 fc:00 794418 /bin/cat\n", 0},
diff --git a/chromium/base/debug/profiler.cc b/chromium/base/debug/profiler.cc
index 924c7693eb5..75e9aac0cba 100644
--- a/chromium/base/debug/profiler.cc
+++ b/chromium/base/debug/profiler.cc
@@ -6,16 +6,18 @@
#include <string>
+#include "base/debug/debugging_flags.h"
#include "base/process/process_handle.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
+#include "build/build_config.h"
#if defined(OS_WIN)
#include "base/win/pe_image.h"
#endif // defined(OS_WIN)
// TODO(peria): Enable profiling on Windows.
-#if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC) && !defined(OS_WIN)
+#if BUILDFLAG(ENABLE_PROFILING) && !defined(NO_TCMALLOC) && !defined(OS_WIN)
#include "third_party/tcmalloc/chromium/src/gperftools/profiler.h"
#endif
@@ -23,7 +25,7 @@ namespace base {
namespace debug {
// TODO(peria): Enable profiling on Windows.
-#if defined(ENABLE_PROFILING) && !defined(NO_TCMALLOC) && !defined(OS_WIN)
+#if BUILDFLAG(ENABLE_PROFILING) && !defined(NO_TCMALLOC) && !defined(OS_WIN)
static int profile_count = 0;
diff --git a/chromium/base/debug/profiler.h b/chromium/base/debug/profiler.h
index 2920d8a2fbe..7cce7b08f90 100644
--- a/chromium/base/debug/profiler.h
+++ b/chromium/base/debug/profiler.h
@@ -5,10 +5,11 @@
#ifndef BASE_DEBUG_PROFILER_H_
#define BASE_DEBUG_PROFILER_H_
+#include <stddef.h>
+
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
// The Profiler functions allow usage of the underlying sampling based
// profiler. If the application has not been built with the necessary
diff --git a/chromium/base/debug/stack_trace.cc b/chromium/base/debug/stack_trace.cc
index ce9e9ad5500..2250c8fb14c 100644
--- a/chromium/base/debug/stack_trace.cc
+++ b/chromium/base/debug/stack_trace.cc
@@ -4,13 +4,13 @@
#include "base/debug/stack_trace.h"
-#include "base/basictypes.h"
-
#include <string.h>
#include <algorithm>
#include <sstream>
+#include "base/macros.h"
+
namespace base {
namespace debug {
diff --git a/chromium/base/debug/stack_trace.h b/chromium/base/debug/stack_trace.h
index 85c91777b49..07e119a16b4 100644
--- a/chromium/base/debug/stack_trace.h
+++ b/chromium/base/debug/stack_trace.h
@@ -5,6 +5,8 @@
#ifndef BASE_DEBUG_STACK_TRACE_H_
#define BASE_DEBUG_STACK_TRACE_H_
+#include <stddef.h>
+
#include <iosfwd>
#include <string>
@@ -52,7 +54,7 @@ class BASE_EXPORT StackTrace {
// Note: this function will throw an import not found (StackWalk64) exception
// on system without dbghelp 5.1.
StackTrace(_EXCEPTION_POINTERS* exception_pointers);
- StackTrace(_CONTEXT* context);
+ StackTrace(const _CONTEXT* context);
#endif
// Copying and assignment are allowed with the default functions.
@@ -76,7 +78,7 @@ class BASE_EXPORT StackTrace {
private:
#if defined(OS_WIN)
- void InitTrace(_CONTEXT* context_record);
+ void InitTrace(const _CONTEXT* context_record);
#endif
// From http://msdn.microsoft.com/en-us/library/bb204633.aspx,
diff --git a/chromium/base/debug/stack_trace_android.cc b/chromium/base/debug/stack_trace_android.cc
index 5168b188da2..1e8038568e1 100644
--- a/chromium/base/debug/stack_trace_android.cc
+++ b/chromium/base/debug/stack_trace_android.cc
@@ -5,6 +5,7 @@
#include "base/debug/stack_trace.h"
#include <android/log.h>
+#include <stddef.h>
#include <unwind.h>
#include <ostream>
diff --git a/chromium/base/debug/stack_trace_posix.cc b/chromium/base/debug/stack_trace_posix.cc
index d8eb00598d3..00ee65745ac 100644
--- a/chromium/base/debug/stack_trace_posix.cc
+++ b/chromium/base/debug/stack_trace_posix.cc
@@ -7,6 +7,8 @@
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
+#include <stddef.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/param.h>
@@ -30,10 +32,10 @@
#include <AvailabilityMacros.h>
#endif
-#include "base/basictypes.h"
#include "base/debug/debugger.h"
#include "base/debug/proc_maps_linux.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/singleton.h"
#include "base/numerics/safe_conversions.h"
@@ -344,7 +346,7 @@ void StackDumpSignalHandler(int signal, siginfo_t* info, void* void_context) {
{ " trp: ", context->uc_mcontext.gregs[REG_TRAPNO] },
{ " msk: ", context->uc_mcontext.gregs[REG_OLDMASK] },
{ " cr2: ", context->uc_mcontext.gregs[REG_CR2] },
-#endif
+#endif // ARCH_CPU_32_BITS
};
#if ARCH_CPU_32_BITS
@@ -363,52 +365,20 @@ void StackDumpSignalHandler(int signal, siginfo_t* info, void* void_context) {
PrintToStderr("\n");
}
PrintToStderr("\n");
-#endif
-#elif defined(OS_MACOSX)
- // TODO(shess): Port to 64-bit, and ARM architecture (32 and 64-bit).
-#if ARCH_CPU_X86_FAMILY && ARCH_CPU_32_BITS
- ucontext_t* context = reinterpret_cast<ucontext_t*>(void_context);
- size_t len;
-
- // NOTE: Even |snprintf()| is not on the approved list for signal
- // handlers, but buffered I/O is definitely not on the list due to
- // potential for |malloc()|.
- len = static_cast<size_t>(
- snprintf(buf, sizeof(buf),
- "ax: %x, bx: %x, cx: %x, dx: %x\n",
- context->uc_mcontext->__ss.__eax,
- context->uc_mcontext->__ss.__ebx,
- context->uc_mcontext->__ss.__ecx,
- context->uc_mcontext->__ss.__edx));
- write(STDERR_FILENO, buf, std::min(len, sizeof(buf) - 1));
-
- len = static_cast<size_t>(
- snprintf(buf, sizeof(buf),
- "di: %x, si: %x, bp: %x, sp: %x, ss: %x, flags: %x\n",
- context->uc_mcontext->__ss.__edi,
- context->uc_mcontext->__ss.__esi,
- context->uc_mcontext->__ss.__ebp,
- context->uc_mcontext->__ss.__esp,
- context->uc_mcontext->__ss.__ss,
- context->uc_mcontext->__ss.__eflags));
- write(STDERR_FILENO, buf, std::min(len, sizeof(buf) - 1));
-
- len = static_cast<size_t>(
- snprintf(buf, sizeof(buf),
- "ip: %x, cs: %x, ds: %x, es: %x, fs: %x, gs: %x\n",
- context->uc_mcontext->__ss.__eip,
- context->uc_mcontext->__ss.__cs,
- context->uc_mcontext->__ss.__ds,
- context->uc_mcontext->__ss.__es,
- context->uc_mcontext->__ss.__fs,
- context->uc_mcontext->__ss.__gs));
- write(STDERR_FILENO, buf, std::min(len, sizeof(buf) - 1));
-#endif // ARCH_CPU_32_BITS
-#endif // defined(OS_MACOSX)
+#endif // ARCH_CPU_X86_FAMILY
+#endif // defined(OS_LINUX)
PrintToStderr("[end of stack trace]\n");
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+ if (::signal(signal, SIG_DFL) == SIG_ERR)
+ _exit(1);
+#else
+ // Non-Mac OSes should probably reraise the signal as well, but the Linux
+ // sandbox tests break on CrOS devices.
+ // https://code.google.com/p/chromium/issues/detail?id=551681
_exit(1);
+#endif // defined(OS_MACOSX) && !defined(OS_IOS)
}
class PrintBacktraceOutputHandler : public BacktraceOutputHandler {
@@ -505,7 +475,7 @@ class SandboxSymbolizeHelper {
}
// Returns a O_RDONLY file descriptor for |file_path| if it was opened
- // sucessfully during the initialization. The file is repositioned at
+ // successfully during the initialization. The file is repositioned at
// offset 0.
// IMPORTANT: This function must be async-signal-safe because it can be
// called from a signal handler (symbolizing stack frames for a crash).
@@ -773,7 +743,7 @@ void StackTrace::OutputToStream(std::ostream* os) const {
namespace internal {
// NOTE: code from sandbox/linux/seccomp-bpf/demo.cc.
-char *itoa_r(intptr_t i, char *buf, size_t sz, int base, size_t padding) {
+char* itoa_r(intptr_t i, char* buf, size_t sz, int base, size_t padding) {
// Make sure we can write at least one NUL byte.
size_t n = 1;
if (n > sz)
@@ -784,7 +754,7 @@ char *itoa_r(intptr_t i, char *buf, size_t sz, int base, size_t padding) {
return NULL;
}
- char *start = buf;
+ char* start = buf;
uintptr_t j = i;
@@ -803,7 +773,7 @@ char *itoa_r(intptr_t i, char *buf, size_t sz, int base, size_t padding) {
// Loop until we have converted the entire number. Output at least one
// character (i.e. '0').
- char *ptr = start;
+ char* ptr = start;
do {
// Make sure there is still enough space left in our output buffer.
if (++n > sz) {
diff --git a/chromium/base/debug/stack_trace_unittest.cc b/chromium/base/debug/stack_trace_unittest.cc
index 804587e3405..9abedba6baf 100644
--- a/chromium/base/debug/stack_trace_unittest.cc
+++ b/chromium/base/debug/stack_trace_unittest.cc
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
+
#include <limits>
#include <sstream>
#include <string>
@@ -11,6 +13,7 @@
#include "base/process/kill.h"
#include "base/process/process_handle.h"
#include "base/test/test_timeouts.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/multiprocess_func_list.h"
diff --git a/chromium/base/debug/stack_trace_win.cc b/chromium/base/debug/stack_trace_win.cc
index d5be5efb355..059675226af 100644
--- a/chromium/base/debug/stack_trace_win.cc
+++ b/chromium/base/debug/stack_trace_win.cc
@@ -6,11 +6,12 @@
#include <windows.h>
#include <dbghelp.h>
+#include <stddef.h>
#include <iostream>
-#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/singleton.h"
#include "base/process/launch.h"
#include "base/strings/string_util.h"
@@ -222,11 +223,19 @@ StackTrace::StackTrace(EXCEPTION_POINTERS* exception_pointers) {
InitTrace(exception_pointers->ContextRecord);
}
-StackTrace::StackTrace(CONTEXT* context) {
+StackTrace::StackTrace(const CONTEXT* context) {
InitTrace(context);
}
-void StackTrace::InitTrace(CONTEXT* context_record) {
+void StackTrace::InitTrace(const CONTEXT* context_record) {
+ // StackWalk64 modifies the register context in place, so we have to copy it
+ // so that downstream exception handlers get the right context. The incoming
+ // context may have had more register state (YMM, etc) than we need to unwind
+ // the stack. Typically StackWalk64 only needs integer and control registers.
+ CONTEXT context_copy;
+ memcpy(&context_copy, context_record, sizeof(context_copy));
+ context_copy.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
+
// When walking an exception stack, we need to use StackWalk64().
count_ = 0;
// Initialize stack walking.
@@ -250,7 +259,7 @@ void StackTrace::InitTrace(CONTEXT* context_record) {
GetCurrentProcess(),
GetCurrentThread(),
&stack_frame,
- context_record,
+ &context_copy,
NULL,
&SymFunctionTableAccess64,
&SymGetModuleBase64,
diff --git a/chromium/base/debug/task_annotator.cc b/chromium/base/debug/task_annotator.cc
index e47a0439e37..4ba4d91b887 100644
--- a/chromium/base/debug/task_annotator.cc
+++ b/chromium/base/debug/task_annotator.cc
@@ -55,9 +55,10 @@ void TaskAnnotator::RunTask(const char* queue_function,
pending_task, stopwatch);
}
-uint64 TaskAnnotator::GetTaskTraceID(const PendingTask& task) const {
- return (static_cast<uint64>(task.sequence_num) << 32) |
- ((static_cast<uint64>(reinterpret_cast<intptr_t>(this)) << 32) >> 32);
+uint64_t TaskAnnotator::GetTaskTraceID(const PendingTask& task) const {
+ return (static_cast<uint64_t>(task.sequence_num) << 32) |
+ ((static_cast<uint64_t>(reinterpret_cast<intptr_t>(this)) << 32) >>
+ 32);
}
} // namespace debug
diff --git a/chromium/base/debug/task_annotator.h b/chromium/base/debug/task_annotator.h
index 74068d92040..443c71bf301 100644
--- a/chromium/base/debug/task_annotator.h
+++ b/chromium/base/debug/task_annotator.h
@@ -5,8 +5,10 @@
#ifndef BASE_DEBUG_TASK_ANNOTATOR_H_
#define BASE_DEBUG_TASK_ANNOTATOR_H_
+#include <stdint.h>
+
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
namespace base {
struct PendingTask;
@@ -32,17 +34,15 @@ class BASE_EXPORT TaskAnnotator {
// Creates a process-wide unique ID to represent this task in trace events.
// This will be mangled with a Process ID hash to reduce the likelyhood of
// colliding with TaskAnnotator pointers on other processes.
- uint64 GetTaskTraceID(const PendingTask& task) const;
+ uint64_t GetTaskTraceID(const PendingTask& task) const;
DISALLOW_COPY_AND_ASSIGN(TaskAnnotator);
};
-#define TRACE_TASK_EXECUTION(run_function, task) \
- TRACE_EVENT_WITH_MEMORY_TAG2( \
- "toplevel", (run_function), \
- (task).posted_from.function_name(), /* Name for memory tracking. */ \
- "src_file", (task).posted_from.file_name(), "src_func", \
- (task).posted_from.function_name());
+#define TRACE_TASK_EXECUTION(run_function, task) \
+ TRACE_EVENT2("toplevel", (run_function), "src_file", \
+ (task).posted_from.file_name(), "src_func", \
+ (task).posted_from.function_name());
} // namespace debug
} // namespace base
diff --git a/chromium/base/deferred_sequenced_task_runner.h b/chromium/base/deferred_sequenced_task_runner.h
index 110d988615d..de5c3b9079f 100644
--- a/chromium/base/deferred_sequenced_task_runner.h
+++ b/chromium/base/deferred_sequenced_task_runner.h
@@ -8,9 +8,9 @@
#include <vector>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/callback.h"
#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/sequenced_task_runner.h"
#include "base/synchronization/lock.h"
diff --git a/chromium/base/deferred_sequenced_task_runner_unittest.cc b/chromium/base/deferred_sequenced_task_runner_unittest.cc
index 6e17ad93a8f..883a3dd0f52 100644
--- a/chromium/base/deferred_sequenced_task_runner_unittest.cc
+++ b/chromium/base/deferred_sequenced_task_runner_unittest.cc
@@ -4,7 +4,6 @@
#include "base/deferred_sequenced_task_runner.h"
-#include "base/basictypes.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/location.h"
diff --git a/chromium/base/environment.cc b/chromium/base/environment.cc
index 11b2bc39a9e..adb73871d07 100644
--- a/chromium/base/environment.cc
+++ b/chromium/base/environment.cc
@@ -4,11 +4,14 @@
#include "base/environment.h"
+#include <stddef.h>
+
#include <vector>
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
#if defined(OS_POSIX)
#include <stdlib.h>
@@ -228,7 +231,7 @@ scoped_ptr<char*[]> AlterEnvironment(const char* const* const env,
result[i] = &storage_data[result_indices[i]];
result[result_indices.size()] = 0; // Null terminator.
- return result.Pass();
+ return result;
}
#endif // OS_POSIX
diff --git a/chromium/base/environment_unittest.cc b/chromium/base/environment_unittest.cc
index f0577a8a82b..77e971787dd 100644
--- a/chromium/base/environment_unittest.cc
+++ b/chromium/base/environment_unittest.cc
@@ -4,6 +4,7 @@
#include "base/environment.h"
#include "base/memory/scoped_ptr.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
@@ -129,7 +130,7 @@ TEST_F(EnvironmentTest, AlterEnvironment) {
EnvironmentMap changes;
scoped_ptr<char*[]> e;
- e = AlterEnvironment(empty, changes).Pass();
+ e = AlterEnvironment(empty, changes);
EXPECT_TRUE(e[0] == NULL);
changes["A"] = "1";
diff --git a/chromium/base/feature_list.cc b/chromium/base/feature_list.cc
index 2acd2900dca..d10c60bd4c5 100644
--- a/chromium/base/feature_list.cc
+++ b/chromium/base/feature_list.cc
@@ -4,12 +4,15 @@
#include "base/feature_list.h"
+#include <stddef.h>
+
#include <utility>
#include <vector>
#include "base/logging.h"
#include "base/metrics/field_trial.h"
#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
namespace base {
@@ -20,9 +23,14 @@ namespace {
// have more control over initialization timing. Leaky.
FeatureList* g_instance = nullptr;
-// Splits a comma-separated string containing feature names into a vector.
-std::vector<std::string> SplitFeatureListString(const std::string& input) {
- return SplitString(input, ",", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
+// Some characters are not allowed to appear in feature names or the associated
+// field trial names, as they are used as special characters for command-line
+// serialization. This function checks that the strings are ASCII (since they
+// are used in command-line API functions that require ASCII) and whether there
+// are any reserved characters present, returning true if the string is valid.
+// Only called in DCHECKs.
+bool IsValidFeatureOrFieldTrialName(const std::string& name) {
+ return IsStringASCII(name) && name.find_first_of(",<") == std::string::npos;
}
} // namespace
@@ -38,12 +46,8 @@ void FeatureList::InitializeFromCommandLine(
// Process disabled features first, so that disabled ones take precedence over
// enabled ones (since RegisterOverride() uses insert()).
- for (const auto& feature_name : SplitFeatureListString(disable_features)) {
- RegisterOverride(feature_name, OVERRIDE_DISABLE_FEATURE, nullptr);
- }
- for (const auto& feature_name : SplitFeatureListString(enable_features)) {
- RegisterOverride(feature_name, OVERRIDE_ENABLE_FEATURE, nullptr);
- }
+ RegisterOverridesFromCommandLine(disable_features, OVERRIDE_DISABLE_FEATURE);
+ RegisterOverridesFromCommandLine(enable_features, OVERRIDE_ENABLE_FEATURE);
}
bool FeatureList::IsFeatureOverriddenFromCommandLine(
@@ -54,20 +58,6 @@ bool FeatureList::IsFeatureOverriddenFromCommandLine(
!it->second.overridden_by_field_trial;
}
-void FeatureList::RegisterFieldTrialOverride(const std::string& feature_name,
- OverrideState override_state,
- FieldTrial* field_trial) {
- DCHECK(field_trial);
- DCHECK(!ContainsKey(overrides_, feature_name) ||
- !overrides_.find(feature_name)->second.field_trial)
- << "Feature " << feature_name
- << " has conflicting field trial overrides: "
- << overrides_.find(feature_name)->second.field_trial->trial_name()
- << " / " << field_trial->trial_name();
-
- RegisterOverride(feature_name, override_state, field_trial);
-}
-
void FeatureList::AssociateReportingFieldTrial(
const std::string& feature_name,
OverrideState for_overridden_state,
@@ -88,12 +78,67 @@ void FeatureList::AssociateReportingFieldTrial(
entry->field_trial = field_trial;
}
+void FeatureList::RegisterFieldTrialOverride(const std::string& feature_name,
+ OverrideState override_state,
+ FieldTrial* field_trial) {
+ DCHECK(field_trial);
+ DCHECK(!ContainsKey(overrides_, feature_name) ||
+ !overrides_.find(feature_name)->second.field_trial)
+ << "Feature " << feature_name
+ << " has conflicting field trial overrides: "
+ << overrides_.find(feature_name)->second.field_trial->trial_name()
+ << " / " << field_trial->trial_name();
+
+ RegisterOverride(feature_name, override_state, field_trial);
+}
+
+void FeatureList::GetFeatureOverrides(std::string* enable_overrides,
+ std::string* disable_overrides) {
+ DCHECK(initialized_);
+
+ enable_overrides->clear();
+ disable_overrides->clear();
+
+ for (const auto& entry : overrides_) {
+ std::string* target_list = nullptr;
+ switch (entry.second.overridden_state) {
+ case OVERRIDE_ENABLE_FEATURE:
+ target_list = enable_overrides;
+ break;
+ case OVERRIDE_DISABLE_FEATURE:
+ target_list = disable_overrides;
+ break;
+ }
+
+ if (!target_list->empty())
+ target_list->push_back(',');
+ target_list->append(entry.first);
+ if (entry.second.field_trial) {
+ target_list->push_back('<');
+ target_list->append(entry.second.field_trial->trial_name());
+ }
+ }
+}
+
// static
bool FeatureList::IsEnabled(const Feature& feature) {
return GetInstance()->IsFeatureEnabled(feature);
}
// static
+std::vector<std::string> FeatureList::SplitFeatureListString(
+ const std::string& input) {
+ return SplitString(input, ",", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
+}
+
+// static
+void FeatureList::InitializeInstance() {
+ if (g_instance)
+ return;
+ SetInstance(make_scoped_ptr(new FeatureList));
+}
+
+// static
FeatureList* FeatureList::GetInstance() {
return g_instance;
}
@@ -120,6 +165,7 @@ void FeatureList::FinalizeInitialization() {
bool FeatureList::IsFeatureEnabled(const Feature& feature) {
DCHECK(initialized_);
+ DCHECK(IsValidFeatureOrFieldTrialName(feature.name)) << feature.name;
DCHECK(CheckFeatureIdentity(feature)) << feature.name;
auto it = overrides_.find(feature.name);
@@ -137,15 +183,39 @@ bool FeatureList::IsFeatureEnabled(const Feature& feature) {
return feature.default_state == FEATURE_ENABLED_BY_DEFAULT;
}
-void FeatureList::RegisterOverride(const std::string& feature_name,
+void FeatureList::RegisterOverridesFromCommandLine(
+ const std::string& feature_list,
+ OverrideState overridden_state) {
+ for (const auto& value : SplitFeatureListString(feature_list)) {
+ StringPiece feature_name(value);
+ base::FieldTrial* trial = nullptr;
+
+ // The entry may be of the form FeatureName<FieldTrialName - in which case,
+ // this splits off the field trial name and associates it with the override.
+ std::string::size_type pos = feature_name.find('<');
+ if (pos != std::string::npos) {
+ feature_name.set(value.data(), pos);
+ trial = base::FieldTrialList::Find(value.substr(pos + 1));
+ }
+
+ RegisterOverride(feature_name, overridden_state, trial);
+ }
+}
+
+void FeatureList::RegisterOverride(StringPiece feature_name,
OverrideState overridden_state,
FieldTrial* field_trial) {
DCHECK(!initialized_);
+ if (field_trial) {
+ DCHECK(IsValidFeatureOrFieldTrialName(field_trial->trial_name()))
+ << field_trial->trial_name();
+ }
+
// Note: The semantics of insert() is that it does not overwrite the entry if
// one already exists for the key. Thus, only the first override for a given
// feature name takes effect.
overrides_.insert(std::make_pair(
- feature_name, OverrideEntry(overridden_state, field_trial)));
+ feature_name.as_string(), OverrideEntry(overridden_state, field_trial)));
}
bool FeatureList::CheckFeatureIdentity(const Feature& feature) {
diff --git a/chromium/base/feature_list.h b/chromium/base/feature_list.h
index 0f91a3efa87..875d3b595a5 100644
--- a/chromium/base/feature_list.h
+++ b/chromium/base/feature_list.h
@@ -7,11 +7,13 @@
#include <map>
#include <string>
+#include <vector>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/gtest_prod_util.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_piece.h"
#include "base/synchronization/lock.h"
namespace base {
@@ -44,7 +46,7 @@ struct BASE_EXPORT Feature {
// The basic use case is for any feature that can be toggled (e.g. through
// command-line or an experiment) to have a defined Feature struct, e.g.:
//
-// struct base::Feature kMyGreatFeature {
+// const base::Feature kMyGreatFeature {
// "MyGreatFeature", base::FEATURE_ENABLED_BY_DEFAULT
// };
//
@@ -80,8 +82,10 @@ class BASE_EXPORT FeatureList {
// Initializes feature overrides via command-line flags |enable_features| and
// |disable_features|, each of which is a comma-separated list of features to
// enable or disable, respectively. If a feature appears on both lists, then
- // it will be disabled. Must only be invoked during the initialization phase
- // (before FinalizeInitialization() has been called).
+ // it will be disabled. If a list entry has the format "FeatureName<TrialName"
+ // then this initialization will also associate the feature state override
+ // with the named field trial, if it exists. Must only be invoked during the
+ // initialization phase (before FinalizeInitialization() has been called).
void InitializeFromCommandLine(const std::string& enable_features,
const std::string& disable_features);
@@ -116,12 +120,30 @@ class BASE_EXPORT FeatureList {
OverrideState override_state,
FieldTrial* field_trial);
+ // Returns comma-separated lists of feature names (in the same format that is
+ // accepted by InitializeFromCommandLine()) corresponding to features that
+ // have been overridden - either through command-line or via FieldTrials. For
+ // those features that have an associated FieldTrial, the output entry will be
+ // of the format "FeatureName<TrialName", where "TrialName" is the name of the
+ // FieldTrial. Must be called only after the instance has been initialized and
+ // registered.
+ void GetFeatureOverrides(std::string* enable_overrides,
+ std::string* disable_overrides);
+
// Returns whether the given |feature| is enabled. Must only be called after
// the singleton instance has been registered via SetInstance(). Additionally,
// a feature with a given name must only have a single corresponding Feature
// struct, which is checked in builds with DCHECKs enabled.
static bool IsEnabled(const Feature& feature);
+ // Splits a comma-separated string containing feature names into a vector.
+ static std::vector<std::string> SplitFeatureListString(
+ const std::string& input);
+
+ // Initializes and sets a default instance of FeatureList if one has not yet
+ // already been set. No-op otherwise.
+ static void InitializeInstance();
+
// Returns the singleton instance of FeatureList. Will return null until an
// instance is registered via SetInstance().
static FeatureList* GetInstance();
@@ -169,6 +191,13 @@ class BASE_EXPORT FeatureList {
// Requires the FeatureList to have already been fully initialized.
bool IsFeatureEnabled(const Feature& feature);
+ // For each feature name in comma-separated list of strings |feature_list|,
+ // registers an override with the specified |overridden_state|. Also, will
+ // associate an optional named field trial if the entry is of the format
+ // "FeatureName<TrialName".
+ void RegisterOverridesFromCommandLine(const std::string& feature_list,
+ OverrideState overridden_state);
+
// Registers an override for feature |feature_name|. The override specifies
// whether the feature should be on or off (via |overridden_state|), which
// will take precedence over the feature's default state. If |field_trial| is
@@ -176,7 +205,7 @@ class BASE_EXPORT FeatureList {
// the feature, which will activate the field trial when the feature state is
// queried. If an override is already registered for the given feature, it
// will not be changed.
- void RegisterOverride(const std::string& feature_name,
+ void RegisterOverride(StringPiece feature_name,
OverrideState overridden_state,
FieldTrial* field_trial);
diff --git a/chromium/base/feature_list_unittest.cc b/chromium/base/feature_list_unittest.cc
index 9d8538e9640..11cf179a8ce 100644
--- a/chromium/base/feature_list_unittest.cc
+++ b/chromium/base/feature_list_unittest.cc
@@ -4,8 +4,14 @@
#include "base/feature_list.h"
+#include <stddef.h>
+
+#include <utility>
+
#include "base/format_macros.h"
+#include "base/macros.h"
#include "base/metrics/field_trial.h"
+#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -23,6 +29,13 @@ struct Feature kFeatureOffByDefault {
kFeatureOffByDefaultName, FEATURE_DISABLED_BY_DEFAULT
};
+std::string SortFeatureListString(const std::string& feature_list) {
+ std::vector<std::string> features =
+ FeatureList::SplitFeatureListString(feature_list);
+ std::sort(features.begin(), features.end());
+ return JoinString(features, ",");
+}
+
} // namespace
class FeatureListTest : public testing::Test {
@@ -33,8 +46,9 @@ class FeatureListTest : public testing::Test {
~FeatureListTest() override { ClearFeatureListInstance(); }
void RegisterFeatureListInstance(scoped_ptr<FeatureList> feature_list) {
+ FeatureList::ClearInstanceForTesting();
feature_list_ = feature_list.get();
- FeatureList::SetInstance(feature_list.Pass());
+ FeatureList::SetInstance(std::move(feature_list));
}
void ClearFeatureListInstance() {
FeatureList::ClearInstanceForTesting();
@@ -81,7 +95,7 @@ TEST_F(FeatureListTest, InitializeFromCommandLine) {
scoped_ptr<FeatureList> feature_list(new FeatureList);
feature_list->InitializeFromCommandLine(test_case.enable_features,
test_case.disable_features);
- RegisterFeatureListInstance(feature_list.Pass());
+ RegisterFeatureListInstance(std::move(feature_list));
EXPECT_EQ(test_case.expected_feature_on_state,
FeatureList::IsEnabled(kFeatureOnByDefault))
@@ -142,7 +156,7 @@ TEST_F(FeatureListTest, FieldTrialOverrides) {
test_case.trial1_state, trial1);
feature_list->RegisterFieldTrialOverride(kFeatureOffByDefaultName,
test_case.trial2_state, trial2);
- RegisterFeatureListInstance(feature_list.Pass());
+ RegisterFeatureListInstance(std::move(feature_list));
// Initially, neither trial should be active.
EXPECT_FALSE(FieldTrialList::IsTrialActive(trial1->trial_name()));
@@ -177,7 +191,7 @@ TEST_F(FeatureListTest, CommandLineTakesPrecedenceOverFieldTrial) {
FieldTrial* trial = FieldTrialList::CreateFieldTrial("TrialExample2", "A");
feature_list->RegisterFieldTrialOverride(
kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE, trial);
- RegisterFeatureListInstance(feature_list.Pass());
+ RegisterFeatureListInstance(std::move(feature_list));
EXPECT_FALSE(FieldTrialList::IsTrialActive(trial->trial_name()));
// Command-line should take precedence.
@@ -232,7 +246,7 @@ TEST_F(FeatureListTest, IsFeatureOverriddenFromCommandLine) {
kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
kFeatureOnByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
- RegisterFeatureListInstance(feature_list.Pass());
+ RegisterFeatureListInstance(std::move(feature_list));
// Check the expected feature states for good measure.
EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
@@ -292,7 +306,7 @@ TEST_F(FeatureListTest, AssociateReportingFieldTrial) {
EXPECT_EQ(test_case.expected_enable_trial_created, enable_trial != nullptr);
EXPECT_EQ(test_case.expected_disable_trial_created,
disable_trial != nullptr);
- RegisterFeatureListInstance(feature_list.Pass());
+ RegisterFeatureListInstance(std::move(feature_list));
EXPECT_FALSE(FieldTrialList::IsTrialActive(kTrialName));
if (disable_trial) {
@@ -307,4 +321,38 @@ TEST_F(FeatureListTest, AssociateReportingFieldTrial) {
}
}
+TEST_F(FeatureListTest, GetFeatureOverrides) {
+ ClearFeatureListInstance();
+ FieldTrialList field_trial_list(nullptr);
+ scoped_ptr<FeatureList> feature_list(new FeatureList);
+ feature_list->InitializeFromCommandLine("A,X", "D");
+
+ FieldTrial* trial = FieldTrialList::CreateFieldTrial("Trial", "Group");
+ feature_list->RegisterFieldTrialOverride(kFeatureOffByDefaultName,
+ FeatureList::OVERRIDE_ENABLE_FEATURE,
+ trial);
+
+ RegisterFeatureListInstance(std::move(feature_list));
+
+ std::string enable_features;
+ std::string disable_features;
+ FeatureList::GetInstance()->GetFeatureOverrides(&enable_features,
+ &disable_features);
+ EXPECT_EQ("A,OffByDefault<Trial,X", SortFeatureListString(enable_features));
+ EXPECT_EQ("D", SortFeatureListString(disable_features));
+}
+
+TEST_F(FeatureListTest, InitializeFromCommandLine_WithFieldTrials) {
+ ClearFeatureListInstance();
+ FieldTrialList field_trial_list(nullptr);
+ FieldTrialList::CreateFieldTrial("Trial", "Group");
+ scoped_ptr<FeatureList> feature_list(new FeatureList);
+ feature_list->InitializeFromCommandLine("A,OffByDefault<Trial,X", "D");
+ RegisterFeatureListInstance(std::move(feature_list));
+
+ EXPECT_FALSE(FieldTrialList::IsTrialActive("Trial"));
+ EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
+ EXPECT_TRUE(FieldTrialList::IsTrialActive("Trial"));
+}
+
} // namespace base
diff --git a/chromium/base/file_version_info_mac.h b/chromium/base/file_version_info_mac.h
index e67783834df..9cc4b1074d3 100644
--- a/chromium/base/file_version_info_mac.h
+++ b/chromium/base/file_version_info_mac.h
@@ -10,6 +10,7 @@
#include "base/file_version_info.h"
#include "base/mac/scoped_nsobject.h"
+#include "base/macros.h"
@class NSBundle;
diff --git a/chromium/base/file_version_info_mac.mm b/chromium/base/file_version_info_mac.mm
index 8542b198441..ce4292441ed 100644
--- a/chromium/base/file_version_info_mac.mm
+++ b/chromium/base/file_version_info_mac.mm
@@ -11,6 +11,7 @@
#include "base/mac/bundle_locations.h"
#include "base/mac/foundation_util.h"
#include "base/strings/sys_string_conversions.h"
+#include "build/build_config.h"
FileVersionInfoMac::FileVersionInfoMac(NSBundle *bundle)
: bundle_([bundle retain]) {
diff --git a/chromium/base/file_version_info_unittest.cc b/chromium/base/file_version_info_unittest.cc
index c5e98594003..4c0ba6ffe32 100644
--- a/chromium/base/file_version_info_unittest.cc
+++ b/chromium/base/file_version_info_unittest.cc
@@ -2,10 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
+
#include "base/file_version_info.h"
#include "base/files/file_path.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/path_service.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#if defined(OS_WIN)
@@ -93,7 +97,7 @@ TEST(FileVersionInfoTest, IsOfficialBuild) {
// Test consistency check.
ASSERT_EQ(arraysize(kDLLNames), arraysize(kExpected));
- for (int i = 0; i < arraysize(kDLLNames); ++i) {
+ for (size_t i = 0; i < arraysize(kDLLNames); ++i) {
FilePath dll_path = GetTestDataPath();
dll_path = dll_path.Append(kDLLNames[i]);
diff --git a/chromium/base/file_version_info_win.cc b/chromium/base/file_version_info_win.cc
index ca3e4b1fa3a..02a14db0032 100644
--- a/chromium/base/file_version_info_win.cc
+++ b/chromium/base/file_version_info_win.cc
@@ -5,10 +5,13 @@
#include "base/file_version_info_win.h"
#include <windows.h>
+#include <stddef.h>
+#include <stdint.h>
#include "base/file_version_info.h"
#include "base/files/file_path.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/threading/thread_restrictions.h"
using base::FilePath;
@@ -68,7 +71,7 @@ FileVersionInfo* FileVersionInfo::CreateFileVersionInfo(
}
LanguageAndCodePage* translate = NULL;
- uint32 page_count;
+ uint32_t page_count;
BOOL query_result = VerQueryValue(data, L"\\VarFileInfo\\Translation",
(void**) &translate, &page_count);
@@ -149,7 +152,7 @@ bool FileVersionInfoWin::is_official_build() {
bool FileVersionInfoWin::GetValue(const wchar_t* name,
std::wstring* value_str) {
WORD lang_codepage[8];
- int i = 0;
+ size_t i = 0;
// Use the language and codepage from the DLL.
lang_codepage[i++] = language_;
lang_codepage[i++] = code_page_;
@@ -171,7 +174,7 @@ bool FileVersionInfoWin::GetValue(const wchar_t* name,
_snwprintf_s(sub_block, MAX_PATH, MAX_PATH,
L"\\StringFileInfo\\%04x%04x\\%ls", language, code_page, name);
LPVOID value = NULL;
- uint32 size;
+ uint32_t size;
BOOL r = ::VerQueryValue(data_.get(), sub_block, &value, &size);
if (r && value) {
value_str->assign(static_cast<wchar_t*>(value));
diff --git a/chromium/base/file_version_info_win.h b/chromium/base/file_version_info_win.h
index 09d8d37cc0c..6dd020264e9 100644
--- a/chromium/base/file_version_info_win.h
+++ b/chromium/base/file_version_info_win.h
@@ -8,8 +8,8 @@
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/file_version_info.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
struct tagVS_FIXEDFILEINFO;
diff --git a/chromium/base/files/dir_reader_fallback.h b/chromium/base/files/dir_reader_fallback.h
index a435f25963d..d44c2279e49 100644
--- a/chromium/base/files/dir_reader_fallback.h
+++ b/chromium/base/files/dir_reader_fallback.h
@@ -21,7 +21,7 @@ class DirReaderFallback {
bool Next() { return false; }
// Return the name of the current directory entry.
- const char* name() { return 0;}
+ const char* name() { return nullptr;}
// Return the file descriptor which is being used.
int fd() const { return -1; }
diff --git a/chromium/base/files/dir_reader_linux.h b/chromium/base/files/dir_reader_linux.h
index abf259530b3..4ce0c34245f 100644
--- a/chromium/base/files/dir_reader_linux.h
+++ b/chromium/base/files/dir_reader_linux.h
@@ -7,11 +7,13 @@
#include <errno.h>
#include <fcntl.h>
+#include <stddef.h>
#include <stdint.h>
#include <sys/syscall.h>
#include <unistd.h>
#include "base/logging.h"
+#include "base/macros.h"
#include "base/posix/eintr_wrapper.h"
// See the comments in dir_reader_posix.h about this.
@@ -70,7 +72,7 @@ class DirReaderLinux {
const char* name() const {
if (!size_)
- return NULL;
+ return nullptr;
const linux_dirent* dirent =
reinterpret_cast<const linux_dirent*>(&buf_[offset_]);
@@ -88,7 +90,8 @@ class DirReaderLinux {
private:
const int fd_;
unsigned char buf_[512];
- size_t offset_, size_;
+ size_t offset_;
+ size_t size_;
DISALLOW_COPY_AND_ASSIGN(DirReaderLinux);
};
diff --git a/chromium/base/files/dir_reader_posix_unittest.cc b/chromium/base/files/dir_reader_posix_unittest.cc
index 2e181b3d851..a75858feebd 100644
--- a/chromium/base/files/dir_reader_posix_unittest.cc
+++ b/chromium/base/files/dir_reader_posix_unittest.cc
@@ -12,6 +12,7 @@
#include "base/files/scoped_temp_dir.h"
#include "base/logging.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#if defined(OS_ANDROID)
diff --git a/chromium/base/files/file.cc b/chromium/base/files/file.cc
index 47b9f88f188..ab056300625 100644
--- a/chromium/base/files/file.cc
+++ b/chromium/base/files/file.cc
@@ -7,6 +7,7 @@
#include "base/files/file_tracing.h"
#include "base/metrics/histogram.h"
#include "base/timer/elapsed_timer.h"
+#include "build/build_config.h"
namespace base {
@@ -26,10 +27,8 @@ File::File()
}
#if !defined(OS_NACL)
-File::File(const FilePath& path, uint32 flags)
- : error_details_(FILE_OK),
- created_(false),
- async_(false) {
+File::File(const FilePath& path, uint32_t flags)
+ : error_details_(FILE_OK), created_(false), async_(false) {
Initialize(path, flags);
}
#endif
@@ -50,13 +49,12 @@ File::File(Error error_details)
async_(false) {
}
-File::File(RValue other)
- : file_(other.object->TakePlatformFile()),
- tracing_path_(other.object->tracing_path_),
- error_details_(other.object->error_details()),
- created_(other.object->created()),
- async_(other.object->async_) {
-}
+File::File(File&& other)
+ : file_(other.TakePlatformFile()),
+ tracing_path_(other.tracing_path_),
+ error_details_(other.error_details()),
+ created_(other.created()),
+ async_(other.async_) {}
File::~File() {
// Go through the AssertIOAllowed logic.
@@ -69,23 +67,22 @@ File File::CreateForAsyncHandle(PlatformFile platform_file) {
// It would be nice if we could validate that |platform_file| was opened with
// FILE_FLAG_OVERLAPPED on Windows but this doesn't appear to be possible.
file.async_ = true;
- return file.Pass();
+ return file;
}
-File& File::operator=(RValue other) {
- if (this != other.object) {
- Close();
- SetPlatformFile(other.object->TakePlatformFile());
- tracing_path_ = other.object->tracing_path_;
- error_details_ = other.object->error_details();
- created_ = other.object->created();
- async_ = other.object->async_;
- }
+File& File::operator=(File&& other) {
+ DCHECK_NE(this, &other);
+ Close();
+ SetPlatformFile(other.TakePlatformFile());
+ tracing_path_ = other.tracing_path_;
+ error_details_ = other.error_details();
+ created_ = other.created();
+ async_ = other.async_;
return *this;
}
#if !defined(OS_NACL)
-void File::Initialize(const FilePath& path, uint32 flags) {
+void File::Initialize(const FilePath& path, uint32_t flags) {
if (path.ReferencesParent()) {
error_details_ = FILE_ERROR_ACCESS_DENIED;
return;
diff --git a/chromium/base/files/file.h b/chromium/base/files/file.h
index 976188b232e..7ab5ca58594 100644
--- a/chromium/base/files/file.h
+++ b/chromium/base/files/file.h
@@ -5,29 +5,27 @@
#ifndef BASE_FILES_FILE_H_
#define BASE_FILES_FILE_H_
-#include "build/build_config.h"
-#if defined(OS_WIN)
-#include <windows.h>
-#endif
-
-#if defined(OS_POSIX)
-#include <sys/stat.h>
-#endif
+#include <stdint.h>
#include <string>
#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/move.h"
#include "base/time/time.h"
+#include "build/build_config.h"
#if defined(OS_WIN)
+#include <windows.h>
#include "base/win/scoped_handle.h"
#endif
+#if defined(OS_POSIX)
+#include <sys/stat.h>
+#endif
+
namespace base {
#if defined(OS_WIN)
@@ -53,7 +51,7 @@ typedef struct stat64 stat_wrapper_t;
// to the OS is not considered const, even if there is no apparent change to
// member variables.
class BASE_EXPORT File {
- MOVE_ONLY_TYPE_FOR_CPP_03(File, RValue)
+ MOVE_ONLY_TYPE_FOR_CPP_03(File)
public:
// FLAG_(OPEN|CREATE).* are mutually exclusive. You should specify exactly one
@@ -85,6 +83,7 @@ class BASE_EXPORT File {
FLAG_TERMINAL_DEVICE = 1 << 16, // Serial port flags.
FLAG_BACKUP_SEMANTICS = 1 << 17, // Used on Windows only.
FLAG_EXECUTE = 1 << 18, // Used on Windows only.
+ FLAG_SEQUENTIAL_SCAN = 1 << 19, // Used on Windows only.
};
// This enum has been recorded in multiple histograms. If the order of the
@@ -137,7 +136,7 @@ class BASE_EXPORT File {
#endif
// The size of the file in bytes. Undefined when is_directory is true.
- int64 size;
+ int64_t size;
// True if the file corresponds to a directory.
bool is_directory;
@@ -160,7 +159,7 @@ class BASE_EXPORT File {
// Creates or opens the given file. This will fail with 'access denied' if the
// |path| contains path traversal ('..') components.
- File(const FilePath& path, uint32 flags);
+ File(const FilePath& path, uint32_t flags);
// Takes ownership of |platform_file|.
explicit File(PlatformFile platform_file);
@@ -168,20 +167,21 @@ class BASE_EXPORT File {
// Creates an object with a specific error_details code.
explicit File(Error error_details);
- // Move constructor for C++03 move emulation of this type.
- File(RValue other);
+ File(File&& other);
~File();
// Takes ownership of |platform_file|.
static File CreateForAsyncHandle(PlatformFile platform_file);
- // Move operator= for C++03 move emulation of this type.
- File& operator=(RValue other);
+ File& operator=(File&& other);
// Creates or opens the given file.
- void Initialize(const FilePath& path, uint32 flags);
+ void Initialize(const FilePath& path, uint32_t flags);
+ // Returns |true| if the handle / fd wrapped by this object is valid. This
+ // method doesn't interact with the file system (and is safe to be called from
+ // ThreadRestrictions::SetIOAllowed(false) threads).
bool IsValid() const;
// Returns true if a new file was created (or an old one truncated to zero
@@ -205,7 +205,7 @@ class BASE_EXPORT File {
// Changes current position in the file to an |offset| relative to an origin
// defined by |whence|. Returns the resultant current position in the file
// (relative to the start) or -1 in case of error.
- int64 Seek(Whence whence, int64 offset);
+ int64_t Seek(Whence whence, int64_t offset);
// Reads the given number of bytes (or until EOF is reached) starting with the
// given offset. Returns the number of bytes read, or -1 on error. Note that
@@ -213,7 +213,7 @@ class BASE_EXPORT File {
// is not intended for stream oriented files but instead for cases when the
// normal expectation is that actually |size| bytes are read unless there is
// an error.
- int Read(int64 offset, char* data, int size);
+ int Read(int64_t offset, char* data, int size);
// Same as above but without seek.
int ReadAtCurrentPos(char* data, int size);
@@ -221,7 +221,7 @@ class BASE_EXPORT File {
// Reads the given number of bytes (or until EOF is reached) starting with the
// given offset, but does not make any effort to read all data on all
// platforms. Returns the number of bytes read, or -1 on error.
- int ReadNoBestEffort(int64 offset, char* data, int size);
+ int ReadNoBestEffort(int64_t offset, char* data, int size);
// Same as above but without seek.
int ReadAtCurrentPosNoBestEffort(char* data, int size);
@@ -232,7 +232,7 @@ class BASE_EXPORT File {
// all platforms.
// Ignores the offset and writes to the end of the file if the file was opened
// with FLAG_APPEND.
- int Write(int64 offset, const char* data, int size);
+ int Write(int64_t offset, const char* data, int size);
// Save as above but without seek.
int WriteAtCurrentPos(const char* data, int size);
@@ -242,12 +242,12 @@ class BASE_EXPORT File {
int WriteAtCurrentPosNoBestEffort(const char* data, int size);
// Returns the current size of this file, or a negative number on failure.
- int64 GetLength();
+ int64_t GetLength();
// Truncates the file to the given length. If |length| is greater than the
// current size of the file, the file is extended with zeros. If the file
// doesn't exist, |false| is returned.
- bool SetLength(int64 length);
+ bool SetLength(int64_t length);
// Instructs the filesystem to flush the file to disk. (POSIX: fsync, Windows:
// FlushFileBuffers).
@@ -307,7 +307,7 @@ class BASE_EXPORT File {
// Creates or opens the given file. Only called if |path| has no
// traversal ('..') components.
- void DoInitialize(const FilePath& path, uint32 flags);
+ void DoInitialize(const FilePath& path, uint32_t flags);
// TODO(tnagel): Reintegrate into Flush() once histogram isn't needed anymore,
// cf. issue 473337.
diff --git a/chromium/base/files/file_enumerator.h b/chromium/base/files/file_enumerator.h
index 38bb8337c70..7cac8dd9d45 100644
--- a/chromium/base/files/file_enumerator.h
+++ b/chromium/base/files/file_enumerator.h
@@ -5,12 +5,15 @@
#ifndef BASE_FILES_FILE_ENUMERATOR_H_
#define BASE_FILES_FILE_ENUMERATOR_H_
+#include <stddef.h>
+#include <stdint.h>
+
#include <stack>
#include <vector>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/files/file_path.h"
+#include "base/macros.h"
#include "base/time/time.h"
#include "build/build_config.h"
@@ -49,7 +52,7 @@ class BASE_EXPORT FileEnumerator {
// includes the |root_path| passed into the FileEnumerator constructor.
FilePath GetName() const;
- int64 GetSize() const;
+ int64_t GetSize() const;
Time GetLastModifiedTime() const;
#if defined(OS_WIN)
diff --git a/chromium/base/files/file_enumerator_posix.cc b/chromium/base/files/file_enumerator_posix.cc
index 7533a24c352..fb4010aadca 100644
--- a/chromium/base/files/file_enumerator_posix.cc
+++ b/chromium/base/files/file_enumerator_posix.cc
@@ -7,9 +7,11 @@
#include <dirent.h>
#include <errno.h>
#include <fnmatch.h>
+#include <stdint.h>
#include "base/logging.h"
#include "base/threading/thread_restrictions.h"
+#include "build/build_config.h"
namespace base {
@@ -27,7 +29,7 @@ FilePath FileEnumerator::FileInfo::GetName() const {
return filename_;
}
-int64 FileEnumerator::FileInfo::GetSize() const {
+int64_t FileEnumerator::FileInfo::GetSize() const {
return stat_.st_size;
}
diff --git a/chromium/base/files/file_enumerator_win.cc b/chromium/base/files/file_enumerator_win.cc
index 90db7f5729e..402a07209a8 100644
--- a/chromium/base/files/file_enumerator_win.cc
+++ b/chromium/base/files/file_enumerator_win.cc
@@ -4,6 +4,7 @@
#include "base/files/file_enumerator.h"
+#include <stdint.h>
#include <string.h>
#include "base/logging.h"
@@ -26,13 +27,13 @@ FilePath FileEnumerator::FileInfo::GetName() const {
return FilePath(find_data_.cFileName);
}
-int64 FileEnumerator::FileInfo::GetSize() const {
+int64_t FileEnumerator::FileInfo::GetSize() const {
ULARGE_INTEGER size;
size.HighPart = find_data_.nFileSizeHigh;
size.LowPart = find_data_.nFileSizeLow;
DCHECK_LE(size.QuadPart,
- static_cast<ULONGLONG>(std::numeric_limits<int64>::max()));
- return static_cast<int64>(size.QuadPart);
+ static_cast<ULONGLONG>(std::numeric_limits<int64_t>::max()));
+ return static_cast<int64_t>(size.QuadPart);
}
base::Time FileEnumerator::FileInfo::GetLastModifiedTime() const {
diff --git a/chromium/base/files/file_locking_unittest.cc b/chromium/base/files/file_locking_unittest.cc
new file mode 100644
index 00000000000..d9a1755563e
--- /dev/null
+++ b/chromium/base/files/file_locking_unittest.cc
@@ -0,0 +1,226 @@
+// 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/command_line.h"
+#include "base/files/file.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/macros.h"
+#include "base/test/multiprocess_test.h"
+#include "base/test/test_timeouts.h"
+#include "base/threading/platform_thread.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
+
+using base::File;
+using base::FilePath;
+
+namespace {
+
+// Flag for the parent to share a temp dir to the child.
+const char kTempDirFlag[] = "temp-dir";
+
+// Flags to control how the subprocess unlocks the file.
+const char kFileUnlock[] = "file-unlock";
+const char kCloseUnlock[] = "close-unlock";
+const char kExitUnlock[] = "exit-unlock";
+
+// File to lock in temp dir.
+const char kLockFile[] = "lockfile";
+
+// Constants for various requests and responses, used as |signal_file| parameter
+// to signal/wait helpers.
+const char kSignalLockFileLocked[] = "locked.signal";
+const char kSignalLockFileClose[] = "close.signal";
+const char kSignalLockFileClosed[] = "closed.signal";
+const char kSignalLockFileUnlock[] = "unlock.signal";
+const char kSignalLockFileUnlocked[] = "unlocked.signal";
+const char kSignalExit[] = "exit.signal";
+
+// Signal an event by creating a file which didn't previously exist.
+bool SignalEvent(const FilePath& signal_dir, const char* signal_file) {
+ File file(signal_dir.AppendASCII(signal_file),
+ File::FLAG_CREATE | File::FLAG_WRITE);
+ return file.IsValid();
+}
+
+// Check whether an event was signaled.
+bool CheckEvent(const FilePath& signal_dir, const char* signal_file) {
+ File file(signal_dir.AppendASCII(signal_file),
+ File::FLAG_OPEN | File::FLAG_READ);
+ return file.IsValid();
+}
+
+// Busy-wait for an event to be signaled, returning false for timeout.
+bool WaitForEventWithTimeout(const FilePath& signal_dir,
+ const char* signal_file,
+ const base::TimeDelta& timeout) {
+ const base::Time finish_by = base::Time::Now() + timeout;
+ while (!CheckEvent(signal_dir, signal_file)) {
+ if (base::Time::Now() > finish_by)
+ return false;
+ base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10));
+ }
+ return true;
+}
+
+// Wait forever for the event to be signaled (should never return false).
+bool WaitForEvent(const FilePath& signal_dir, const char* signal_file) {
+ return WaitForEventWithTimeout(signal_dir, signal_file,
+ base::TimeDelta::Max());
+}
+
+// Keep these in sync so StartChild*() can refer to correct test main.
+#define ChildMain ChildLockUnlock
+#define ChildMainString "ChildLockUnlock"
+
+// Subprocess to test getting a file lock then releasing it. |kTempDirFlag|
+// must pass in an existing temporary directory for the lockfile and signal
+// files. One of the following flags must be passed to determine how to unlock
+// the lock file:
+// - |kFileUnlock| calls Unlock() to unlock.
+// - |kCloseUnlock| calls Close() while the lock is held.
+// - |kExitUnlock| exits while the lock is held.
+MULTIPROCESS_TEST_MAIN(ChildMain) {
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ const FilePath temp_path = command_line->GetSwitchValuePath(kTempDirFlag);
+ CHECK(base::DirectoryExists(temp_path));
+
+ // Immediately lock the file.
+ File file(temp_path.AppendASCII(kLockFile),
+ File::FLAG_OPEN | File::FLAG_READ | File::FLAG_WRITE);
+ CHECK(file.IsValid());
+ CHECK_EQ(File::FILE_OK, file.Lock());
+ CHECK(SignalEvent(temp_path, kSignalLockFileLocked));
+
+ if (command_line->HasSwitch(kFileUnlock)) {
+ // Wait for signal to unlock, then unlock the file.
+ CHECK(WaitForEvent(temp_path, kSignalLockFileUnlock));
+ CHECK_EQ(File::FILE_OK, file.Unlock());
+ CHECK(SignalEvent(temp_path, kSignalLockFileUnlocked));
+ } else if (command_line->HasSwitch(kCloseUnlock)) {
+ // Wait for the signal to close, then close the file.
+ CHECK(WaitForEvent(temp_path, kSignalLockFileClose));
+ file.Close();
+ CHECK(!file.IsValid());
+ CHECK(SignalEvent(temp_path, kSignalLockFileClosed));
+ } else {
+ CHECK(command_line->HasSwitch(kExitUnlock));
+ }
+
+ // Wait for signal to exit, so that unlock or close can be distinguished from
+ // exit.
+ CHECK(WaitForEvent(temp_path, kSignalExit));
+ return 0;
+}
+
+} // namespace
+
+class FileLockingTest : public testing::Test {
+ public:
+ FileLockingTest() {}
+
+ protected:
+ void SetUp() override {
+ testing::Test::SetUp();
+
+ // Setup the temp dir and the lock file.
+ ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+ lock_file_.Initialize(
+ temp_dir_.path().AppendASCII(kLockFile),
+ File::FLAG_CREATE | File::FLAG_READ | File::FLAG_WRITE);
+ ASSERT_TRUE(lock_file_.IsValid());
+ }
+
+ bool SignalEvent(const char* signal_file) {
+ return ::SignalEvent(temp_dir_.path(), signal_file);
+ }
+
+ bool WaitForEventOrTimeout(const char* signal_file) {
+ return ::WaitForEventWithTimeout(temp_dir_.path(), signal_file,
+ TestTimeouts::action_timeout());
+ }
+
+ // Start a child process set to use the specified unlock action, and wait for
+ // it to lock the file.
+ void StartChildAndSignalLock(const char* unlock_action) {
+ // Create a temporary dir and spin up a ChildLockExit subprocess against it.
+ const FilePath temp_path = temp_dir_.path();
+ base::CommandLine child_command_line(
+ base::GetMultiProcessTestChildBaseCommandLine());
+ child_command_line.AppendSwitchPath(kTempDirFlag, temp_path);
+ child_command_line.AppendSwitch(unlock_action);
+ lock_child_ =
+ base::SpawnMultiProcessTestChild(ChildMainString, child_command_line,
+ base::LaunchOptions());
+ ASSERT_TRUE(lock_child_.IsValid());
+
+ // Wait for the child to lock the file.
+ ASSERT_TRUE(WaitForEventOrTimeout(kSignalLockFileLocked));
+ }
+
+ // Signal the child to exit cleanly.
+ void ExitChildCleanly() {
+ ASSERT_TRUE(SignalEvent(kSignalExit));
+ int rv = -1;
+ ASSERT_TRUE(lock_child_.WaitForExitWithTimeout(
+ TestTimeouts::action_timeout(), &rv));
+ ASSERT_EQ(0, rv);
+ }
+
+ base::ScopedTempDir temp_dir_;
+ base::File lock_file_;
+ base::Process lock_child_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FileLockingTest);
+};
+
+// Test that locks are released by Unlock().
+TEST_F(FileLockingTest, LockAndUnlock) {
+ StartChildAndSignalLock(kFileUnlock);
+
+ ASSERT_NE(File::FILE_OK, lock_file_.Lock());
+ ASSERT_TRUE(SignalEvent(kSignalLockFileUnlock));
+ ASSERT_TRUE(WaitForEventOrTimeout(kSignalLockFileUnlocked));
+ ASSERT_EQ(File::FILE_OK, lock_file_.Lock());
+ ASSERT_EQ(File::FILE_OK, lock_file_.Unlock());
+
+ ExitChildCleanly();
+}
+
+// Test that locks are released on Close().
+TEST_F(FileLockingTest, UnlockOnClose) {
+ StartChildAndSignalLock(kCloseUnlock);
+
+ ASSERT_NE(File::FILE_OK, lock_file_.Lock());
+ ASSERT_TRUE(SignalEvent(kSignalLockFileClose));
+ ASSERT_TRUE(WaitForEventOrTimeout(kSignalLockFileClosed));
+ ASSERT_EQ(File::FILE_OK, lock_file_.Lock());
+ ASSERT_EQ(File::FILE_OK, lock_file_.Unlock());
+
+ ExitChildCleanly();
+}
+
+// Test that locks are released on exit.
+TEST_F(FileLockingTest, UnlockOnExit) {
+ StartChildAndSignalLock(kExitUnlock);
+
+ ASSERT_NE(File::FILE_OK, lock_file_.Lock());
+ ExitChildCleanly();
+ ASSERT_EQ(File::FILE_OK, lock_file_.Lock());
+ ASSERT_EQ(File::FILE_OK, lock_file_.Unlock());
+}
+
+// Test that killing the process releases the lock. This should cover crashing.
+TEST_F(FileLockingTest, UnlockOnTerminate) {
+ // The child will wait for an exit which never arrives.
+ StartChildAndSignalLock(kExitUnlock);
+
+ ASSERT_NE(File::FILE_OK, lock_file_.Lock());
+ ASSERT_TRUE(lock_child_.Terminate(0, true));
+ ASSERT_EQ(File::FILE_OK, lock_file_.Lock());
+ ASSERT_EQ(File::FILE_OK, lock_file_.Unlock());
+}
diff --git a/chromium/base/files/file_path.cc b/chromium/base/files/file_path.cc
index 18775ed9ca9..63e93879a35 100644
--- a/chromium/base/files/file_path.cc
+++ b/chromium/base/files/file_path.cc
@@ -7,13 +7,14 @@
#include <string.h>
#include <algorithm>
-#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/pickle.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
#if defined(OS_MACOSX)
#include "base/mac/scoped_cftyperef.h"
diff --git a/chromium/base/files/file_path.h b/chromium/base/files/file_path.h
index 25b8391c010..89e9cbfb1d5 100644
--- a/chromium/base/files/file_path.h
+++ b/chromium/base/files/file_path.h
@@ -111,6 +111,7 @@
#include "base/base_export.h"
#include "base/compiler_specific.h"
#include "base/containers/hash_tables.h"
+#include "base/macros.h"
#include "base/strings/string16.h"
#include "base/strings/string_piece.h"
#include "build/build_config.h"
@@ -124,6 +125,15 @@
#define FILE_PATH_USES_WIN_SEPARATORS
#endif // OS_WIN
+// To print path names portably use PRIsFP (based on PRIuS and friends from
+// C99 and format_macros.h) like this:
+// base::StringPrintf("Path is %" PRIsFP ".\n", path.value().c_str());
+#if defined(OS_POSIX)
+#define PRIsFP "s"
+#elif defined(OS_WIN)
+#define PRIsFP "ls"
+#endif // OS_WIN
+
namespace base {
class Pickle;
diff --git a/chromium/base/files/file_path_constants.cc b/chromium/base/files/file_path_constants.cc
index 34b17a60b72..0b748466c22 100644
--- a/chromium/base/files/file_path_constants.cc
+++ b/chromium/base/files/file_path_constants.cc
@@ -2,7 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
+
#include "base/files/file_path.h"
+#include "base/macros.h"
namespace base {
diff --git a/chromium/base/files/file_path_unittest.cc b/chromium/base/files/file_path_unittest.cc
index bc0e8432e0e..f57de67911a 100644
--- a/chromium/base/files/file_path_unittest.cc
+++ b/chromium/base/files/file_path_unittest.cc
@@ -2,11 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
+
#include <sstream>
-#include "base/basictypes.h"
#include "base/files/file_path.h"
+#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
diff --git a/chromium/base/files/file_path_watcher.cc b/chromium/base/files/file_path_watcher.cc
index 59ae7059caf..955e6a2a5bb 100644
--- a/chromium/base/files/file_path_watcher.cc
+++ b/chromium/base/files/file_path_watcher.cc
@@ -9,6 +9,7 @@
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
+#include "build/build_config.h"
#if defined(OS_MACOSX) && !defined(OS_IOS)
#include "base/mac/mac_util.h"
diff --git a/chromium/base/files/file_path_watcher.h b/chromium/base/files/file_path_watcher.h
index 4f132aff78a..d5c6db1acfe 100644
--- a/chromium/base/files/file_path_watcher.h
+++ b/chromium/base/files/file_path_watcher.h
@@ -8,9 +8,9 @@
#define BASE_FILES_FILE_PATH_WATCHER_H_
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/callback.h"
#include "base/files/file_path.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/single_thread_task_runner.h"
@@ -62,9 +62,8 @@ class BASE_EXPORT FilePathWatcher {
return task_runner_;
}
- void set_task_runner(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
- task_runner_ = task_runner.Pass();
+ void set_task_runner(scoped_refptr<base::SingleThreadTaskRunner> runner) {
+ task_runner_ = std::move(runner);
}
// Must be called before the PlatformDelegate is deleted.
diff --git a/chromium/base/files/file_path_watcher_fsevents.cc b/chromium/base/files/file_path_watcher_fsevents.cc
index da01c431bfe..78637aa5a54 100644
--- a/chromium/base/files/file_path_watcher_fsevents.cc
+++ b/chromium/base/files/file_path_watcher_fsevents.cc
@@ -12,6 +12,7 @@
#include "base/logging.h"
#include "base/mac/libdispatch_task_runner.h"
#include "base/mac/scoped_cftyperef.h"
+#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "base/thread_task_runner_handle.h"
diff --git a/chromium/base/files/file_path_watcher_fsevents.h b/chromium/base/files/file_path_watcher_fsevents.h
index 300aa761dfa..1ebe4636e4b 100644
--- a/chromium/base/files/file_path_watcher_fsevents.h
+++ b/chromium/base/files/file_path_watcher_fsevents.h
@@ -6,11 +6,13 @@
#define BASE_FILES_FILE_PATH_WATCHER_FSEVENTS_H_
#include <CoreServices/CoreServices.h>
+#include <stddef.h>
#include <vector>
#include "base/files/file_path.h"
#include "base/files/file_path_watcher.h"
+#include "base/macros.h"
namespace base {
diff --git a/chromium/base/files/file_path_watcher_kqueue.cc b/chromium/base/files/file_path_watcher_kqueue.cc
index e15cba7d341..4d2b1d54f0e 100644
--- a/chromium/base/files/file_path_watcher_kqueue.cc
+++ b/chromium/base/files/file_path_watcher_kqueue.cc
@@ -5,6 +5,7 @@
#include "base/files/file_path_watcher_kqueue.h"
#include <fcntl.h>
+#include <stddef.h>
#include <sys/param.h>
#include "base/bind.h"
diff --git a/chromium/base/files/file_path_watcher_kqueue.h b/chromium/base/files/file_path_watcher_kqueue.h
index 69555a30032..d9db8c2587a 100644
--- a/chromium/base/files/file_path_watcher_kqueue.h
+++ b/chromium/base/files/file_path_watcher_kqueue.h
@@ -10,6 +10,7 @@
#include "base/files/file_path.h"
#include "base/files/file_path_watcher.h"
+#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "base/single_thread_task_runner.h"
diff --git a/chromium/base/files/file_path_watcher_linux.cc b/chromium/base/files/file_path_watcher_linux.cc
index 6dfc0a6403e..a75eaba7db9 100644
--- a/chromium/base/files/file_path_watcher_linux.cc
+++ b/chromium/base/files/file_path_watcher_linux.cc
@@ -5,6 +5,7 @@
#include "base/files/file_path_watcher.h"
#include <errno.h>
+#include <stddef.h>
#include <string.h>
#include <sys/inotify.h>
#include <sys/ioctl.h>
@@ -25,6 +26,7 @@
#include "base/lazy_instance.h"
#include "base/location.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/posix/eintr_wrapper.h"
#include "base/single_thread_task_runner.h"
diff --git a/chromium/base/files/file_path_watcher_mac.cc b/chromium/base/files/file_path_watcher_mac.cc
index 6f55ba4f892..7338eafa444 100644
--- a/chromium/base/files/file_path_watcher_mac.cc
+++ b/chromium/base/files/file_path_watcher_mac.cc
@@ -4,6 +4,7 @@
#include "base/files/file_path_watcher.h"
#include "base/files/file_path_watcher_kqueue.h"
+#include "build/build_config.h"
#if !defined(OS_IOS)
#include "base/files/file_path_watcher_fsevents.h"
diff --git a/chromium/base/files/file_path_watcher_unittest.cc b/chromium/base/files/file_path_watcher_unittest.cc
index 21e9dd137e2..a860b130995 100644
--- a/chromium/base/files/file_path_watcher_unittest.cc
+++ b/chromium/base/files/file_path_watcher_unittest.cc
@@ -13,7 +13,6 @@
#include <set>
-#include "base/basictypes.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/compiler_specific.h"
@@ -21,6 +20,7 @@
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/location.h"
+#include "base/macros.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
@@ -30,6 +30,7 @@
#include "base/test/test_timeouts.h"
#include "base/thread_task_runner_handle.h"
#include "base/threading/thread.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#if defined(OS_ANDROID)
diff --git a/chromium/base/files/file_path_watcher_win.cc b/chromium/base/files/file_path_watcher_win.cc
index 3f37cec51c1..29436e7c09f 100644
--- a/chromium/base/files/file_path_watcher_win.cc
+++ b/chromium/base/files/file_path_watcher_win.cc
@@ -9,6 +9,7 @@
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/thread_task_runner_handle.h"
#include "base/time/time.h"
diff --git a/chromium/base/files/file_posix.cc b/chromium/base/files/file_posix.cc
index a5aee01aa29..462fbd6d336 100644
--- a/chromium/base/files/file_posix.cc
+++ b/chromium/base/files/file_posix.cc
@@ -6,6 +6,7 @@
#include <errno.h>
#include <fcntl.h>
+#include <stdint.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -14,6 +15,7 @@
#include "base/posix/eintr_wrapper.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_restrictions.h"
+#include "build/build_config.h"
#if defined(OS_ANDROID)
#include "base/os_compat_android.h"
@@ -22,19 +24,19 @@
namespace base {
// Make sure our Whence mappings match the system headers.
-COMPILE_ASSERT(File::FROM_BEGIN == SEEK_SET &&
- File::FROM_CURRENT == SEEK_CUR &&
- File::FROM_END == SEEK_END, whence_matches_system);
+static_assert(File::FROM_BEGIN == SEEK_SET && File::FROM_CURRENT == SEEK_CUR &&
+ File::FROM_END == SEEK_END,
+ "whence mapping must match the system headers");
namespace {
#if defined(OS_BSD) || defined(OS_MACOSX) || defined(OS_NACL)
-static int CallFstat(int fd, stat_wrapper_t *sb) {
+int CallFstat(int fd, stat_wrapper_t *sb) {
ThreadRestrictions::AssertIOAllowed();
return fstat(fd, sb);
}
#else
-static int CallFstat(int fd, stat_wrapper_t *sb) {
+int CallFstat(int fd, stat_wrapper_t *sb) {
ThreadRestrictions::AssertIOAllowed();
return fstat64(fd, sb);
}
@@ -43,15 +45,15 @@ static int CallFstat(int fd, stat_wrapper_t *sb) {
// NaCl doesn't provide the following system calls, so either simulate them or
// wrap them in order to minimize the number of #ifdef's in this file.
#if !defined(OS_NACL)
-static bool IsOpenAppend(PlatformFile file) {
+bool IsOpenAppend(PlatformFile file) {
return (fcntl(file, F_GETFL) & O_APPEND) != 0;
}
-static int CallFtruncate(PlatformFile file, int64 length) {
+int CallFtruncate(PlatformFile file, int64_t length) {
return HANDLE_EINTR(ftruncate(file, length));
}
-static int CallFutimes(PlatformFile file, const struct timeval times[2]) {
+int CallFutimes(PlatformFile file, const struct timeval times[2]) {
#ifdef __USE_XOPEN2K8
// futimens should be available, but futimes might not be
// http://pubs.opengroup.org/onlinepubs/9699919799/
@@ -68,36 +70,36 @@ static int CallFutimes(PlatformFile file, const struct timeval times[2]) {
#endif
}
-static File::Error CallFctnlFlock(PlatformFile file, bool do_lock) {
+File::Error CallFcntlFlock(PlatformFile file, bool do_lock) {
struct flock lock;
- lock.l_type = F_WRLCK;
+ lock.l_type = do_lock ? F_WRLCK : F_UNLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0; // Lock entire file.
- if (HANDLE_EINTR(fcntl(file, do_lock ? F_SETLK : F_UNLCK, &lock)) == -1)
+ if (HANDLE_EINTR(fcntl(file, F_SETLK, &lock)) == -1)
return File::OSErrorToFileError(errno);
return File::FILE_OK;
}
#else // defined(OS_NACL)
-static bool IsOpenAppend(PlatformFile file) {
+bool IsOpenAppend(PlatformFile file) {
// NaCl doesn't implement fcntl. Since NaCl's write conforms to the POSIX
// standard and always appends if the file is opened with O_APPEND, just
// return false here.
return false;
}
-static int CallFtruncate(PlatformFile file, int64 length) {
+int CallFtruncate(PlatformFile file, int64_t length) {
NOTIMPLEMENTED(); // NaCl doesn't implement ftruncate.
return 0;
}
-static int CallFutimes(PlatformFile file, const struct timeval times[2]) {
+int CallFutimes(PlatformFile file, const struct timeval times[2]) {
NOTIMPLEMENTED(); // NaCl doesn't implement futimes.
return 0;
}
-static File::Error CallFctnlFlock(PlatformFile file, bool do_lock) {
+File::Error CallFcntlFlock(PlatformFile file, bool do_lock) {
NOTIMPLEMENTED(); // NaCl doesn't implement flock struct.
return File::FILE_ERROR_INVALID_OPERATION;
}
@@ -112,32 +114,32 @@ void File::Info::FromStat(const stat_wrapper_t& stat_info) {
#if defined(OS_LINUX)
time_t last_modified_sec = stat_info.st_mtim.tv_sec;
- int64 last_modified_nsec = stat_info.st_mtim.tv_nsec;
+ int64_t last_modified_nsec = stat_info.st_mtim.tv_nsec;
time_t last_accessed_sec = stat_info.st_atim.tv_sec;
- int64 last_accessed_nsec = stat_info.st_atim.tv_nsec;
+ int64_t last_accessed_nsec = stat_info.st_atim.tv_nsec;
time_t creation_time_sec = stat_info.st_ctim.tv_sec;
- int64 creation_time_nsec = stat_info.st_ctim.tv_nsec;
+ int64_t creation_time_nsec = stat_info.st_ctim.tv_nsec;
#elif defined(OS_ANDROID)
time_t last_modified_sec = stat_info.st_mtime;
- int64 last_modified_nsec = stat_info.st_mtime_nsec;
+ int64_t last_modified_nsec = stat_info.st_mtime_nsec;
time_t last_accessed_sec = stat_info.st_atime;
- int64 last_accessed_nsec = stat_info.st_atime_nsec;
+ int64_t last_accessed_nsec = stat_info.st_atime_nsec;
time_t creation_time_sec = stat_info.st_ctime;
- int64 creation_time_nsec = stat_info.st_ctime_nsec;
+ int64_t creation_time_nsec = stat_info.st_ctime_nsec;
#elif defined(OS_MACOSX) || defined(OS_IOS) || defined(OS_BSD)
time_t last_modified_sec = stat_info.st_mtimespec.tv_sec;
- int64 last_modified_nsec = stat_info.st_mtimespec.tv_nsec;
+ int64_t last_modified_nsec = stat_info.st_mtimespec.tv_nsec;
time_t last_accessed_sec = stat_info.st_atimespec.tv_sec;
- int64 last_accessed_nsec = stat_info.st_atimespec.tv_nsec;
+ int64_t last_accessed_nsec = stat_info.st_atimespec.tv_nsec;
time_t creation_time_sec = stat_info.st_ctimespec.tv_sec;
- int64 creation_time_nsec = stat_info.st_ctimespec.tv_nsec;
+ int64_t creation_time_nsec = stat_info.st_ctimespec.tv_nsec;
#else
time_t last_modified_sec = stat_info.st_mtime;
- int64 last_modified_nsec = 0;
+ int64_t last_modified_nsec = 0;
time_t last_accessed_sec = stat_info.st_atime;
- int64 last_accessed_nsec = 0;
+ int64_t last_accessed_nsec = 0;
time_t creation_time_sec = stat_info.st_ctime;
- int64 creation_time_nsec = 0;
+ int64_t creation_time_nsec = 0;
#endif
last_modified =
@@ -177,24 +179,24 @@ void File::Close() {
file_.reset();
}
-int64 File::Seek(Whence whence, int64 offset) {
+int64_t File::Seek(Whence whence, int64_t offset) {
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);
+ static_assert(sizeof(int64_t) == sizeof(off64_t), "off64_t must be 64 bits");
return lseek64(file_.get(), static_cast<off64_t>(offset),
static_cast<int>(whence));
#else
- COMPILE_ASSERT(sizeof(int64) == sizeof(off_t), off_t_64_bit);
+ static_assert(sizeof(int64_t) == sizeof(off_t), "off_t must be 64 bits");
return lseek(file_.get(), static_cast<off_t>(offset),
static_cast<int>(whence));
#endif
}
-int File::Read(int64 offset, char* data, int size) {
+int File::Read(int64_t offset, char* data, int size) {
ThreadRestrictions::AssertIOAllowed();
DCHECK(IsValid());
if (size < 0)
@@ -237,7 +239,7 @@ int File::ReadAtCurrentPos(char* data, int size) {
return bytes_read ? bytes_read : rv;
}
-int File::ReadNoBestEffort(int64 offset, char* data, int size) {
+int File::ReadNoBestEffort(int64_t offset, char* data, int size) {
ThreadRestrictions::AssertIOAllowed();
DCHECK(IsValid());
SCOPED_FILE_TRACE_WITH_SIZE("ReadNoBestEffort", size);
@@ -254,7 +256,7 @@ int File::ReadAtCurrentPosNoBestEffort(char* data, int size) {
return HANDLE_EINTR(read(file_.get(), data, size));
}
-int File::Write(int64 offset, const char* data, int size) {
+int File::Write(int64_t offset, const char* data, int size) {
ThreadRestrictions::AssertIOAllowed();
if (IsOpenAppend(file_.get()))
@@ -312,7 +314,7 @@ int File::WriteAtCurrentPosNoBestEffort(const char* data, int size) {
return HANDLE_EINTR(write(file_.get(), data, size));
}
-int64 File::GetLength() {
+int64_t File::GetLength() {
DCHECK(IsValid());
SCOPED_FILE_TRACE("GetLength");
@@ -324,7 +326,7 @@ int64 File::GetLength() {
return file_info.st_size;
}
-bool File::SetLength(int64 length) {
+bool File::SetLength(int64_t length) {
ThreadRestrictions::AssertIOAllowed();
DCHECK(IsValid());
@@ -360,12 +362,12 @@ bool File::GetInfo(Info* info) {
File::Error File::Lock() {
SCOPED_FILE_TRACE("Lock");
- return CallFctnlFlock(file_.get(), true);
+ return CallFcntlFlock(file_.get(), true);
}
File::Error File::Unlock() {
SCOPED_FILE_TRACE("Unlock");
- return CallFctnlFlock(file_.get(), false);
+ return CallFcntlFlock(file_.get(), false);
}
File File::Duplicate() {
@@ -381,7 +383,7 @@ File File::Duplicate() {
File other(other_fd);
if (async())
other.async_ = true;
- return other.Pass();
+ return other;
}
// Static.
@@ -423,7 +425,7 @@ File::Error File::OSErrorToFileError(int saved_errno) {
// 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(const FilePath& path, uint32 flags) {
+void File::DoInitialize(const FilePath& path, uint32_t flags) {
ThreadRestrictions::AssertIOAllowed();
DCHECK(!IsValid());
@@ -471,7 +473,7 @@ void File::DoInitialize(const FilePath& path, uint32 flags) {
else if (flags & FLAG_APPEND)
open_flags |= O_APPEND | O_WRONLY;
- COMPILE_ASSERT(O_RDONLY == 0, O_RDONLY_must_equal_zero);
+ static_assert(O_RDONLY == 0, "O_RDONLY must equal zero");
int mode = S_IRUSR | S_IWUSR;
#if defined(OS_CHROMEOS)
diff --git a/chromium/base/files/file_proxy.cc b/chromium/base/files/file_proxy.cc
index f995735d5bc..f157d4d4caa 100644
--- a/chromium/base/files/file_proxy.cc
+++ b/chromium/base/files/file_proxy.cc
@@ -4,11 +4,14 @@
#include "base/files/file_proxy.h"
+#include <utility>
+
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/files/file.h"
#include "base/files/file_util.h"
#include "base/location.h"
+#include "base/macros.h"
#include "base/task_runner.h"
#include "base/task_runner_util.h"
@@ -24,7 +27,7 @@ namespace base {
class FileHelper {
public:
FileHelper(FileProxy* proxy, File file)
- : file_(file.Pass()),
+ : file_(std::move(file)),
error_(File::FILE_ERROR_FAILED),
task_runner_(proxy->task_runner()),
proxy_(AsWeakPtr(proxy)) {
@@ -32,7 +35,7 @@ class FileHelper {
void PassFile() {
if (proxy_)
- proxy_->SetFile(file_.Pass());
+ proxy_->SetFile(std::move(file_));
else if (file_.IsValid())
task_runner_->PostTask(FROM_HERE, Bind(&FileDeleter, Passed(&file_)));
}
@@ -52,7 +55,7 @@ namespace {
class GenericFileHelper : public FileHelper {
public:
GenericFileHelper(FileProxy* proxy, File file)
- : FileHelper(proxy, file.Pass()) {
+ : FileHelper(proxy, std::move(file)) {
}
void Close() {
@@ -65,7 +68,7 @@ class GenericFileHelper : public FileHelper {
error_ = rv ? File::FILE_OK : File::FILE_ERROR_FAILED;
}
- void SetLength(int64 length) {
+ void SetLength(int64_t length) {
if (file_.SetLength(length))
error_ = File::FILE_OK;
}
@@ -88,7 +91,7 @@ class GenericFileHelper : public FileHelper {
class CreateOrOpenHelper : public FileHelper {
public:
CreateOrOpenHelper(FileProxy* proxy, File file)
- : FileHelper(proxy, file.Pass()) {
+ : FileHelper(proxy, std::move(file)) {
}
void RunWork(const FilePath& file_path, int file_flags) {
@@ -109,10 +112,10 @@ class CreateOrOpenHelper : public FileHelper {
class CreateTemporaryHelper : public FileHelper {
public:
CreateTemporaryHelper(FileProxy* proxy, File file)
- : FileHelper(proxy, file.Pass()) {
+ : FileHelper(proxy, std::move(file)) {
}
- void RunWork(uint32 additional_file_flags) {
+ void RunWork(uint32_t additional_file_flags) {
// TODO(darin): file_util should have a variant of CreateTemporaryFile
// that returns a FilePath and a File.
if (!CreateTemporaryFile(&file_path_)) {
@@ -122,10 +125,8 @@ class CreateTemporaryHelper : public FileHelper {
return;
}
- uint32 file_flags = File::FLAG_WRITE |
- File::FLAG_TEMPORARY |
- File::FLAG_CREATE_ALWAYS |
- additional_file_flags;
+ uint32_t file_flags = File::FLAG_WRITE | File::FLAG_TEMPORARY |
+ File::FLAG_CREATE_ALWAYS | additional_file_flags;
file_.Initialize(file_path_, file_flags);
if (file_.IsValid()) {
@@ -151,7 +152,7 @@ class CreateTemporaryHelper : public FileHelper {
class GetInfoHelper : public FileHelper {
public:
GetInfoHelper(FileProxy* proxy, File file)
- : FileHelper(proxy, file.Pass()) {
+ : FileHelper(proxy, std::move(file)) {
}
void RunWork() {
@@ -173,13 +174,13 @@ class GetInfoHelper : public FileHelper {
class ReadHelper : public FileHelper {
public:
ReadHelper(FileProxy* proxy, File file, int bytes_to_read)
- : FileHelper(proxy, file.Pass()),
+ : FileHelper(proxy, std::move(file)),
buffer_(new char[bytes_to_read]),
bytes_to_read_(bytes_to_read),
bytes_read_(0) {
}
- void RunWork(int64 offset) {
+ void RunWork(int64_t offset) {
bytes_read_ = file_.Read(offset, buffer_.get(), bytes_to_read_);
error_ = (bytes_read_ < 0) ? File::FILE_ERROR_FAILED : File::FILE_OK;
}
@@ -202,14 +203,14 @@ class WriteHelper : public FileHelper {
WriteHelper(FileProxy* proxy,
File file,
const char* buffer, int bytes_to_write)
- : FileHelper(proxy, file.Pass()),
+ : FileHelper(proxy, std::move(file)),
buffer_(new char[bytes_to_write]),
bytes_to_write_(bytes_to_write),
bytes_written_(0) {
memcpy(buffer_.get(), buffer, bytes_to_write);
}
- void RunWork(int64 offset) {
+ void RunWork(int64_t offset) {
bytes_written_ = file_.Write(offset, buffer_.get(), bytes_to_write_);
error_ = (bytes_written_ < 0) ? File::FILE_ERROR_FAILED : File::FILE_OK;
}
@@ -238,7 +239,7 @@ FileProxy::~FileProxy() {
}
bool FileProxy::CreateOrOpen(const FilePath& file_path,
- uint32 file_flags,
+ uint32_t file_flags,
const StatusCallback& callback) {
DCHECK(!file_.IsValid());
CreateOrOpenHelper* helper = new CreateOrOpenHelper(this, File());
@@ -249,7 +250,7 @@ bool FileProxy::CreateOrOpen(const FilePath& file_path,
Bind(&CreateOrOpenHelper::Reply, Owned(helper), callback));
}
-bool FileProxy::CreateTemporary(uint32 additional_file_flags,
+bool FileProxy::CreateTemporary(uint32_t additional_file_flags,
const CreateTemporaryCallback& callback) {
DCHECK(!file_.IsValid());
CreateTemporaryHelper* helper = new CreateTemporaryHelper(this, File());
@@ -266,11 +267,11 @@ bool FileProxy::IsValid() const {
void FileProxy::SetFile(File file) {
DCHECK(!file_.IsValid());
- file_ = file.Pass();
+ file_ = std::move(file);
}
File FileProxy::TakeFile() {
- return file_.Pass();
+ return std::move(file_);
}
PlatformFile FileProxy::GetPlatformFile() const {
@@ -279,7 +280,7 @@ PlatformFile FileProxy::GetPlatformFile() const {
bool FileProxy::Close(const StatusCallback& callback) {
DCHECK(file_.IsValid());
- GenericFileHelper* helper = new GenericFileHelper(this, file_.Pass());
+ GenericFileHelper* helper = new GenericFileHelper(this, std::move(file_));
return task_runner_->PostTaskAndReply(
FROM_HERE,
Bind(&GenericFileHelper::Close, Unretained(helper)),
@@ -288,28 +289,28 @@ bool FileProxy::Close(const StatusCallback& callback) {
bool FileProxy::GetInfo(const GetFileInfoCallback& callback) {
DCHECK(file_.IsValid());
- GetInfoHelper* helper = new GetInfoHelper(this, file_.Pass());
+ GetInfoHelper* helper = new GetInfoHelper(this, std::move(file_));
return task_runner_->PostTaskAndReply(
FROM_HERE,
Bind(&GetInfoHelper::RunWork, Unretained(helper)),
Bind(&GetInfoHelper::Reply, Owned(helper), callback));
}
-bool FileProxy::Read(int64 offset,
+bool FileProxy::Read(int64_t offset,
int bytes_to_read,
const ReadCallback& callback) {
DCHECK(file_.IsValid());
if (bytes_to_read < 0)
return false;
- ReadHelper* helper = new ReadHelper(this, file_.Pass(), bytes_to_read);
+ ReadHelper* helper = new ReadHelper(this, std::move(file_), bytes_to_read);
return task_runner_->PostTaskAndReply(
FROM_HERE,
Bind(&ReadHelper::RunWork, Unretained(helper), offset),
Bind(&ReadHelper::Reply, Owned(helper), callback));
}
-bool FileProxy::Write(int64 offset,
+bool FileProxy::Write(int64_t offset,
const char* buffer,
int bytes_to_write,
const WriteCallback& callback) {
@@ -318,7 +319,7 @@ bool FileProxy::Write(int64 offset,
return false;
WriteHelper* helper =
- new WriteHelper(this, file_.Pass(), buffer, bytes_to_write);
+ new WriteHelper(this, std::move(file_), buffer, bytes_to_write);
return task_runner_->PostTaskAndReply(
FROM_HERE,
Bind(&WriteHelper::RunWork, Unretained(helper), offset),
@@ -329,7 +330,7 @@ bool FileProxy::SetTimes(Time last_access_time,
Time last_modified_time,
const StatusCallback& callback) {
DCHECK(file_.IsValid());
- GenericFileHelper* helper = new GenericFileHelper(this, file_.Pass());
+ GenericFileHelper* helper = new GenericFileHelper(this, std::move(file_));
return task_runner_->PostTaskAndReply(
FROM_HERE,
Bind(&GenericFileHelper::SetTimes, Unretained(helper), last_access_time,
@@ -337,9 +338,9 @@ bool FileProxy::SetTimes(Time last_access_time,
Bind(&GenericFileHelper::Reply, Owned(helper), callback));
}
-bool FileProxy::SetLength(int64 length, const StatusCallback& callback) {
+bool FileProxy::SetLength(int64_t length, const StatusCallback& callback) {
DCHECK(file_.IsValid());
- GenericFileHelper* helper = new GenericFileHelper(this, file_.Pass());
+ GenericFileHelper* helper = new GenericFileHelper(this, std::move(file_));
return task_runner_->PostTaskAndReply(
FROM_HERE,
Bind(&GenericFileHelper::SetLength, Unretained(helper), length),
@@ -348,7 +349,7 @@ bool FileProxy::SetLength(int64 length, const StatusCallback& callback) {
bool FileProxy::Flush(const StatusCallback& callback) {
DCHECK(file_.IsValid());
- GenericFileHelper* helper = new GenericFileHelper(this, file_.Pass());
+ GenericFileHelper* helper = new GenericFileHelper(this, std::move(file_));
return task_runner_->PostTaskAndReply(
FROM_HERE,
Bind(&GenericFileHelper::Flush, Unretained(helper)),
diff --git a/chromium/base/files/file_proxy.h b/chromium/base/files/file_proxy.h
index f990d044d37..87037ac05ed 100644
--- a/chromium/base/files/file_proxy.h
+++ b/chromium/base/files/file_proxy.h
@@ -5,10 +5,13 @@
#ifndef BASE_FILES_FILE_PROXY_H_
#define BASE_FILES_FILE_PROXY_H_
+#include <stdint.h>
+
#include "base/base_export.h"
#include "base/callback_forward.h"
#include "base/files/file.h"
#include "base/files/file_path.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
@@ -64,7 +67,7 @@ class BASE_EXPORT FileProxy : public SupportsWeakPtr<FileProxy> {
//
// This returns false if task posting to |task_runner| has failed.
bool CreateOrOpen(const FilePath& file_path,
- uint32 file_flags,
+ uint32_t file_flags,
const StatusCallback& callback);
// Creates a temporary file for writing. The path and an open file are
@@ -75,7 +78,7 @@ class BASE_EXPORT FileProxy : public SupportsWeakPtr<FileProxy> {
// File::FLAG_TEMPORARY.
//
// This returns false if task posting to |task_runner| has failed.
- bool CreateTemporary(uint32 additional_file_flags,
+ bool CreateTemporary(uint32_t additional_file_flags,
const CreateTemporaryCallback& callback);
// Returns true if the underlying |file_| is valid.
@@ -104,12 +107,12 @@ class BASE_EXPORT FileProxy : public SupportsWeakPtr<FileProxy> {
// Proxies File::Read. The callback can't be null.
// This returns false if |bytes_to_read| is less than zero, or
// if task posting to |task_runner| has failed.
- bool Read(int64 offset, int bytes_to_read, const ReadCallback& callback);
+ bool Read(int64_t offset, int bytes_to_read, const ReadCallback& callback);
// Proxies File::Write. The callback can be null.
// This returns false if |bytes_to_write| is less than or equal to zero,
// if |buffer| is NULL, or if task posting to |task_runner| has failed.
- bool Write(int64 offset,
+ bool Write(int64_t offset,
const char* buffer,
int bytes_to_write,
const WriteCallback& callback);
@@ -122,7 +125,7 @@ class BASE_EXPORT FileProxy : public SupportsWeakPtr<FileProxy> {
// Proxies File::SetLength. The callback can be null.
// This returns false if task posting to |task_runner| has failed.
- bool SetLength(int64 length, const StatusCallback& callback);
+ bool SetLength(int64_t length, const StatusCallback& callback);
// Proxies File::Flush. The callback can be null.
// This returns false if task posting to |task_runner| has failed.
diff --git a/chromium/base/files/file_proxy_unittest.cc b/chromium/base/files/file_proxy_unittest.cc
index efe5c924299..2562208b270 100644
--- a/chromium/base/files/file_proxy_unittest.cc
+++ b/chromium/base/files/file_proxy_unittest.cc
@@ -4,13 +4,20 @@
#include "base/files/file_proxy.h"
+#include <stddef.h>
+#include <stdint.h>
+
+#include <utility>
+
#include "base/bind.h"
#include "base/files/file.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
+#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread.h"
#include "base/threading/thread_restrictions.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
@@ -69,7 +76,7 @@ class FileProxyTest : public testing::Test {
}
protected:
- void CreateProxy(uint32 flags, FileProxy* proxy) {
+ void CreateProxy(uint32_t flags, FileProxy* proxy) {
proxy->CreateOrOpen(
test_path(), flags,
Bind(&FileProxyTest::DidCreateOrOpen, weak_factory_.GetWeakPtr()));
@@ -83,10 +90,10 @@ class FileProxyTest : public testing::Test {
const FilePath& test_dir_path() const { return dir_.path(); }
const FilePath test_path() const { return dir_.path().AppendASCII("test"); }
+ ScopedTempDir dir_;
MessageLoopForIO message_loop_;
Thread file_thread_;
- ScopedTempDir dir_;
File::Error error_;
FilePath path_;
File::Info file_info_;
@@ -208,7 +215,7 @@ TEST_F(FileProxyTest, SetAndTake) {
ASSERT_TRUE(file.IsValid());
FileProxy proxy(file_task_runner());
EXPECT_FALSE(proxy.IsValid());
- proxy.SetFile(file.Pass());
+ proxy.SetFile(std::move(file));
EXPECT_TRUE(proxy.IsValid());
EXPECT_FALSE(file.IsValid());
diff --git a/chromium/base/files/file_tracing.cc b/chromium/base/files/file_tracing.cc
index 92a5780b384..6d11cbc746e 100644
--- a/chromium/base/files/file_tracing.cc
+++ b/chromium/base/files/file_tracing.cc
@@ -39,8 +39,9 @@ FileTracing::ScopedTrace::~ScopedTrace() {
g_provider->FileTracingEventEnd(name_, id_);
}
-void FileTracing::ScopedTrace::Initialize(
- const char* name, File* file, int64 size) {
+void FileTracing::ScopedTrace::Initialize(const char* name,
+ File* file,
+ int64_t size) {
id_ = &file->trace_enabler_;
name_ = name;
g_provider->FileTracingEventBegin(name_, id_, file->tracing_path_, size);
diff --git a/chromium/base/files/file_tracing.h b/chromium/base/files/file_tracing.h
index d37c21d9ed4..bedd7be64b2 100644
--- a/chromium/base/files/file_tracing.h
+++ b/chromium/base/files/file_tracing.h
@@ -5,8 +5,9 @@
#ifndef BASE_FILES_FILE_TRACING_H_
#define BASE_FILES_FILE_TRACING_H_
+#include <stdint.h>
+
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/macros.h"
#define FILE_TRACING_PREFIX "File"
@@ -44,8 +45,10 @@ class BASE_EXPORT FileTracing {
// Begins an event for |id| with |name|. |path| tells where in the directory
// structure the event is happening (and may be blank). |size| is the number
// of bytes involved in the event.
- virtual void FileTracingEventBegin(
- const char* name, void* id, const FilePath& path, int64 size) = 0;
+ virtual void FileTracingEventBegin(const char* name,
+ void* id,
+ const FilePath& path,
+ int64_t size) = 0;
// Ends an event for |id| with |name|.
virtual void FileTracingEventEnd(const char* name, void* id) = 0;
@@ -70,7 +73,7 @@ class BASE_EXPORT FileTracing {
// event to trace (e.g. "Read", "Write") and must have an application
// lifetime (e.g. static or literal). |file| is the file being traced; must
// outlive this class. |size| is the size (in bytes) of this event.
- void Initialize(const char* name, File* file, int64 size);
+ void Initialize(const char* name, File* file, int64_t size);
private:
// The ID of this trace. Based on the |file| passed to |Initialize()|. Must
diff --git a/chromium/base/files/file_unittest.cc b/chromium/base/files/file_unittest.cc
index 67dbbfd1ec8..2445f7e1282 100644
--- a/chromium/base/files/file_unittest.cc
+++ b/chromium/base/files/file_unittest.cc
@@ -3,9 +3,15 @@
// found in the LICENSE file.
#include "base/files/file.h"
+
+#include <stdint.h>
+
+#include <utility>
+
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/time/time.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::File;
@@ -199,7 +205,7 @@ TEST(FileTest, ReadWrite) {
EXPECT_EQ(kPartialWriteLength, bytes_written);
// Make sure the file was extended.
- int64 file_size = 0;
+ int64_t file_size = 0;
EXPECT_TRUE(GetFileSize(file_path, &file_size));
EXPECT_EQ(kOffsetBeyondEndOfFile + kPartialWriteLength, file_size);
@@ -240,7 +246,7 @@ TEST(FileTest, Append) {
ASSERT_TRUE(file2.IsValid());
// Test passing the file around.
- file = file2.Pass();
+ file = std::move(file2);
EXPECT_FALSE(file2.IsValid());
ASSERT_TRUE(file.IsValid());
@@ -281,7 +287,7 @@ TEST(FileTest, Length) {
// Extend the file.
const int kExtendedFileLength = 10;
- int64 file_size = 0;
+ int64_t file_size = 0;
EXPECT_TRUE(file.SetLength(kExtendedFileLength));
EXPECT_EQ(kExtendedFileLength, file.GetLength());
EXPECT_TRUE(GetFileSize(file_path, &file_size));
@@ -434,7 +440,7 @@ TEST(FileTest, Seek) {
base::File::FLAG_WRITE);
ASSERT_TRUE(file.IsValid());
- const int64 kOffset = 10;
+ const int64_t kOffset = 10;
EXPECT_EQ(kOffset, file.Seek(base::File::FROM_BEGIN, kOffset));
EXPECT_EQ(2 * kOffset, file.Seek(base::File::FROM_CURRENT, kOffset));
EXPECT_EQ(kOffset, file.Seek(base::File::FROM_CURRENT, -kOffset));
diff --git a/chromium/base/files/file_util.cc b/chromium/base/files/file_util.cc
index 4b6b8886d8a..9e35b671db8 100644
--- a/chromium/base/files/file_util.cc
+++ b/chromium/base/files/file_util.cc
@@ -19,6 +19,7 @@
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
namespace base {
@@ -34,8 +35,8 @@ static const int kMaxUniqueFiles = 100;
} // namespace
-int64 ComputeDirectorySize(const FilePath& root_path) {
- int64 running_size = 0;
+int64_t ComputeDirectorySize(const FilePath& root_path) {
+ int64_t running_size = 0;
FileEnumerator file_iter(root_path, true, FileEnumerator::FILES);
while (!file_iter.Next().empty())
running_size += file_iter.GetInfo().GetSize();
@@ -185,7 +186,7 @@ bool CreateDirectory(const FilePath& full_path) {
return CreateDirectoryAndGetError(full_path, NULL);
}
-bool GetFileSize(const FilePath& file_path, int64* file_size) {
+bool GetFileSize(const FilePath& file_path, int64_t* file_size) {
File::Info info;
if (!GetFileInfo(file_path, &info))
return false;
diff --git a/chromium/base/files/file_util.h b/chromium/base/files/file_util.h
index 7f169f1c54b..dfc10a35bf5 100644
--- a/chromium/base/files/file_util.h
+++ b/chromium/base/files/file_util.h
@@ -8,15 +8,8 @@
#ifndef BASE_FILES_FILE_UTIL_H_
#define BASE_FILES_FILE_UTIL_H_
-#include "build/build_config.h"
-
-#if defined(OS_WIN)
-#include <windows.h>
-#elif defined(OS_POSIX)
-#include <sys/stat.h>
-#include <unistd.h>
-#endif
-
+#include <stddef.h>
+#include <stdint.h>
#include <stdio.h>
#include <set>
@@ -24,11 +17,18 @@
#include <vector>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/string16.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#elif defined(OS_POSIX)
+#include <sys/stat.h>
+#include <unistd.h>
+#endif
#if defined(OS_POSIX)
#include "base/file_descriptor_posix.h"
@@ -53,7 +53,7 @@ BASE_EXPORT FilePath MakeAbsoluteFilePath(const FilePath& input);
//
// This function is implemented using the FileEnumerator class so it is not
// particularly speedy in any platform.
-BASE_EXPORT int64 ComputeDirectorySize(const FilePath& root_path);
+BASE_EXPORT int64_t ComputeDirectorySize(const FilePath& root_path);
// Deletes the given path, whether it's a file or a directory.
// If it's a directory, it's perfectly happy to delete all of the
@@ -265,7 +265,7 @@ BASE_EXPORT bool CreateDirectoryAndGetError(const FilePath& full_path,
BASE_EXPORT bool CreateDirectory(const FilePath& full_path);
// Returns the file size. Returns true on success.
-BASE_EXPORT bool GetFileSize(const FilePath& file_path, int64* file_size);
+BASE_EXPORT bool GetFileSize(const FilePath& file_path, int64_t* file_size);
// Sets |real_path| to |path| with symbolic links and junctions expanded.
// On windows, make sure the path starts with a lettered drive.
@@ -350,6 +350,11 @@ BASE_EXPORT bool SetCurrentDirectory(const FilePath& path);
BASE_EXPORT int GetUniquePathNumber(const FilePath& path,
const FilePath::StringType& suffix);
+// Sets the given |fd| to non-blocking mode.
+// Returns true if it was able to set it in the non-blocking mode, otherwise
+// false.
+BASE_EXPORT bool SetNonBlocking(int fd);
+
#if defined(OS_POSIX)
// Test that |path| can only be changed by a given user and members of
// a given set of groups.
diff --git a/chromium/base/files/file_util_mac.mm b/chromium/base/files/file_util_mac.mm
index a701bad928c..e9c6c651593 100644
--- a/chromium/base/files/file_util_mac.mm
+++ b/chromium/base/files/file_util_mac.mm
@@ -7,7 +7,6 @@
#include <copyfile.h>
#import <Foundation/Foundation.h>
-#include "base/basictypes.h"
#include "base/files/file_path.h"
#include "base/mac/foundation_util.h"
#include "base/strings/string_util.h"
diff --git a/chromium/base/files/file_util_posix.cc b/chromium/base/files/file_util_posix.cc
index ffa79a45f42..7e31bfbbb7f 100644
--- a/chromium/base/files/file_util_posix.cc
+++ b/chromium/base/files/file_util_posix.cc
@@ -9,6 +9,7 @@
#include <fcntl.h>
#include <libgen.h>
#include <limits.h>
+#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -21,16 +22,11 @@
#include <time.h>
#include <unistd.h>
-#if defined(OS_MACOSX)
-#include <AvailabilityMacros.h>
-#include "base/mac/foundation_util.h"
-#endif
-
-#include "base/basictypes.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_path.h"
#include "base/files/scoped_file.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/singleton.h"
#include "base/path_service.h"
@@ -43,6 +39,12 @@
#include "base/sys_info.h"
#include "base/threading/thread_restrictions.h"
#include "base/time/time.h"
+#include "build/build_config.h"
+
+#if defined(OS_MACOSX)
+#include <AvailabilityMacros.h>
+#include "base/mac/foundation_util.h"
+#endif
#if defined(OS_ANDROID)
#include "base/android/content_uri_utils.h"
@@ -348,6 +350,17 @@ bool CopyDirectory(const FilePath& from_path,
}
#endif // !defined(OS_NACL_NONSFI)
+bool SetNonBlocking(int fd) {
+ int flags = fcntl(fd, F_GETFL, 0);
+ if (flags == -1)
+ return false;
+ if (flags & O_NONBLOCK)
+ return true;
+ if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
+ return false;
+ return true;
+}
+
bool PathExists(const FilePath& path) {
ThreadRestrictions::AssertIOAllowed();
#if defined(OS_ANDROID)
@@ -674,7 +687,7 @@ int ReadFile(const FilePath& filename, char* data, int max_size) {
int WriteFile(const FilePath& filename, const char* data, int size) {
ThreadRestrictions::AssertIOAllowed();
- int fd = HANDLE_EINTR(creat(filename.value().c_str(), 0640));
+ int fd = HANDLE_EINTR(creat(filename.value().c_str(), 0666));
if (fd < 0)
return -1;
diff --git a/chromium/base/files/file_util_proxy.cc b/chromium/base/files/file_util_proxy.cc
index 0942e7a2761..633d162599c 100644
--- a/chromium/base/files/file_util_proxy.cc
+++ b/chromium/base/files/file_util_proxy.cc
@@ -8,6 +8,7 @@
#include "base/bind_helpers.h"
#include "base/files/file_util.h"
#include "base/location.h"
+#include "base/macros.h"
#include "base/task_runner.h"
#include "base/task_runner_util.h"
diff --git a/chromium/base/files/file_util_proxy.h b/chromium/base/files/file_util_proxy.h
index 80688cfbb48..db69737648b 100644
--- a/chromium/base/files/file_util_proxy.h
+++ b/chromium/base/files/file_util_proxy.h
@@ -9,6 +9,7 @@
#include "base/callback_forward.h"
#include "base/files/file.h"
#include "base/files/file_path.h"
+#include "base/macros.h"
namespace base {
diff --git a/chromium/base/files/file_util_unittest.cc b/chromium/base/files/file_util_unittest.cc
index 933cb7f46e5..61ccba4902b 100644
--- a/chromium/base/files/file_util_unittest.cc
+++ b/chromium/base/files/file_util_unittest.cc
@@ -2,25 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "build/build_config.h"
-
-#if defined(OS_WIN)
-#include <windows.h>
-#include <shellapi.h>
-#include <shlobj.h>
-#include <tchar.h>
-#include <winioctl.h>
-#endif
-
-#if defined(OS_POSIX)
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#endif
+#include <stddef.h>
+#include <stdint.h>
#include <algorithm>
#include <fstream>
#include <set>
+#include <utility>
#include <vector>
#include "base/base_paths.h"
@@ -29,19 +17,32 @@
#include "base/files/file_util.h"
#include "base/files/scoped_file.h"
#include "base/files/scoped_temp_dir.h"
+#include "base/macros.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"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
#if defined(OS_WIN)
+#include <windows.h>
+#include <shellapi.h>
+#include <shlobj.h>
+#include <tchar.h>
+#include <winioctl.h>
#include "base/win/scoped_handle.h"
#include "base/win/windows_version.h"
#endif
+#if defined(OS_POSIX)
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#endif
+
#if defined(OS_ANDROID)
#include "base/android/content_uri_utils.h"
#endif
@@ -249,7 +250,7 @@ TEST_F(FileUtilTest, FileAndDirectorySize) {
// should return 53 bytes.
FilePath file_01 = temp_dir_.path().Append(FPL("The file 01.txt"));
CreateTextFile(file_01, L"12345678901234567890");
- int64 size_f1 = 0;
+ int64_t size_f1 = 0;
ASSERT_TRUE(GetFileSize(file_01, &size_f1));
EXPECT_EQ(20ll, size_f1);
@@ -258,7 +259,7 @@ TEST_F(FileUtilTest, FileAndDirectorySize) {
FilePath file_02 = subdir_path.Append(FPL("The file 02.txt"));
CreateTextFile(file_02, L"123456789012345678901234567890");
- int64 size_f2 = 0;
+ int64_t size_f2 = 0;
ASSERT_TRUE(GetFileSize(file_02, &size_f2));
EXPECT_EQ(30ll, size_f2);
@@ -268,7 +269,7 @@ TEST_F(FileUtilTest, FileAndDirectorySize) {
FilePath file_03 = subsubdir_path.Append(FPL("The file 03.txt"));
CreateTextFile(file_03, L"123");
- int64 computed_size = ComputeDirectorySize(temp_dir_.path());
+ int64_t computed_size = ComputeDirectorySize(temp_dir_.path());
EXPECT_EQ(size_f1 + size_f2 + 3, computed_size);
}
@@ -353,7 +354,8 @@ TEST_F(FileUtilTest, NormalizeFilePathReparsePoints) {
FilePath long_name = sub_a.Append(FilePath(long_name_str));
FilePath deep_file = long_name.Append(sub_long_rel).Append(deep_txt);
- ASSERT_EQ(MAX_PATH - kCreateDirLimit, deep_file.value().length());
+ ASSERT_EQ(static_cast<size_t>(MAX_PATH - kCreateDirLimit),
+ deep_file.value().length());
FilePath sub_long = deep_file.DirName();
ASSERT_TRUE(CreateDirectory(sub_long));
@@ -720,7 +722,7 @@ TEST_F(FileUtilTest, ChangeFilePermissionsAndRead) {
EXPECT_TRUE(PathExists(file_name));
// Make sure the file is readable.
- int32 mode = 0;
+ int32_t mode = 0;
EXPECT_TRUE(GetPosixFilePermissions(file_name, &mode));
EXPECT_TRUE(mode & FILE_PERMISSION_READ_BY_USER);
@@ -1703,14 +1705,14 @@ TEST_F(FileUtilTest, CreateAndOpenTemporaryFileTest) {
TEST_F(FileUtilTest, FileToFILE) {
File file;
- FILE* stream = FileToFILE(file.Pass(), "w");
+ FILE* stream = FileToFILE(std::move(file), "w");
EXPECT_FALSE(stream);
FilePath file_name = temp_dir_.path().Append(FPL("The file.txt"));
file = File(file_name, File::FLAG_CREATE | File::FLAG_WRITE);
EXPECT_TRUE(file.IsValid());
- stream = FileToFILE(file.Pass(), "w");
+ stream = FileToFILE(std::move(file), "w");
EXPECT_TRUE(stream);
EXPECT_FALSE(file.IsValid());
EXPECT_TRUE(CloseFile(stream));
@@ -2446,7 +2448,7 @@ TEST_F(FileUtilTest, ValidContentUriTest) {
data_dir = data_dir.AppendASCII("file_util");
ASSERT_TRUE(PathExists(data_dir));
FilePath image_file = data_dir.Append(FILE_PATH_LITERAL("red.png"));
- int64 image_size;
+ int64_t image_size;
GetFileSize(image_file, &image_size);
EXPECT_LT(0, image_size);
@@ -2457,7 +2459,7 @@ TEST_F(FileUtilTest, ValidContentUriTest) {
EXPECT_TRUE(PathExists(path));
// The file size may not equal to the input image as MediaStore may convert
// the image.
- int64 content_uri_size;
+ int64_t content_uri_size;
GetFileSize(path, &content_uri_size);
EXPECT_EQ(image_size, content_uri_size);
@@ -2474,7 +2476,7 @@ TEST_F(FileUtilTest, NonExistentContentUriTest) {
EXPECT_TRUE(path.IsContentUri());
EXPECT_FALSE(PathExists(path));
// Size should be smaller than 0.
- int64 size;
+ int64_t size;
EXPECT_FALSE(GetFileSize(path, &size));
// We should not be able to read the file.
diff --git a/chromium/base/files/file_util_win.cc b/chromium/base/files/file_util_win.cc
index e254232f663..d70454df383 100644
--- a/chromium/base/files/file_util_win.cc
+++ b/chromium/base/files/file_util_win.cc
@@ -9,7 +9,10 @@
#include <psapi.h>
#include <shellapi.h>
#include <shlobj.h>
+#include <stddef.h>
+#include <stdint.h>
#include <time.h>
+#include <winsock2.h>
#include <algorithm>
#include <limits>
@@ -18,6 +21,7 @@
#include "base/files/file_enumerator.h"
#include "base/files/file_path.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/metrics/histogram.h"
#include "base/process/process_handle.h"
#include "base/rand_util.h"
@@ -36,6 +40,36 @@ namespace {
const DWORD kFileShareAll =
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
+// Deletes all files and directories in a path.
+// Returns false on the first failure it encounters.
+bool DeleteFileRecursive(const FilePath& path,
+ const FilePath::StringType& pattern,
+ bool recursive) {
+ FileEnumerator traversal(path, false,
+ FileEnumerator::FILES | FileEnumerator::DIRECTORIES,
+ pattern);
+ for (FilePath current = traversal.Next(); !current.empty();
+ current = traversal.Next()) {
+ // Try to clear the read-only bit if we find it.
+ FileEnumerator::FileInfo info = traversal.GetInfo();
+ if ((info.find_data().dwFileAttributes & FILE_ATTRIBUTE_READONLY) &&
+ (recursive || !info.IsDirectory())) {
+ SetFileAttributes(
+ current.value().c_str(),
+ info.find_data().dwFileAttributes & ~FILE_ATTRIBUTE_READONLY);
+ }
+
+ if (info.IsDirectory()) {
+ if (recursive && (!DeleteFileRecursive(current, pattern, true) ||
+ !RemoveDirectory(current.value().c_str())))
+ return false;
+ } else if (!::DeleteFile(current.value().c_str())) {
+ return false;
+ }
+ }
+ return true;
+}
+
} // namespace
FilePath MakeAbsoluteFilePath(const FilePath& input) {
@@ -49,56 +83,36 @@ FilePath MakeAbsoluteFilePath(const FilePath& input) {
bool DeleteFile(const FilePath& path, bool recursive) {
ThreadRestrictions::AssertIOAllowed();
- if (path.value().length() >= MAX_PATH)
- return false;
-
- // On XP SHFileOperation will return ERROR_ACCESS_DENIED instead of
- // ERROR_FILE_NOT_FOUND, so just shortcut this here.
if (path.empty())
return true;
- if (!recursive) {
- // If not recursing, then first check to see if |path| is a directory.
- // If it is, then remove it with RemoveDirectory.
- File::Info file_info;
- if (GetFileInfo(path, &file_info) && file_info.is_directory)
- return RemoveDirectory(path.value().c_str()) != 0;
-
- // Otherwise, it's a file, wildcard or non-existant. Try DeleteFile first
- // because it should be faster. If DeleteFile fails, then we fall through
- // to SHFileOperation, which will do the right thing.
- if (::DeleteFile(path.value().c_str()) != 0)
- return true;
- }
+ if (path.value().length() >= MAX_PATH)
+ return false;
- // SHFILEOPSTRUCT wants the path to be terminated with two NULLs,
- // so we have to use wcscpy because wcscpy_s writes non-NULLs
- // into the rest of the buffer.
- wchar_t double_terminated_path[MAX_PATH + 1] = {0};
-#pragma warning(suppress:4996) // don't complain about wcscpy deprecation
- wcscpy(double_terminated_path, path.value().c_str());
-
- SHFILEOPSTRUCT file_operation = {0};
- file_operation.wFunc = FO_DELETE;
- file_operation.pFrom = double_terminated_path;
- file_operation.fFlags = FOF_NOERRORUI | FOF_SILENT | FOF_NOCONFIRMATION;
- if (!recursive)
- file_operation.fFlags |= FOF_NORECURSION | FOF_FILESONLY;
- int err = SHFileOperation(&file_operation);
-
- // Since we're passing flags to the operation telling it to be silent,
- // it's possible for the operation to be aborted/cancelled without err
- // being set (although MSDN doesn't give any scenarios for how this can
- // happen). See MSDN for SHFileOperation and SHFILEOPTSTRUCT.
- if (file_operation.fAnyOperationsAborted)
+ // Handle any path with wildcards.
+ if (path.BaseName().value().find_first_of(L"*?") !=
+ FilePath::StringType::npos) {
+ return DeleteFileRecursive(path.DirName(), path.BaseName().value(),
+ recursive);
+ }
+ DWORD attr = GetFileAttributes(path.value().c_str());
+ // We're done if we can't find the path.
+ if (attr == INVALID_FILE_ATTRIBUTES)
+ return true;
+ // We may need to clear the read-only bit.
+ if ((attr & FILE_ATTRIBUTE_READONLY) &&
+ !SetFileAttributes(path.value().c_str(),
+ attr & ~FILE_ATTRIBUTE_READONLY)) {
return false;
+ }
+ // Directories are handled differently if they're recursive.
+ if (!(attr & FILE_ATTRIBUTE_DIRECTORY))
+ return !!::DeleteFile(path.value().c_str());
+ // Handle a simple, single file delete.
+ if (!recursive || DeleteFileRecursive(path, L"*", true))
+ return !!RemoveDirectory(path.value().c_str());
- // Some versions of Windows return ERROR_FILE_NOT_FOUND (0x2) when deleting
- // an empty directory and some return 0x402 when they should be returning
- // ERROR_FILE_NOT_FOUND. MSDN says Vista and up won't return 0x402. Windows 7
- // can return DE_INVALIDFILES (0x7C) for nonexistent directories.
- return (err == 0 || err == ERROR_FILE_NOT_FOUND || err == 0x402 ||
- err == 0x7C);
+ return false;
}
bool DeleteFileAfterReboot(const FilePath& path) {
@@ -349,7 +363,8 @@ bool CreateTemporaryDirInDir(const FilePath& base_dir,
new_dir_name.assign(prefix);
new_dir_name.append(IntToString16(GetCurrentProcId()));
new_dir_name.push_back('_');
- new_dir_name.append(IntToString16(RandInt(0, kint16max)));
+ new_dir_name.append(
+ IntToString16(RandInt(0, std::numeric_limits<int16_t>::max())));
path_to_create = base_dir.Append(new_dir_name);
if (::CreateDirectory(path_to_create.value().c_str(), NULL)) {
@@ -753,6 +768,13 @@ bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
return true;
}
+bool SetNonBlocking(int fd) {
+ unsigned long nonblocking = 1;
+ if (ioctlsocket(fd, FIONBIO, &nonblocking) == 0)
+ return true;
+ return false;
+}
+
// -----------------------------------------------------------------------------
namespace internal {
diff --git a/chromium/base/files/file_win.cc b/chromium/base/files/file_win.cc
index ce38d0b0e2a..8329672b988 100644
--- a/chromium/base/files/file_win.cc
+++ b/chromium/base/files/file_win.cc
@@ -5,6 +5,7 @@
#include "base/files/file.h"
#include <io.h>
+#include <stdint.h>
#include "base/logging.h"
#include "base/metrics/sparse_histogram.h"
@@ -13,9 +14,10 @@
namespace base {
// Make sure our Whence mappings match the system headers.
-COMPILE_ASSERT(File::FROM_BEGIN == FILE_BEGIN &&
- File::FROM_CURRENT == FILE_CURRENT &&
- File::FROM_END == FILE_END, whence_matches_system);
+static_assert(File::FROM_BEGIN == FILE_BEGIN &&
+ File::FROM_CURRENT == FILE_CURRENT &&
+ File::FROM_END == FILE_END,
+ "whence mapping must match the system headers");
bool File::IsValid() const {
return file_.IsValid();
@@ -38,7 +40,7 @@ void File::Close() {
file_.Close();
}
-int64 File::Seek(Whence whence, int64 offset) {
+int64_t File::Seek(Whence whence, int64_t offset) {
ThreadRestrictions::AssertIOAllowed();
DCHECK(IsValid());
@@ -52,7 +54,7 @@ int64 File::Seek(Whence whence, int64 offset) {
return res.QuadPart;
}
-int File::Read(int64 offset, char* data, int size) {
+int File::Read(int64_t offset, char* data, int size) {
ThreadRestrictions::AssertIOAllowed();
DCHECK(IsValid());
DCHECK(!async_);
@@ -95,7 +97,7 @@ int File::ReadAtCurrentPos(char* data, int size) {
return -1;
}
-int File::ReadNoBestEffort(int64 offset, char* data, int size) {
+int File::ReadNoBestEffort(int64_t offset, char* data, int size) {
// TODO(dbeam): trace this separately?
return Read(offset, data, size);
}
@@ -105,7 +107,7 @@ int File::ReadAtCurrentPosNoBestEffort(char* data, int size) {
return ReadAtCurrentPos(data, size);
}
-int File::Write(int64 offset, const char* data, int size) {
+int File::Write(int64_t offset, const char* data, int size) {
ThreadRestrictions::AssertIOAllowed();
DCHECK(IsValid());
DCHECK(!async_);
@@ -146,7 +148,7 @@ int File::WriteAtCurrentPosNoBestEffort(const char* data, int size) {
return WriteAtCurrentPos(data, size);
}
-int64 File::GetLength() {
+int64_t File::GetLength() {
ThreadRestrictions::AssertIOAllowed();
DCHECK(IsValid());
@@ -156,10 +158,10 @@ int64 File::GetLength() {
if (!::GetFileSizeEx(file_.Get(), &size))
return -1;
- return static_cast<int64>(size.QuadPart);
+ return static_cast<int64_t>(size.QuadPart);
}
-bool File::SetLength(int64 length) {
+bool File::SetLength(int64_t length) {
ThreadRestrictions::AssertIOAllowed();
DCHECK(IsValid());
@@ -308,7 +310,7 @@ File::Error File::OSErrorToFileError(DWORD last_error) {
}
}
-void File::DoInitialize(const FilePath& path, uint32 flags) {
+void File::DoInitialize(const FilePath& path, uint32_t flags) {
ThreadRestrictions::AssertIOAllowed();
DCHECK(!IsValid());
@@ -375,6 +377,8 @@ void File::DoInitialize(const FilePath& path, uint32 flags) {
create_flags |= FILE_FLAG_DELETE_ON_CLOSE;
if (flags & FLAG_BACKUP_SEMANTICS)
create_flags |= FILE_FLAG_BACKUP_SEMANTICS;
+ if (flags & FLAG_SEQUENTIAL_SCAN)
+ create_flags |= FILE_FLAG_SEQUENTIAL_SCAN;
file_.Set(CreateFile(path.value().c_str(), access, sharing, NULL,
disposition, create_flags, NULL));
diff --git a/chromium/base/files/important_file_writer.cc b/chromium/base/files/important_file_writer.cc
index 1529107bdf3..b4293053a69 100644
--- a/chromium/base/files/important_file_writer.cc
+++ b/chromium/base/files/important_file_writer.cc
@@ -4,9 +4,11 @@
#include "base/files/important_file_writer.h"
+#include <stddef.h>
+#include <stdint.h>
#include <stdio.h>
-
#include <string>
+#include <utility>
#include "base/bind.h"
#include "base/critical_closure.h"
@@ -15,6 +17,7 @@
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/metrics/histogram.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/string_number_conversions.h"
@@ -23,6 +26,7 @@
#include "base/task_runner_util.h"
#include "base/threading/thread.h"
#include "base/time/time.h"
+#include "build/build_config.h"
namespace base {
@@ -191,7 +195,7 @@ void ImportantFileWriter::DoScheduledWrite() {
DCHECK(serializer_);
scoped_ptr<std::string> data(new std::string);
if (serializer_->SerializeData(data.get())) {
- WriteNow(data.Pass());
+ WriteNow(std::move(data));
} else {
DLOG(WARNING) << "failed to serialize data to be saved in "
<< path_.value();
diff --git a/chromium/base/files/important_file_writer.h b/chromium/base/files/important_file_writer.h
index 7c6160a5f9f..1b2ad5caed0 100644
--- a/chromium/base/files/important_file_writer.h
+++ b/chromium/base/files/important_file_writer.h
@@ -8,9 +8,9 @@
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/callback.h"
#include "base/files/file_path.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/threading/non_thread_safe.h"
#include "base/time/time.h"
diff --git a/chromium/base/files/important_file_writer_unittest.cc b/chromium/base/files/important_file_writer_unittest.cc
index 71900c93d5e..28e6001a003 100644
--- a/chromium/base/files/important_file_writer_unittest.cc
+++ b/chromium/base/files/important_file_writer_unittest.cc
@@ -11,6 +11,7 @@
#include "base/files/scoped_temp_dir.h"
#include "base/location.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/thread_task_runner_handle.h"
diff --git a/chromium/base/files/memory_mapped_file.cc b/chromium/base/files/memory_mapped_file.cc
index 227a41f1cd9..0fd9d6796b1 100644
--- a/chromium/base/files/memory_mapped_file.cc
+++ b/chromium/base/files/memory_mapped_file.cc
@@ -4,9 +4,12 @@
#include "base/files/memory_mapped_file.h"
+#include <utility>
+
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/sys_info.h"
+#include "build/build_config.h"
namespace base {
@@ -47,7 +50,7 @@ bool MemoryMappedFile::Initialize(const FilePath& file_name) {
}
bool MemoryMappedFile::Initialize(File file) {
- return Initialize(file.Pass(), Region::kWholeFile);
+ return Initialize(std::move(file), Region::kWholeFile);
}
bool MemoryMappedFile::Initialize(File file, const Region& region) {
@@ -59,7 +62,7 @@ bool MemoryMappedFile::Initialize(File file, const Region& region) {
DCHECK_GT(region.size, 0);
}
- file_ = file.Pass();
+ file_ = std::move(file);
if (!MapFileRegionToMemory(region)) {
CloseHandles();
@@ -74,14 +77,15 @@ bool MemoryMappedFile::IsValid() const {
}
// static
-void MemoryMappedFile::CalculateVMAlignedBoundaries(int64 start,
- int64 size,
- int64* aligned_start,
- int64* aligned_size,
- int32* offset) {
+void MemoryMappedFile::CalculateVMAlignedBoundaries(int64_t start,
+ int64_t size,
+ int64_t* aligned_start,
+ int64_t* aligned_size,
+ int32_t* offset) {
// Sadly, on Windows, the mmap alignment is not just equal to the page size.
- const int64 mask = static_cast<int64>(SysInfo::VMAllocationGranularity()) - 1;
- DCHECK_LT(mask, std::numeric_limits<int32>::max());
+ const int64_t mask =
+ static_cast<int64_t>(SysInfo::VMAllocationGranularity()) - 1;
+ DCHECK_LT(mask, std::numeric_limits<int32_t>::max());
*offset = start & mask;
*aligned_start = start & ~mask;
*aligned_size = (size + *offset + mask) & ~mask;
diff --git a/chromium/base/files/memory_mapped_file.h b/chromium/base/files/memory_mapped_file.h
index 9ff29b9fef1..6362e765cb4 100644
--- a/chromium/base/files/memory_mapped_file.h
+++ b/chromium/base/files/memory_mapped_file.h
@@ -5,9 +5,12 @@
#ifndef BASE_FILES_MEMORY_MAPPED_FILE_H_
#define BASE_FILES_MEMORY_MAPPED_FILE_H_
+#include <stddef.h>
+#include <stdint.h>
+
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/files/file.h"
+#include "base/macros.h"
#include "build/build_config.h"
#if defined(OS_WIN)
@@ -32,10 +35,10 @@ class BASE_EXPORT MemoryMappedFile {
bool operator!=(const Region& other) const;
// Start of the region (measured in bytes from the beginning of the file).
- int64 offset;
+ int64_t offset;
// Length of the region in bytes.
- int64 size;
+ int64_t size;
};
// Opens an existing file and maps it into memory. Access is restricted to
@@ -58,7 +61,7 @@ class BASE_EXPORT MemoryMappedFile {
bool InitializeAsImageSection(const FilePath& file_name);
#endif // OS_WIN
- const uint8* data() const { return data_; }
+ const uint8_t* data() const { return data_; }
size_t length() const { return length_; }
// Is file_ a valid file handle that points to an open, memory mapped file?
@@ -71,11 +74,11 @@ class BASE_EXPORT MemoryMappedFile {
// - |aligned_start| is page aligned and <= |start|.
// - |aligned_size| is a multiple of the VM granularity and >= |size|.
// - |offset| is the displacement of |start| w.r.t |aligned_start|.
- static void CalculateVMAlignedBoundaries(int64 start,
- int64 size,
- int64* aligned_start,
- int64* aligned_size,
- int32* offset);
+ static void CalculateVMAlignedBoundaries(int64_t start,
+ int64_t size,
+ int64_t* aligned_start,
+ int64_t* aligned_size,
+ int32_t* offset);
// Map the file to memory, set data_ to that memory address. Return true on
// success, false on any kind of failure. This is a helper for Initialize().
@@ -85,7 +88,7 @@ class BASE_EXPORT MemoryMappedFile {
void CloseHandles();
File file_;
- uint8* data_;
+ uint8_t* data_;
size_t length_;
#if defined(OS_WIN)
diff --git a/chromium/base/files/memory_mapped_file_posix.cc b/chromium/base/files/memory_mapped_file_posix.cc
index 168da923d46..1067fdc9ac3 100644
--- a/chromium/base/files/memory_mapped_file_posix.cc
+++ b/chromium/base/files/memory_mapped_file_posix.cc
@@ -4,12 +4,15 @@
#include "base/files/memory_mapped_file.h"
+#include <stddef.h>
+#include <stdint.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include "base/logging.h"
#include "base/threading/thread_restrictions.h"
+#include "build/build_config.h"
namespace base {
@@ -23,10 +26,10 @@ bool MemoryMappedFile::MapFileRegionToMemory(
off_t map_start = 0;
size_t map_size = 0;
- int32 data_offset = 0;
+ int32_t data_offset = 0;
if (region == MemoryMappedFile::Region::kWholeFile) {
- int64 file_len = file_.GetLength();
+ int64_t file_len = file_.GetLength();
if (file_len == -1) {
DPLOG(ERROR) << "fstat " << file_.GetPlatformFile();
return false;
@@ -38,8 +41,8 @@ bool MemoryMappedFile::MapFileRegionToMemory(
// start and size to be page-aligned. Hence, we map here the page-aligned
// outer region [|aligned_start|, |aligned_start| + |size|] which contains
// |region| and then add up the |data_offset| displacement.
- int64 aligned_start = 0;
- int64 aligned_size = 0;
+ int64_t aligned_start = 0;
+ int64_t aligned_size = 0;
CalculateVMAlignedBoundaries(region.offset,
region.size,
&aligned_start,
@@ -49,9 +52,10 @@ bool MemoryMappedFile::MapFileRegionToMemory(
// Ensure that the casts in the mmap call below are sane.
if (aligned_start < 0 || aligned_size < 0 ||
aligned_start > std::numeric_limits<off_t>::max() ||
- static_cast<uint64>(aligned_size) >
+ static_cast<uint64_t>(aligned_size) >
std::numeric_limits<size_t>::max() ||
- static_cast<uint64>(region.size) > std::numeric_limits<size_t>::max()) {
+ static_cast<uint64_t>(region.size) >
+ std::numeric_limits<size_t>::max()) {
DLOG(ERROR) << "Region bounds are not valid for mmap";
return false;
}
@@ -61,12 +65,8 @@ bool MemoryMappedFile::MapFileRegionToMemory(
length_ = static_cast<size_t>(region.size);
}
- data_ = static_cast<uint8*>(mmap(NULL,
- map_size,
- PROT_READ,
- MAP_SHARED,
- file_.GetPlatformFile(),
- map_start));
+ data_ = static_cast<uint8_t*>(mmap(NULL, map_size, PROT_READ, MAP_SHARED,
+ file_.GetPlatformFile(), map_start));
if (data_ == MAP_FAILED) {
DPLOG(ERROR) << "mmap " << file_.GetPlatformFile();
return false;
diff --git a/chromium/base/files/memory_mapped_file_unittest.cc b/chromium/base/files/memory_mapped_file_unittest.cc
index 05b941c308a..f75686f74bf 100644
--- a/chromium/base/files/memory_mapped_file_unittest.cc
+++ b/chromium/base/files/memory_mapped_file_unittest.cc
@@ -4,6 +4,11 @@
#include "base/files/memory_mapped_file.h"
+#include <stddef.h>
+#include <stdint.h>
+
+#include <utility>
+
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -14,16 +19,16 @@ namespace base {
namespace {
// Create a temporary buffer and fill it with a watermark sequence.
-scoped_ptr<uint8[]> CreateTestBuffer(size_t size, size_t offset) {
- scoped_ptr<uint8[]> buf(new uint8[size]);
+scoped_ptr<uint8_t[]> CreateTestBuffer(size_t size, size_t offset) {
+ scoped_ptr<uint8_t[]> buf(new uint8_t[size]);
for (size_t i = 0; i < size; ++i)
- buf.get()[i] = static_cast<uint8>((offset + i) % 253);
- return buf.Pass();
+ buf.get()[i] = static_cast<uint8_t>((offset + i) % 253);
+ return buf;
}
// Check that the watermark sequence is consistent with the |offset| provided.
-bool CheckBufferContents(const uint8* data, size_t size, size_t offset) {
- scoped_ptr<uint8[]> test_data(CreateTestBuffer(size, offset));
+bool CheckBufferContents(const uint8_t* data, size_t size, size_t offset) {
+ scoped_ptr<uint8_t[]> test_data(CreateTestBuffer(size, offset));
return memcmp(test_data.get(), data, size) == 0;
}
@@ -41,7 +46,7 @@ class MemoryMappedFileTest : public PlatformTest {
File::FLAG_CREATE_ALWAYS | File::FLAG_READ | File::FLAG_WRITE);
EXPECT_TRUE(file.IsValid());
- scoped_ptr<uint8[]> test_data(CreateTestBuffer(size, 0));
+ scoped_ptr<uint8_t[]> test_data(CreateTestBuffer(size, 0));
size_t bytes_written =
file.Write(0, reinterpret_cast<char*>(test_data.get()), size);
EXPECT_EQ(size, bytes_written);
@@ -93,7 +98,7 @@ TEST_F(MemoryMappedFileTest, MapWholeFileUsingRegion) {
MemoryMappedFile map;
File file(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ);
- map.Initialize(file.Pass(), MemoryMappedFile::Region::kWholeFile);
+ map.Initialize(std::move(file), MemoryMappedFile::Region::kWholeFile);
ASSERT_EQ(kFileSize, map.length());
ASSERT_TRUE(map.data() != NULL);
EXPECT_TRUE(map.IsValid());
@@ -108,7 +113,7 @@ TEST_F(MemoryMappedFileTest, MapPartialRegionAtBeginning) {
File file(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ);
MemoryMappedFile::Region region = {0, kPartialSize};
- map.Initialize(file.Pass(), region);
+ map.Initialize(std::move(file), region);
ASSERT_EQ(kPartialSize, map.length());
ASSERT_TRUE(map.data() != NULL);
EXPECT_TRUE(map.IsValid());
@@ -124,7 +129,7 @@ TEST_F(MemoryMappedFileTest, MapPartialRegionAtEnd) {
File file(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ);
MemoryMappedFile::Region region = {kOffset, kPartialSize};
- map.Initialize(file.Pass(), region);
+ map.Initialize(std::move(file), region);
ASSERT_EQ(kPartialSize, map.length());
ASSERT_TRUE(map.data() != NULL);
EXPECT_TRUE(map.IsValid());
@@ -141,7 +146,7 @@ TEST_F(MemoryMappedFileTest, MapSmallPartialRegionInTheMiddle) {
File file(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ);
MemoryMappedFile::Region region = {kOffset, kPartialSize};
- map.Initialize(file.Pass(), region);
+ map.Initialize(std::move(file), region);
ASSERT_EQ(kPartialSize, map.length());
ASSERT_TRUE(map.data() != NULL);
EXPECT_TRUE(map.IsValid());
@@ -158,7 +163,7 @@ TEST_F(MemoryMappedFileTest, MapLargePartialRegionInTheMiddle) {
File file(temp_file_path(), File::FLAG_OPEN | File::FLAG_READ);
MemoryMappedFile::Region region = {kOffset, kPartialSize};
- map.Initialize(file.Pass(), region);
+ map.Initialize(std::move(file), region);
ASSERT_EQ(kPartialSize, map.length());
ASSERT_TRUE(map.data() != NULL);
EXPECT_TRUE(map.IsValid());
diff --git a/chromium/base/files/memory_mapped_file_win.cc b/chromium/base/files/memory_mapped_file_win.cc
index 85859061ef3..5b397eed093 100644
--- a/chromium/base/files/memory_mapped_file_win.cc
+++ b/chromium/base/files/memory_mapped_file_win.cc
@@ -4,6 +4,11 @@
#include "base/files/memory_mapped_file.h"
+#include <stddef.h>
+#include <stdint.h>
+
+#include <limits>
+
#include "base/files/file_path.h"
#include "base/strings/string16.h"
#include "base/threading/thread_restrictions.h"
@@ -34,11 +39,11 @@ bool MemoryMappedFile::MapFileRegionToMemory(
LARGE_INTEGER map_start = {};
SIZE_T map_size = 0;
- int32 data_offset = 0;
+ int32_t data_offset = 0;
if (region == MemoryMappedFile::Region::kWholeFile) {
- int64 file_len = file_.GetLength();
- if (file_len <= 0 || file_len > kint32max)
+ int64_t file_len = file_.GetLength();
+ if (file_len <= 0 || file_len > std::numeric_limits<int32_t>::max())
return false;
length_ = static_cast<size_t>(file_len);
} else {
@@ -49,15 +54,15 @@ bool MemoryMappedFile::MapFileRegionToMemory(
// aligned and must be less than or equal the mapped file size.
// We map here the outer region [|aligned_start|, |aligned_start+size|]
// which contains |region| and then add up the |data_offset| displacement.
- int64 aligned_start = 0;
- int64 ignored = 0;
+ int64_t aligned_start = 0;
+ int64_t ignored = 0;
CalculateVMAlignedBoundaries(
region.offset, region.size, &aligned_start, &ignored, &data_offset);
- int64 size = region.size + data_offset;
+ int64_t size = region.size + data_offset;
// Ensure that the casts below in the MapViewOfFile call are sane.
if (aligned_start < 0 || size < 0 ||
- static_cast<uint64>(size) > std::numeric_limits<SIZE_T>::max()) {
+ static_cast<uint64_t>(size) > std::numeric_limits<SIZE_T>::max()) {
DLOG(ERROR) << "Region bounds are not valid for MapViewOfFile";
return false;
}
@@ -66,11 +71,9 @@ bool MemoryMappedFile::MapFileRegionToMemory(
length_ = static_cast<size_t>(region.size);
}
- data_ = static_cast<uint8*>(::MapViewOfFile(file_mapping_.Get(),
- FILE_MAP_READ,
- map_start.HighPart,
- map_start.LowPart,
- map_size));
+ data_ = static_cast<uint8_t*>(
+ ::MapViewOfFile(file_mapping_.Get(), FILE_MAP_READ, map_start.HighPart,
+ map_start.LowPart, map_size));
if (data_ == NULL)
return false;
data_ += data_offset;
diff --git a/chromium/base/files/scoped_file.cc b/chromium/base/files/scoped_file.cc
index 39f064de1c4..8971280776c 100644
--- a/chromium/base/files/scoped_file.cc
+++ b/chromium/base/files/scoped_file.cc
@@ -5,6 +5,7 @@
#include "base/files/scoped_file.h"
#include "base/logging.h"
+#include "build/build_config.h"
#if defined(OS_POSIX)
#include <unistd.h>
diff --git a/chromium/base/files/scoped_temp_dir.h b/chromium/base/files/scoped_temp_dir.h
index 5f63e09cff8..b1f2f5b8740 100644
--- a/chromium/base/files/scoped_temp_dir.h
+++ b/chromium/base/files/scoped_temp_dir.h
@@ -17,6 +17,7 @@
#include "base/base_export.h"
#include "base/files/file_path.h"
+#include "base/macros.h"
namespace base {
diff --git a/chromium/base/files/scoped_temp_dir_unittest.cc b/chromium/base/files/scoped_temp_dir_unittest.cc
index a19f34ddce0..3b2f28e50e9 100644
--- a/chromium/base/files/scoped_temp_dir_unittest.cc
+++ b/chromium/base/files/scoped_temp_dir_unittest.cc
@@ -7,6 +7,7 @@
#include "base/files/file.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
diff --git a/chromium/base/format_macros.h b/chromium/base/format_macros.h
index d58658d2b91..0697c6ddf25 100644
--- a/chromium/base/format_macros.h
+++ b/chromium/base/format_macros.h
@@ -21,6 +21,9 @@
// printf("xyz: %" PRIuS, size);
// The "u" in the macro corresponds to %u, and S is for "size".
+#include <stddef.h>
+#include <stdint.h>
+
#include "build/build_config.h"
#if defined(OS_POSIX) && (defined(_INTTYPES_H) || defined(_INTTYPES_H_)) && \
diff --git a/chromium/base/guid.cc b/chromium/base/guid.cc
index be5c58b5359..99b037bcfae 100644
--- a/chromium/base/guid.cc
+++ b/chromium/base/guid.cc
@@ -4,6 +4,8 @@
#include "base/guid.h"
+#include <stddef.h>
+
#include "base/strings/string_util.h"
namespace base {
diff --git a/chromium/base/guid.h b/chromium/base/guid.h
index abcc589f72d..c0a06f8858e 100644
--- a/chromium/base/guid.h
+++ b/chromium/base/guid.h
@@ -5,10 +5,11 @@
#ifndef BASE_GUID_H_
#define BASE_GUID_H_
+#include <stdint.h>
+
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "build/build_config.h"
namespace base {
@@ -24,7 +25,7 @@ BASE_EXPORT bool IsValidGUID(const std::string& guid);
#if defined(OS_POSIX)
// For unit testing purposes only. Do not use outside of tests.
-BASE_EXPORT std::string RandomDataToGUIDString(const uint64 bytes[2]);
+BASE_EXPORT std::string RandomDataToGUIDString(const uint64_t bytes[2]);
#endif
} // namespace base
diff --git a/chromium/base/guid_posix.cc b/chromium/base/guid_posix.cc
index f0fedc27e57..ec1ca515d34 100644
--- a/chromium/base/guid_posix.cc
+++ b/chromium/base/guid_posix.cc
@@ -4,13 +4,15 @@
#include "base/guid.h"
+#include <stdint.h>
+
#include "base/rand_util.h"
#include "base/strings/stringprintf.h"
namespace base {
std::string GenerateGUID() {
- uint64 sixteen_bytes[2] = { base::RandUint64(), base::RandUint64() };
+ uint64_t sixteen_bytes[2] = {base::RandUint64(), base::RandUint64()};
// Set the GUID to version 4 as described in RFC 4122, section 4.4.
// The format of GUID version 4 must be xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx,
@@ -30,7 +32,7 @@ std::string GenerateGUID() {
// TODO(cmasone): Once we're comfortable this works, migrate Windows code to
// use this as well.
-std::string RandomDataToGUIDString(const uint64 bytes[2]) {
+std::string RandomDataToGUIDString(const uint64_t bytes[2]) {
return StringPrintf("%08X-%04X-%04X-%04X-%012llX",
static_cast<unsigned int>(bytes[0] >> 32),
static_cast<unsigned int>((bytes[0] >> 16) & 0x0000ffff),
diff --git a/chromium/base/guid_unittest.cc b/chromium/base/guid_unittest.cc
index 1c5d393c4d8..b6d976d8e0d 100644
--- a/chromium/base/guid_unittest.cc
+++ b/chromium/base/guid_unittest.cc
@@ -4,9 +4,12 @@
#include "base/guid.h"
+#include <stdint.h>
+
#include <limits>
#include "base/strings/string_util.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
@@ -26,13 +29,13 @@ bool IsGUIDv4(const std::string& guid) {
} // namespace
TEST(GUIDTest, GUIDGeneratesAllZeroes) {
- uint64 bytes[] = { 0, 0 };
+ uint64_t bytes[] = {0, 0};
std::string clientid = RandomDataToGUIDString(bytes);
EXPECT_EQ("00000000-0000-0000-0000-000000000000", clientid);
}
TEST(GUIDTest, GUIDGeneratesCorrectly) {
- uint64 bytes[] = { 0x0123456789ABCDEFULL, 0xFEDCBA9876543210ULL };
+ uint64_t bytes[] = {0x0123456789ABCDEFULL, 0xFEDCBA9876543210ULL};
std::string clientid = RandomDataToGUIDString(bytes);
EXPECT_EQ("01234567-89AB-CDEF-FEDC-BA9876543210", clientid);
}
diff --git a/chromium/base/guid_win.cc b/chromium/base/guid_win.cc
index da3453dc73c..1e84d780444 100644
--- a/chromium/base/guid_win.cc
+++ b/chromium/base/guid_win.cc
@@ -9,7 +9,6 @@
#include <objbase.h>
#include <windows.h>
-#include "base/basictypes.h"
#include "base/logging.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
diff --git a/chromium/base/hash.cc b/chromium/base/hash.cc
index a7db64a919c..d3206f6a6c9 100644
--- a/chromium/base/hash.cc
+++ b/chromium/base/hash.cc
@@ -11,7 +11,7 @@ extern "C" uint32_t SuperFastHash(const char* data, int len);
namespace base {
-uint32 SuperFastHash(const char* data, int len) {
+uint32_t SuperFastHash(const char* data, int len) {
return ::SuperFastHash(data, len);
}
diff --git a/chromium/base/hash.h b/chromium/base/hash.h
index e46f6ac2484..ed8d9fd4cc9 100644
--- a/chromium/base/hash.h
+++ b/chromium/base/hash.h
@@ -5,21 +5,23 @@
#ifndef BASE_HASH_H_
#define BASE_HASH_H_
+#include <stddef.h>
+#include <stdint.h>
+
#include <limits>
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/logging.h"
namespace base {
// WARNING: This hash function should not be used for any cryptographic purpose.
-BASE_EXPORT uint32 SuperFastHash(const char* data, int len);
+BASE_EXPORT uint32_t SuperFastHash(const char* data, int len);
// Computes a hash of a memory buffer |data| of a given |length|.
// WARNING: This hash function should not be used for any cryptographic purpose.
-inline uint32 Hash(const char* data, size_t length) {
+inline uint32_t Hash(const char* data, size_t length) {
if (length > static_cast<size_t>(std::numeric_limits<int>::max())) {
NOTREACHED();
return 0;
@@ -29,7 +31,7 @@ inline uint32 Hash(const char* data, size_t length) {
// Computes a hash of a string |str|.
// WARNING: This hash function should not be used for any cryptographic purpose.
-inline uint32 Hash(const std::string& str) {
+inline uint32_t Hash(const std::string& str) {
return Hash(str.data(), str.size());
}
diff --git a/chromium/base/i18n/base_i18n_switches.cc b/chromium/base/i18n/base_i18n_switches.cc
new file mode 100644
index 00000000000..44e8393baab
--- /dev/null
+++ b/chromium/base/i18n/base_i18n_switches.cc
@@ -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.
+
+#include "base/i18n/base_i18n_switches.h"
+
+namespace switches {
+
+// Force the UI to a specific direction. Valid values are "ltr" (left-to-right)
+// and "rtl" (right-to-left).
+const char kForceUIDirection[] = "force-ui-direction";
+
+const char kForceUIDirectionLTR[] = "ltr";
+const char kForceUIDirectionRTL[] = "rtl";
+
+} // namespace switches
diff --git a/chromium/base/i18n/base_i18n_switches.h b/chromium/base/i18n/base_i18n_switches.h
new file mode 100644
index 00000000000..f00cff34acb
--- /dev/null
+++ b/chromium/base/i18n/base_i18n_switches.h
@@ -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.
+
+#ifndef BASE_I18N_BASE_I18N_SWITCHES_H_
+#define BASE_I18N_BASE_I18N_SWITCHES_H_
+
+#include "base/i18n/base_i18n_export.h"
+
+namespace switches {
+
+BASE_I18N_EXPORT extern const char kForceUIDirection[];
+
+// kForceUIDirection choices.
+BASE_I18N_EXPORT extern const char kForceUIDirectionLTR[];
+BASE_I18N_EXPORT extern const char kForceUIDirectionRTL[];
+
+} // namespace switches
+
+#endif // BASE_I18N_BASE_I18N_SWITCHES_H_
diff --git a/chromium/base/i18n/bidi_line_iterator.h b/chromium/base/i18n/bidi_line_iterator.h
index 0bf1ec67ce2..5bc30be181f 100644
--- a/chromium/base/i18n/bidi_line_iterator.h
+++ b/chromium/base/i18n/bidi_line_iterator.h
@@ -5,9 +5,9 @@
#ifndef BASE_I18N_BIDI_LINE_ITERATOR_H_
#define BASE_I18N_BIDI_LINE_ITERATOR_H_
-#include "base/basictypes.h"
#include "base/i18n/base_i18n_export.h"
#include "base/i18n/rtl.h"
+#include "base/macros.h"
#include "base/strings/string16.h"
#include "third_party/icu/source/common/unicode/ubidi.h"
diff --git a/chromium/base/i18n/break_iterator.cc b/chromium/base/i18n/break_iterator.cc
index bc20fff928a..869390fec37 100644
--- a/chromium/base/i18n/break_iterator.cc
+++ b/chromium/base/i18n/break_iterator.cc
@@ -4,6 +4,8 @@
#include "base/i18n/break_iterator.h"
+#include <stdint.h>
+
#include "base/logging.h"
#include "third_party/icu/source/common/unicode/ubrk.h"
#include "third_party/icu/source/common/unicode/uchar.h"
diff --git a/chromium/base/i18n/break_iterator.h b/chromium/base/i18n/break_iterator.h
index 9dbac7c59e6..dc30b644f79 100644
--- a/chromium/base/i18n/break_iterator.h
+++ b/chromium/base/i18n/break_iterator.h
@@ -5,8 +5,10 @@
#ifndef BASE_I18N_BREAK_ITERATOR_H_
#define BASE_I18N_BREAK_ITERATOR_H_
-#include "base/basictypes.h"
+#include <stddef.h>
+
#include "base/i18n/base_i18n_export.h"
+#include "base/macros.h"
#include "base/strings/string16.h"
#include "base/strings/string_piece.h"
diff --git a/chromium/base/i18n/break_iterator_unittest.cc b/chromium/base/i18n/break_iterator_unittest.cc
index c53509148d9..6137e02bd77 100644
--- a/chromium/base/i18n/break_iterator_unittest.cc
+++ b/chromium/base/i18n/break_iterator_unittest.cc
@@ -4,6 +4,9 @@
#include "base/i18n/break_iterator.h"
+#include <stddef.h>
+
+#include "base/macros.h"
#include "base/strings/string_piece.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
diff --git a/chromium/base/i18n/build_utf8_validator_tables.cc b/chromium/base/i18n/build_utf8_validator_tables.cc
index ae5b1a71e9d..0cdcc3519ac 100644
--- a/chromium/base/i18n/build_utf8_validator_tables.cc
+++ b/chromium/base/i18n/build_utf8_validator_tables.cc
@@ -23,9 +23,11 @@
// Because the table is not expected to ever change, it is checked into the
// repository rather than being regenerated at build time.
//
-// This code uses type uint8 throughout to represent bytes, to avoid
+// This code uses type uint8_t throughout to represent bytes, to avoid
// signed/unsigned char confusion.
+#include <stddef.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -35,11 +37,11 @@
#include <string>
#include <vector>
-#include "base/basictypes.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/stringprintf.h"
#include "third_party/icu/source/common/unicode/utf8.h"
@@ -63,7 +65,7 @@ const char kProlog[] =
"namespace base {\n"
"namespace internal {\n"
"\n"
- "const uint8 kUtf8ValidatorTables[] = {\n";
+ "const uint8_t kUtf8ValidatorTables[] = {\n";
const char kEpilog[] =
"};\n"
@@ -77,7 +79,7 @@ const char kEpilog[] =
class Range {
public:
// Ranges always start with just one byte.
- explicit Range(uint8 value) : from_(value), to_(value) {}
+ explicit Range(uint8_t value) : from_(value), to_(value) {}
// Range objects are copyable and assignable to be used in STL
// containers. Since they only contain non-pointer POD types, the default copy
@@ -85,13 +87,13 @@ class Range {
// Add a byte to the range. We intentionally only support adding a byte at the
// end, since that is the only operation the code needs.
- void AddByte(uint8 to) {
+ void AddByte(uint8_t to) {
CHECK(to == to_ + 1);
to_ = to;
}
- uint8 from() const { return from_; }
- uint8 to() const { return to_; }
+ uint8_t from() const { return from_; }
+ uint8_t to() const { return to_; }
bool operator<(const Range& rhs) const {
return (from() < rhs.from() || (from() == rhs.from() && to() < rhs.to()));
@@ -102,8 +104,8 @@ class Range {
}
private:
- uint8 from_;
- uint8 to_;
+ uint8_t from_;
+ uint8_t to_;
};
// A vector of Ranges is like a simple regular expression--it corresponds to
@@ -112,7 +114,7 @@ class Range {
typedef std::vector<Range> StringSet;
// A UTF-8 "character" is represented by a sequence of bytes.
-typedef std::vector<uint8> Character;
+typedef std::vector<uint8_t> Character;
// In the second stage of the algorithm, we want to convert a large list of
// Characters into a small list of StringSets.
@@ -129,7 +131,7 @@ class TablePrinter {
explicit TablePrinter(FILE* stream)
: stream_(stream), values_on_this_line_(0), current_offset_(0) {}
- void PrintValue(uint8 value) {
+ void PrintValue(uint8_t value) {
if (values_on_this_line_ == 0) {
fputs(" ", stream_);
} else if (values_on_this_line_ == kMaxValuesPerLine) {
@@ -175,7 +177,7 @@ PairVector InitializeCharacters() {
// explicitly permitted.
continue;
}
- uint8 bytes[4];
+ uint8_t bytes[4];
unsigned int offset = 0;
UBool is_error = false;
U8_APPEND(bytes, offset, arraysize(bytes), i, is_error);
@@ -281,8 +283,8 @@ void LogStringSets(const PairVector& pairs) {
// byte and the next entry in the vector (or 0xFF) result in a transition to the
// target state.
struct StateRange {
- uint8 from;
- uint8 target_state;
+ uint8_t from;
+ uint8_t target_state;
};
typedef std::vector<StateRange> State;
@@ -297,30 +299,31 @@ State GenerateInvalidState() {
// A map from a state (ie. a set of strings which will match from this state) to
// a number (which is an index into the array of states).
-typedef std::map<StringSet, uint8> StateMap;
+typedef std::map<StringSet, uint8_t> StateMap;
// Create a new state corresponding to |set|, add it |states| and |state_map|
// and return the index it was given in |states|.
-uint8 MakeState(const StringSet& set,
- std::vector<State>* states,
- StateMap* state_map) {
+uint8_t MakeState(const StringSet& set,
+ std::vector<State>* states,
+ StateMap* state_map) {
DCHECK(!set.empty());
const Range& range = set.front();
const StringSet rest(set.begin() + 1, set.end());
const StateMap::const_iterator where = state_map->find(rest);
- const uint8 target_state = where == state_map->end()
- ? MakeState(rest, states, state_map)
- : where->second;
+ const uint8_t target_state = where == state_map->end()
+ ? MakeState(rest, states, state_map)
+ : where->second;
DCHECK_LT(0, range.from());
DCHECK_LT(range.to(), 0xFF);
const StateRange new_state_initializer[] = {
- {0, 1}, {range.from(), target_state},
- {static_cast<uint8>(range.to() + 1), 1}};
+ {0, 1},
+ {range.from(), target_state},
+ {static_cast<uint8_t>(range.to() + 1), 1}};
states->push_back(
State(new_state_initializer,
new_state_initializer + arraysize(new_state_initializer)));
- const uint8 new_state_number =
- base::checked_cast<uint8>(states->size() - 1);
+ const uint8_t new_state_number =
+ base::checked_cast<uint8_t>(states->size() - 1);
CHECK(state_map->insert(std::make_pair(set, new_state_number)).second);
return new_state_number;
}
@@ -336,19 +339,20 @@ std::vector<State> GenerateStates(const PairVector& pairs) {
const Range& range = it->set.front();
const StringSet rest(it->set.begin() + 1, it->set.end());
const StateMap::const_iterator where = state_map.find(rest);
- const uint8 target_state = where == state_map.end()
- ? MakeState(rest, &states, &state_map)
- : where->second;
+ const uint8_t target_state = where == state_map.end()
+ ? MakeState(rest, &states, &state_map)
+ : where->second;
if (states[0].back().from == range.from()) {
DCHECK_EQ(1, states[0].back().target_state);
states[0].back().target_state = target_state;
DCHECK_LT(range.to(), 0xFF);
- const StateRange new_range = {static_cast<uint8>(range.to() + 1), 1};
+ const StateRange new_range = {static_cast<uint8_t>(range.to() + 1), 1};
states[0].push_back(new_range);
} else {
DCHECK_LT(range.to(), 0xFF);
- const StateRange new_range_initializer[] = {{range.from(), target_state},
- {static_cast<uint8>(range.to() + 1), 1}};
+ const StateRange new_range_initializer[] = {
+ {range.from(), target_state},
+ {static_cast<uint8_t>(range.to() + 1), 1}};
states[0]
.insert(states[0].end(),
new_range_initializer,
@@ -368,9 +372,9 @@ void PrintStates(const std::vector<State>& states, FILE* stream) {
// First calculate the start-offset of each state. This allows the state
// machine to jump directly to the correct offset, avoiding an extra
// indirection. State 0 starts at offset 0.
- std::vector<uint8> state_offset(1, 0);
- std::vector<uint8> shifts;
- uint8 pos = 0;
+ std::vector<uint8_t> state_offset(1, 0);
+ std::vector<uint8_t> shifts;
+ uint8_t pos = 0;
for (std::vector<State>::const_iterator state_it = states.begin();
state_it != states.end();
@@ -379,7 +383,7 @@ void PrintStates(const std::vector<State>& states, FILE* stream) {
// set bit in any of the ranges for this state, since this tells us how many
// bits we can discard and still determine what range a byte lies in. Sadly
// it appears that ffs() is not portable, so we do it clumsily.
- uint8 shift = 7;
+ uint8_t shift = 7;
for (State::const_iterator range_it = state_it->begin();
range_it != state_it->end();
++range_it) {
@@ -397,10 +401,10 @@ void PrintStates(const std::vector<State>& states, FILE* stream) {
fputs(kProlog, stream);
TablePrinter table_printer(stream);
- for (uint8 state_index = 0; state_index < states.size(); ++state_index) {
- const uint8 shift = shifts[state_index];
- uint8 next_range = 0;
- uint8 target_state = 1;
+ for (uint8_t state_index = 0; state_index < states.size(); ++state_index) {
+ const uint8_t shift = shifts[state_index];
+ uint8_t next_range = 0;
+ uint8_t target_state = 1;
fprintf(stream,
" // State %d, offset 0x%02x\n",
static_cast<int>(state_index),
diff --git a/chromium/base/i18n/case_conversion.cc b/chromium/base/i18n/case_conversion.cc
index 4b62d164484..9b7ce80537d 100644
--- a/chromium/base/i18n/case_conversion.cc
+++ b/chromium/base/i18n/case_conversion.cc
@@ -4,6 +4,8 @@
#include "base/i18n/case_conversion.h"
+#include <stdint.h>
+
#include "base/numerics/safe_conversions.h"
#include "base/strings/string16.h"
#include "base/strings/string_util.h"
diff --git a/chromium/base/i18n/char_iterator.h b/chromium/base/i18n/char_iterator.h
index 8174ef48f22..24024d4929f 100644
--- a/chromium/base/i18n/char_iterator.h
+++ b/chromium/base/i18n/char_iterator.h
@@ -5,11 +5,15 @@
#ifndef BASE_I18N_CHAR_ITERATOR_H_
#define BASE_I18N_CHAR_ITERATOR_H_
+#include <stddef.h>
+#include <stdint.h>
+
#include <string>
-#include "base/basictypes.h"
#include "base/i18n/base_i18n_export.h"
+#include "base/macros.h"
#include "base/strings/string16.h"
+#include "build/build_config.h"
// The CharIterator classes iterate through the characters in UTF8 and
// UTF16 strings. Example usage:
@@ -35,14 +39,14 @@ class BASE_I18N_EXPORT UTF8CharIterator {
// Return the starting array index of the current character within the
// string.
- int32 array_pos() const { return array_pos_; }
+ int32_t array_pos() const { return array_pos_; }
// Return the logical index of the current character, independent of the
// number of bytes each character takes.
- int32 char_pos() const { return char_pos_; }
+ int32_t char_pos() const { return char_pos_; }
// Return the current char.
- int32 get() const { return char_; }
+ int32_t get() const { return char_; }
// Returns true if we're at the end of the string.
bool end() const { return array_pos_ == len_; }
@@ -56,19 +60,19 @@ class BASE_I18N_EXPORT UTF8CharIterator {
const uint8_t* str_;
// The length of the encoded string.
- int32 len_;
+ int32_t len_;
// Array index.
- int32 array_pos_;
+ int32_t array_pos_;
// The next array index.
- int32 next_pos_;
+ int32_t next_pos_;
// Character index.
- int32 char_pos_;
+ int32_t char_pos_;
// The current character.
- int32 char_;
+ int32_t char_;
DISALLOW_COPY_AND_ASSIGN(UTF8CharIterator);
};
@@ -82,14 +86,14 @@ class BASE_I18N_EXPORT UTF16CharIterator {
// Return the starting array index of the current character within the
// string.
- int32 array_pos() const { return array_pos_; }
+ int32_t array_pos() const { return array_pos_; }
// Return the logical index of the current character, independent of the
// number of codewords each character takes.
- int32 char_pos() const { return char_pos_; }
+ int32_t char_pos() const { return char_pos_; }
// Return the current char.
- int32 get() const { return char_; }
+ int32_t get() const { return char_; }
// Returns true if we're at the end of the string.
bool end() const { return array_pos_ == len_; }
@@ -107,19 +111,19 @@ class BASE_I18N_EXPORT UTF16CharIterator {
const char16* str_;
// The length of the encoded string.
- int32 len_;
+ int32_t len_;
// Array index.
- int32 array_pos_;
+ int32_t array_pos_;
// The next array index.
- int32 next_pos_;
+ int32_t next_pos_;
// Character index.
- int32 char_pos_;
+ int32_t char_pos_;
// The current character.
- int32 char_;
+ int32_t char_;
DISALLOW_COPY_AND_ASSIGN(UTF16CharIterator);
};
diff --git a/chromium/base/i18n/file_util_icu.cc b/chromium/base/i18n/file_util_icu.cc
index f6e2c2956f4..4f4e69a389c 100644
--- a/chromium/base/i18n/file_util_icu.cc
+++ b/chromium/base/i18n/file_util_icu.cc
@@ -6,10 +6,13 @@
#include "base/i18n/file_util_icu.h"
+#include <stdint.h>
+
#include "base/files/file_path.h"
#include "base/i18n/icu_string_conversions.h"
#include "base/i18n/string_compare.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/singleton.h"
#include "base/strings/string_util.h"
@@ -110,7 +113,7 @@ void ReplaceIllegalCharactersInPath(FilePath::StringType* file_name,
int cursor = 0; // The ICU macros expect an int.
while (cursor < static_cast<int>(file_name->size())) {
int char_begin = cursor;
- uint32 code_point;
+ uint32_t code_point;
#if defined(OS_MACOSX)
// Mac uses UTF-8 encoding for filenames.
U8_NEXT(file_name->data(), cursor, static_cast<int>(file_name->length()),
diff --git a/chromium/base/i18n/file_util_icu_unittest.cc b/chromium/base/i18n/file_util_icu_unittest.cc
index 8fa7f6a261d..003fcf56116 100644
--- a/chromium/base/i18n/file_util_icu_unittest.cc
+++ b/chromium/base/i18n/file_util_icu_unittest.cc
@@ -4,8 +4,12 @@
#include "base/i18n/file_util_icu.h"
+#include <stddef.h>
+
#include "base/files/file_util.h"
+#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
diff --git a/chromium/base/i18n/icu_encoding_detection.cc b/chromium/base/i18n/icu_encoding_detection.cc
index ccd5cde2098..04df0758c15 100644
--- a/chromium/base/i18n/icu_encoding_detection.cc
+++ b/chromium/base/i18n/icu_encoding_detection.cc
@@ -4,6 +4,8 @@
#include "base/i18n/icu_encoding_detection.h"
+#include <stdint.h>
+
#include <set>
#include "base/strings/string_util.h"
@@ -22,16 +24,10 @@ bool DetectEncoding(const std::string& text, std::string* encoding) {
ucsdet_setText(detector, text.data(), static_cast<int32_t>(text.length()),
&status);
const UCharsetMatch* match = ucsdet_detect(detector, &status);
- if (match == NULL)
- return false;
- const char* detected_encoding = ucsdet_getName(match, &status);
+ if (match != nullptr)
+ *encoding = ucsdet_getName(match, &status);
ucsdet_close(detector);
-
- if (U_FAILURE(status))
- return false;
-
- *encoding = detected_encoding;
- return true;
+ return (match != nullptr) && !!U_SUCCESS(status);
}
bool DetectAllEncodings(const std::string& text,
diff --git a/chromium/base/i18n/icu_string_conversions.cc b/chromium/base/i18n/icu_string_conversions.cc
index edb31c3525f..68ce5294f98 100644
--- a/chromium/base/i18n/icu_string_conversions.cc
+++ b/chromium/base/i18n/icu_string_conversions.cc
@@ -4,9 +4,11 @@
#include "base/i18n/icu_string_conversions.h"
+#include <stddef.h>
+#include <stdint.h>
+
#include <vector>
-#include "base/basictypes.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/string_util.h"
diff --git a/chromium/base/i18n/icu_string_conversions_unittest.cc b/chromium/base/i18n/icu_string_conversions_unittest.cc
index 821529ddcee..99e4b9096d8 100644
--- a/chromium/base/i18n/icu_string_conversions_unittest.cc
+++ b/chromium/base/i18n/icu_string_conversions_unittest.cc
@@ -4,17 +4,19 @@
#include <math.h>
#include <stdarg.h>
+#include <stddef.h>
#include <limits>
#include <sstream>
-#include "base/basictypes.h"
#include "base/format_macros.h"
#include "base/i18n/icu_string_conversions.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/strings/string_piece.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
diff --git a/chromium/base/i18n/icu_util.cc b/chromium/base/i18n/icu_util.cc
index 1dd54cd606d..08dbeb3c14c 100644
--- a/chromium/base/i18n/icu_util.cc
+++ b/chromium/base/i18n/icu_util.cc
@@ -17,6 +17,7 @@
#include "base/path_service.h"
#include "base/strings/string_util.h"
#include "base/strings/sys_string_conversions.h"
+#include "build/build_config.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)
@@ -27,6 +28,10 @@
#include "base/android/apk_assets.h"
#endif
+#if defined(OS_IOS)
+#include "base/ios/ios_util.h"
+#endif
+
#if defined(OS_MACOSX)
#include "base/mac/foundation_util.h"
#endif
@@ -123,6 +128,12 @@ void LazyInitIcuDataFile() {
ScopedCFTypeRef<CFStringRef> data_file_name(
SysUTF8ToCFStringRef(kIcuDataFileName));
FilePath data_path = mac::PathForFrameworkBundleResource(data_file_name);
+#if defined(OS_IOS)
+ FilePath override_data_path = base::ios::FilePathOfEmbeddedICU();
+ if (!override_data_path.empty()) {
+ data_path = override_data_path;
+ }
+#endif // !defined(OS_IOS)
if (data_path.empty()) {
LOG(ERROR) << kIcuDataFileName << " not found in bundle";
return;
@@ -143,6 +154,7 @@ bool InitializeICUWithFileDescriptorInternal(
return true;
}
if (data_fd == kInvalidPlatformFile) {
+ LOG(ERROR) << "Invalid file descriptor to ICU data received.";
return false;
}
@@ -154,7 +166,7 @@ bool InitializeICUWithFileDescriptorInternal(
g_icudtl_mapped_file = icudtl_mapped_file.release();
UErrorCode err = U_ZERO_ERROR;
- udata_setCommonData(const_cast<uint8*>(g_icudtl_mapped_file->data()), &err);
+ udata_setCommonData(const_cast<uint8_t*>(g_icudtl_mapped_file->data()), &err);
return err == U_ZERO_ERROR;
}
#endif // ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE
@@ -164,6 +176,7 @@ bool InitializeICUWithFileDescriptorInternal(
#if !defined(OS_NACL)
#if ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE
+#if defined(OS_ANDROID)
bool InitializeICUWithFileDescriptor(
PlatformFile data_fd,
const MemoryMappedFile::Region& data_region) {
@@ -179,6 +192,28 @@ PlatformFile GetIcuDataFileHandle(MemoryMappedFile::Region* out_region) {
*out_region = g_icudtl_region;
return g_icudtl_pf;
}
+#endif
+
+const uint8_t* GetRawIcuMemory() {
+ CHECK(g_icudtl_mapped_file);
+ return g_icudtl_mapped_file->data();
+}
+
+bool InitializeICUFromRawMemory(const uint8_t* raw_memory) {
+#if !defined(COMPONENT_BUILD)
+#if !defined(NDEBUG)
+ DCHECK(!g_check_called_once || !g_called_once);
+ g_called_once = true;
+#endif
+
+ UErrorCode err = U_ZERO_ERROR;
+ udata_setCommonData(const_cast<uint8_t*>(raw_memory), &err);
+ return err == U_ZERO_ERROR;
+#else
+ return true;
+#endif
+}
+
#endif // ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE
bool InitializeICU() {
diff --git a/chromium/base/i18n/icu_util.h b/chromium/base/i18n/icu_util.h
index d62f8bac0d9..3d412b63891 100644
--- a/chromium/base/i18n/icu_util.h
+++ b/chromium/base/i18n/icu_util.h
@@ -5,6 +5,8 @@
#ifndef BASE_I18N_ICU_UTIL_H_
#define BASE_I18N_ICU_UTIL_H_
+#include <stdint.h>
+
#include "base/files/memory_mapped_file.h"
#include "base/i18n/base_i18n_export.h"
#include "build/build_config.h"
@@ -18,16 +20,37 @@ namespace i18n {
BASE_I18N_EXPORT bool InitializeICU();
#if ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE
+#if defined(OS_ANDROID)
// Returns the PlatformFile and Region that was initialized by InitializeICU().
// Use with InitializeICUWithFileDescriptor().
BASE_I18N_EXPORT PlatformFile GetIcuDataFileHandle(
MemoryMappedFile::Region* out_region);
-// Android and html_viewer use a file descriptor passed by browser process to
-// initialize ICU in render processes.
+// Android uses a file descriptor passed by browser process to initialize ICU
+// in render processes.
BASE_I18N_EXPORT bool InitializeICUWithFileDescriptor(
PlatformFile data_fd,
const MemoryMappedFile::Region& data_region);
+#endif
+
+// Returns a void pointer to the memory mapped ICU data file.
+//
+// There are cases on Android where we would be unsafely reusing a file
+// descriptor within the same process when initializing two copies of ICU from
+// different binaries in the same address space. This returns an unowned
+// pointer to the memory mapped icu data file; consumers copies of base must
+// not outlive the copy of base that owns the memory mapped file.
+BASE_I18N_EXPORT const uint8_t* GetRawIcuMemory();
+
+// Initializes ICU memory
+//
+// This does nothing in component builds; this initialization should only be
+// done in cases where there could be two copies of base in a single process in
+// non-component builds. (The big example is mojo: the shell will have a copy
+// of base linked in, and the majority of mojo applications will have base
+// linked in but in non-component builds, these will be separate copies of
+// base.)
+BASE_I18N_EXPORT bool InitializeICUFromRawMemory(const uint8_t* raw_memory);
#endif // ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE
#endif // !defined(OS_NACL)
diff --git a/chromium/base/i18n/message_formatter.h b/chromium/base/i18n/message_formatter.h
index bcdc3bc9775..4a5b92f2aab 100644
--- a/chromium/base/i18n/message_formatter.h
+++ b/chromium/base/i18n/message_formatter.h
@@ -9,6 +9,7 @@
#include <string>
#include "base/i18n/base_i18n_export.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/string16.h"
#include "base/strings/string_piece.h"
diff --git a/chromium/base/i18n/number_formatting.cc b/chromium/base/i18n/number_formatting.cc
index 47aa14cab23..920ba96b573 100644
--- a/chromium/base/i18n/number_formatting.cc
+++ b/chromium/base/i18n/number_formatting.cc
@@ -4,6 +4,8 @@
#include "base/i18n/number_formatting.h"
+#include <stddef.h>
+
#include "base/format_macros.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
@@ -45,7 +47,7 @@ LazyInstance<NumberFormatWrapper> g_number_format_float =
} // namespace
-string16 FormatNumber(int64 number) {
+string16 FormatNumber(int64_t number) {
icu::NumberFormat* number_format =
g_number_format_int.Get().number_format.get();
diff --git a/chromium/base/i18n/number_formatting.h b/chromium/base/i18n/number_formatting.h
index 556f9c24d2d..bdb862f21a6 100644
--- a/chromium/base/i18n/number_formatting.h
+++ b/chromium/base/i18n/number_formatting.h
@@ -5,7 +5,8 @@
#ifndef BASE_I18N_NUMBER_FORMATTING_H_
#define BASE_I18N_NUMBER_FORMATTING_H_
-#include "base/basictypes.h"
+#include <stdint.h>
+
#include "base/i18n/base_i18n_export.h"
#include "base/strings/string16.h"
@@ -14,7 +15,7 @@ namespace base {
// Return a number formatted with separators in the user's locale.
// Ex: FormatNumber(1234567)
// => "1,234,567" in English, "1.234.567" in German
-BASE_I18N_EXPORT string16 FormatNumber(int64 number);
+BASE_I18N_EXPORT string16 FormatNumber(int64_t number);
// Return a number formatted with separators in the user's locale.
// Ex: FormatDouble(1234567.8, 1)
diff --git a/chromium/base/i18n/number_formatting_unittest.cc b/chromium/base/i18n/number_formatting_unittest.cc
index dc6de2bbb6d..31341ac25e4 100644
--- a/chromium/base/i18n/number_formatting_unittest.cc
+++ b/chromium/base/i18n/number_formatting_unittest.cc
@@ -2,12 +2,17 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
+#include <stdint.h>
+
#include <limits>
#include "base/i18n/number_formatting.h"
#include "base/i18n/rtl.h"
+#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/icu_test_util.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/icu/source/i18n/unicode/usearch.h"
@@ -16,15 +21,15 @@ namespace {
TEST(NumberFormattingTest, FormatNumber) {
static const struct {
- int64 number;
+ int64_t number;
const char* expected_english;
const char* expected_german;
} cases[] = {
{0, "0", "0"},
{1024, "1,024", "1.024"},
- {std::numeric_limits<int64>::max(),
+ {std::numeric_limits<int64_t>::max(),
"9,223,372,036,854,775,807", "9.223.372.036.854.775.807"},
- {std::numeric_limits<int64>::min(),
+ {std::numeric_limits<int64_t>::min(),
"-9,223,372,036,854,775,808", "-9.223.372.036.854.775.808"},
{-42, "-42", "-42"},
};
diff --git a/chromium/base/i18n/rtl.cc b/chromium/base/i18n/rtl.cc
index ac9589cb325..095d66c6d8a 100644
--- a/chromium/base/i18n/rtl.cc
+++ b/chromium/base/i18n/rtl.cc
@@ -4,14 +4,21 @@
#include "base/i18n/rtl.h"
+#include <stddef.h>
+#include <stdint.h>
+
#include <algorithm>
+#include "base/command_line.h"
#include "base/files/file_path.h"
+#include "base/i18n/base_i18n_switches.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
#include "third_party/icu/source/common/unicode/locid.h"
#include "third_party/icu/source/common/unicode/uchar.h"
#include "third_party/icu/source/common/unicode/uscript.h"
@@ -64,6 +71,30 @@ base::i18n::TextDirection GetCharacterDirection(UChar32 character) {
return base::i18n::UNKNOWN_DIRECTION;
}
+// Gets the explicitly forced text direction for debugging. If no forcing is
+// applied, returns UNKNOWN_DIRECTION.
+base::i18n::TextDirection GetForcedTextDirection() {
+ // On iOS, check for RTL forcing.
+#if defined(OS_IOS)
+ if (base::ios::IsInForcedRTL())
+ return base::i18n::RIGHT_TO_LEFT;
+#endif
+
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ if (command_line->HasSwitch(switches::kForceUIDirection)) {
+ std::string force_flag =
+ command_line->GetSwitchValueASCII(switches::kForceUIDirection);
+
+ if (force_flag == switches::kForceUIDirectionLTR)
+ return base::i18n::LEFT_TO_RIGHT;
+
+ if (force_flag == switches::kForceUIDirectionRTL)
+ return base::i18n::RIGHT_TO_LEFT;
+ }
+
+ return base::i18n::UNKNOWN_DIRECTION;
+}
+
} // namespace
namespace base {
@@ -135,11 +166,10 @@ bool ICUIsRTL() {
}
TextDirection GetTextDirectionForLocaleInStartUp(const char* locale_name) {
-// On iOS, check for RTL forcing.
-#if defined(OS_IOS)
- if (ios::IsInForcedRTL())
- return RIGHT_TO_LEFT;
-#endif
+ // Check for direction forcing.
+ TextDirection forced_direction = GetForcedTextDirection();
+ if (forced_direction != UNKNOWN_DIRECTION)
+ return forced_direction;
// This list needs to be updated in alphabetical order if we add more RTL
// locales.
@@ -155,11 +185,10 @@ TextDirection GetTextDirectionForLocaleInStartUp(const char* locale_name) {
}
TextDirection GetTextDirectionForLocale(const char* locale_name) {
- // On iOS, check for RTL forcing.
-#if defined(OS_IOS)
- if (ios::IsInForcedRTL())
- return RIGHT_TO_LEFT;
-#endif
+ // Check for direction forcing.
+ TextDirection forced_direction = GetForcedTextDirection();
+ if (forced_direction != UNKNOWN_DIRECTION)
+ return forced_direction;
UErrorCode status = U_ZERO_ERROR;
ULayoutType layout_dir = uloc_getCharacterOrientation(locale_name, &status);
diff --git a/chromium/base/i18n/rtl_unittest.cc b/chromium/base/i18n/rtl_unittest.cc
index 6deaf34582a..c040670cb69 100644
--- a/chromium/base/i18n/rtl_unittest.cc
+++ b/chromium/base/i18n/rtl_unittest.cc
@@ -4,13 +4,17 @@
#include "base/i18n/rtl.h"
+#include <stddef.h>
+
#include <algorithm>
#include "base/files/file_path.h"
+#include "base/macros.h"
#include "base/strings/string_util.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/icu_test_util.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
#include "third_party/icu/source/i18n/unicode/usearch.h"
diff --git a/chromium/base/i18n/streaming_utf8_validator.cc b/chromium/base/i18n/streaming_utf8_validator.cc
index c809985e168..19c86a37a47 100644
--- a/chromium/base/i18n/streaming_utf8_validator.cc
+++ b/chromium/base/i18n/streaming_utf8_validator.cc
@@ -14,7 +14,7 @@
namespace base {
namespace {
-uint8 StateTableLookup(uint8 offset) {
+uint8_t StateTableLookup(uint8_t offset) {
DCHECK_LT(offset, internal::kUtf8ValidatorTablesSize);
return internal::kUtf8ValidatorTables[offset];
}
@@ -25,7 +25,7 @@ StreamingUtf8Validator::State StreamingUtf8Validator::AddBytes(const char* data,
size_t size) {
// Copy |state_| into a local variable so that the compiler doesn't have to be
// careful of aliasing.
- uint8 state = state_;
+ uint8_t state = state_;
for (const char* p = data; p != data + size; ++p) {
if ((*p & 0x80) == 0) {
if (state == 0)
@@ -33,8 +33,8 @@ StreamingUtf8Validator::State StreamingUtf8Validator::AddBytes(const char* data,
state = internal::I18N_UTF8_VALIDATOR_INVALID_INDEX;
break;
}
- const uint8 shift_amount = StateTableLookup(state);
- const uint8 shifted_char = (*p & 0x7F) >> shift_amount;
+ const uint8_t shift_amount = StateTableLookup(state);
+ const uint8_t shifted_char = (*p & 0x7F) >> shift_amount;
state = StateTableLookup(state + shifted_char + 1);
// State may be INVALID here, but this code is optimised for the case of
// valid UTF-8 and it is more efficient (by about 2%) to not attempt an
diff --git a/chromium/base/i18n/streaming_utf8_validator.h b/chromium/base/i18n/streaming_utf8_validator.h
index f10ac721c54..ebf38a69b3a 100644
--- a/chromium/base/i18n/streaming_utf8_validator.h
+++ b/chromium/base/i18n/streaming_utf8_validator.h
@@ -11,10 +11,13 @@
#ifndef BASE_I18N_STREAMING_UTF8_VALIDATOR_H_
#define BASE_I18N_STREAMING_UTF8_VALIDATOR_H_
+#include <stddef.h>
+#include <stdint.h>
+
#include <string>
-#include "base/basictypes.h"
#include "base/i18n/base_i18n_export.h"
+#include "base/macros.h"
namespace base {
@@ -51,7 +54,7 @@ class BASE_I18N_EXPORT StreamingUtf8Validator {
// The current state of the validator. Value 0 is the initial/valid state.
// The state is stored as an offset into |kUtf8ValidatorTables|. The special
// state |kUtf8InvalidState| is invalid.
- uint8 state_;
+ uint8_t state_;
// This type could be made copyable but there is currently no use-case for
// it.
diff --git a/chromium/base/i18n/streaming_utf8_validator_perftest.cc b/chromium/base/i18n/streaming_utf8_validator_perftest.cc
index 6b8c17b654b..ad328f886d9 100644
--- a/chromium/base/i18n/streaming_utf8_validator_perftest.cc
+++ b/chromium/base/i18n/streaming_utf8_validator_perftest.cc
@@ -12,11 +12,13 @@
#include "base/i18n/streaming_utf8_validator.h"
+#include <stddef.h>
+
#include <string>
-#include "base/basictypes.h"
#include "base/bind.h"
#include "base/callback.h"
+#include "base/macros.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/test/perf_time_logger.h"
diff --git a/chromium/base/i18n/streaming_utf8_validator_unittest.cc b/chromium/base/i18n/streaming_utf8_validator_unittest.cc
index 20ea564c032..b3e44b348e7 100644
--- a/chromium/base/i18n/streaming_utf8_validator_unittest.cc
+++ b/chromium/base/i18n/streaming_utf8_validator_unittest.cc
@@ -4,11 +4,14 @@
#include "base/i18n/streaming_utf8_validator.h"
+#include <stddef.h>
+#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <string>
+#include "base/macros.h"
#include "base/strings/string_piece.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -21,7 +24,6 @@
#ifdef BASE_I18N_UTF8_VALIDATOR_THOROUGH_TEST
-#include "base/basictypes.h"
#include "base/bind.h"
#include "base/location.h"
#include "base/logging.h"
@@ -48,7 +50,7 @@ const StreamingUtf8Validator::State INVALID = StreamingUtf8Validator::INVALID;
#ifdef BASE_I18N_UTF8_VALIDATOR_THOROUGH_TEST
-const uint32 kThoroughTestChunkSize = 1 << 24;
+const uint32_t kThoroughTestChunkSize = 1 << 24;
class StreamingUtf8ValidatorThoroughTest : public ::testing::Test {
protected:
@@ -57,11 +59,11 @@ class StreamingUtf8ValidatorThoroughTest : public ::testing::Test {
// This uses the same logic as base::IsStringUTF8 except it considers
// non-characters valid (and doesn't require a string as input).
- static bool IsStringUtf8(const char* src, int32 src_len) {
- int32 char_index = 0;
+ static bool IsStringUtf8(const char* src, int32_t src_len) {
+ int32_t char_index = 0;
while (char_index < src_len) {
- int32 code_point;
+ int32_t code_point;
U8_NEXT(src, char_index, src_len, code_point);
if (!base::IsValidCodepoint(code_point))
return false;
@@ -72,7 +74,7 @@ class StreamingUtf8ValidatorThoroughTest : public ::testing::Test {
// Converts the passed-in integer to a 4 byte string and then
// verifies that IsStringUtf8 and StreamingUtf8Validator agree on
// whether it is valid UTF-8 or not.
- void TestNumber(uint32 n) const {
+ void TestNumber(uint32_t n) const {
char test[sizeof n];
memcpy(test, &n, sizeof n);
StreamingUtf8Validator validator;
@@ -91,8 +93,8 @@ class StreamingUtf8ValidatorThoroughTest : public ::testing::Test {
// starting at |begin|. This is intended to be run from a worker
// pool. Signals |all_done_| at the end if it thinks all tasks are
// finished.
- void TestRange(uint32 begin, uint32 size) {
- for (uint32 i = 0; i < size; ++i) {
+ void TestRange(uint32_t begin, uint32_t size) {
+ for (uint32_t i = 0; i < size; ++i) {
TestNumber(begin + i);
}
base::AutoLock al(lock_);
@@ -115,7 +117,7 @@ TEST_F(StreamingUtf8ValidatorThoroughTest, TestEverything) {
scoped_refptr<base::SequencedWorkerPool> pool =
new base::SequencedWorkerPool(32, "TestEverything");
base::AutoLock al(lock_);
- uint32 begin = 0;
+ uint32_t begin = 0;
do {
pool->PostWorkerTask(
FROM_HERE,
diff --git a/chromium/base/i18n/string_search.cc b/chromium/base/i18n/string_search.cc
index 121dfce5869..779e4d99765 100644
--- a/chromium/base/i18n/string_search.cc
+++ b/chromium/base/i18n/string_search.cc
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stdint.h>
+
#include "base/i18n/string_search.h"
#include "base/logging.h"
diff --git a/chromium/base/i18n/string_search.h b/chromium/base/i18n/string_search.h
index 138606f8c60..07a29c19b70 100644
--- a/chromium/base/i18n/string_search.h
+++ b/chromium/base/i18n/string_search.h
@@ -5,6 +5,8 @@
#ifndef BASE_I18N_STRING_SEARCH_H_
#define BASE_I18N_STRING_SEARCH_H_
+#include <stddef.h>
+
#include "base/i18n/base_i18n_export.h"
#include "base/strings/string16.h"
diff --git a/chromium/base/i18n/string_search_unittest.cc b/chromium/base/i18n/string_search_unittest.cc
index 9419b267cb5..f1c9d193f27 100644
--- a/chromium/base/i18n/string_search_unittest.cc
+++ b/chromium/base/i18n/string_search_unittest.cc
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
+
#include <string>
#include "base/i18n/rtl.h"
diff --git a/chromium/base/i18n/time_formatting.cc b/chromium/base/i18n/time_formatting.cc
index 55121115fa5..321020cd451 100644
--- a/chromium/base/i18n/time_formatting.cc
+++ b/chromium/base/i18n/time_formatting.cc
@@ -4,6 +4,8 @@
#include "base/i18n/time_formatting.h"
+#include <stddef.h>
+
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/utf_string_conversions.h"
diff --git a/chromium/base/i18n/timezone.cc b/chromium/base/i18n/timezone.cc
index f668543ecdc..fbc9949d1e4 100644
--- a/chromium/base/i18n/timezone.cc
+++ b/chromium/base/i18n/timezone.cc
@@ -4,10 +4,12 @@
#include "base/i18n/timezone.h"
+#include <stddef.h>
#include <string.h>
#include <map>
+#include "base/macros.h"
#include "base/memory/singleton.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
diff --git a/chromium/base/i18n/utf8_validator_tables.cc b/chromium/base/i18n/utf8_validator_tables.cc
index 8dfa10caf79..913afc77c30 100644
--- a/chromium/base/i18n/utf8_validator_tables.cc
+++ b/chromium/base/i18n/utf8_validator_tables.cc
@@ -10,7 +10,7 @@
namespace base {
namespace internal {
-const uint8 kUtf8ValidatorTables[] = {
+const uint8_t kUtf8ValidatorTables[] = {
// State 0, offset 0x00
0x00, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, // 0x08
0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, // 0x10
diff --git a/chromium/base/i18n/utf8_validator_tables.h b/chromium/base/i18n/utf8_validator_tables.h
index b7db56e43e4..939616b8045 100644
--- a/chromium/base/i18n/utf8_validator_tables.h
+++ b/chromium/base/i18n/utf8_validator_tables.h
@@ -5,7 +5,10 @@
#ifndef BASE_I18N_UTF8_VALIDATOR_TABLES_H_
#define BASE_I18N_UTF8_VALIDATOR_TABLES_H_
-#include "base/basictypes.h"
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/macros.h"
namespace base {
namespace internal {
@@ -14,7 +17,7 @@ namespace internal {
// next_state, next_state, ....). The right_shifts are used to reduce the
// overall size of the table. The table only covers bytes in the range
// [0x80, 0xFF] to save space.
-extern const uint8 kUtf8ValidatorTables[];
+extern const uint8_t kUtf8ValidatorTables[];
extern const size_t kUtf8ValidatorTablesSize;
diff --git a/chromium/base/id_map.h b/chromium/base/id_map.h
index b1abdfdcee4..15c66623093 100644
--- a/chromium/base/id_map.h
+++ b/chromium/base/id_map.h
@@ -5,12 +5,14 @@
#ifndef BASE_ID_MAP_H_
#define BASE_ID_MAP_H_
+#include <stddef.h>
#include <stdint.h>
#include <set>
#include "base/containers/hash_tables.h"
#include "base/logging.h"
-#include "base/threading/non_thread_safe.h"
+#include "base/macros.h"
+#include "base/sequence_checker.h"
// Ownership semantics - own pointer means the pointer is deleted in Remove()
// & during destruction
@@ -33,7 +35,7 @@ enum IDMapOwnershipSemantics {
template <typename T,
IDMapOwnershipSemantics OS = IDMapExternalPointer,
typename K = int32_t>
-class IDMap : public base::NonThreadSafe {
+class IDMap {
public:
using KeyType = K;
@@ -42,16 +44,18 @@ class IDMap : public base::NonThreadSafe {
public:
IDMap() : iteration_depth_(0), next_id_(1), check_on_null_data_(false) {
- // A number of consumers of IDMap create it on one thread but always access
- // it from a different, but consitent, thread post-construction.
- DetachFromThread();
+ // A number of consumers of IDMap create it on one thread but always
+ // access it from a different, but consistent, thread (or sequence)
+ // post-construction. The first call to CalledOnValidSequencedThread()
+ // will re-bind it.
+ sequence_checker_.DetachFromSequence();
}
~IDMap() {
- // Many IDMap's are static, and hence will be destroyed on the main thread.
- // However, all the accesses may take place on another thread, such as the
- // IO thread. Detaching again to clean this up.
- DetachFromThread();
+ // Many IDMap's are static, and hence will be destroyed on the main
+ // thread. However, all the accesses may take place on another thread (or
+ // sequence), such as the IO thread. Detaching again to clean this up.
+ sequence_checker_.DetachFromSequence();
Releaser<OS, 0>::release_all(&data_);
}
@@ -61,7 +65,7 @@ class IDMap : public base::NonThreadSafe {
// Adds a view with an automatically generated unique ID. See AddWithID.
KeyType Add(T* data) {
- DCHECK(CalledOnValidThread());
+ DCHECK(sequence_checker_.CalledOnValidSequencedThread());
DCHECK(!check_on_null_data_ || data);
KeyType this_id = next_id_;
DCHECK(data_.find(this_id) == data_.end()) << "Inserting duplicate item";
@@ -75,14 +79,14 @@ class IDMap : public base::NonThreadSafe {
// this function, or allow this object to generate IDs and call Add. These
// two methods may not be mixed, or duplicate IDs may be generated
void AddWithID(T* data, KeyType id) {
- DCHECK(CalledOnValidThread());
+ DCHECK(sequence_checker_.CalledOnValidSequencedThread());
DCHECK(!check_on_null_data_ || data);
DCHECK(data_.find(id) == data_.end()) << "Inserting duplicate item";
data_[id] = data;
}
void Remove(KeyType id) {
- DCHECK(CalledOnValidThread());
+ DCHECK(sequence_checker_.CalledOnValidSequencedThread());
typename HashTable::iterator i = data_.find(id);
if (i == data_.end()) {
NOTREACHED() << "Attempting to remove an item not in the list";
@@ -103,7 +107,7 @@ class IDMap : public base::NonThreadSafe {
// 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(sequence_checker_.CalledOnValidSequencedThread());
DCHECK(!check_on_null_data_ || new_data);
typename HashTable::iterator i = data_.find(id);
if (i == data_.end()) {
@@ -117,7 +121,7 @@ class IDMap : public base::NonThreadSafe {
}
void Clear() {
- DCHECK(CalledOnValidThread());
+ DCHECK(sequence_checker_.CalledOnValidSequencedThread());
if (iteration_depth_ == 0) {
Releaser<OS, 0>::release_all(&data_);
} else {
@@ -128,12 +132,12 @@ class IDMap : public base::NonThreadSafe {
}
bool IsEmpty() const {
- DCHECK(CalledOnValidThread());
+ DCHECK(sequence_checker_.CalledOnValidSequencedThread());
return size() == 0u;
}
T* Lookup(KeyType id) const {
- DCHECK(CalledOnValidThread());
+ DCHECK(sequence_checker_.CalledOnValidSequencedThread());
typename HashTable::const_iterator i = data_.find(id);
if (i == data_.end())
return NULL;
@@ -141,7 +145,7 @@ class IDMap : public base::NonThreadSafe {
}
size_t size() const {
- DCHECK(CalledOnValidThread());
+ DCHECK(sequence_checker_.CalledOnValidSequencedThread());
return data_.size() - removed_ids_.size();
}
@@ -176,7 +180,7 @@ class IDMap : public base::NonThreadSafe {
}
~Iterator() {
- DCHECK(map_->CalledOnValidThread());
+ DCHECK(map_->sequence_checker_.CalledOnValidSequencedThread());
// We're going to decrement iteration depth. Make sure it's greater than
// zero so that it doesn't become negative.
@@ -187,29 +191,29 @@ class IDMap : public base::NonThreadSafe {
}
bool IsAtEnd() const {
- DCHECK(map_->CalledOnValidThread());
+ DCHECK(map_->sequence_checker_.CalledOnValidSequencedThread());
return iter_ == map_->data_.end();
}
KeyType GetCurrentKey() const {
- DCHECK(map_->CalledOnValidThread());
+ DCHECK(map_->sequence_checker_.CalledOnValidSequencedThread());
return iter_->first;
}
ReturnType* GetCurrentValue() const {
- DCHECK(map_->CalledOnValidThread());
+ DCHECK(map_->sequence_checker_.CalledOnValidSequencedThread());
return iter_->second;
}
void Advance() {
- DCHECK(map_->CalledOnValidThread());
+ DCHECK(map_->sequence_checker_.CalledOnValidSequencedThread());
++iter_;
SkipRemovedEntries();
}
private:
void Init() {
- DCHECK(map_->CalledOnValidThread());
+ DCHECK(map_->sequence_checker_.CalledOnValidSequencedThread());
++map_->iteration_depth_;
SkipRemovedEntries();
}
@@ -273,6 +277,8 @@ class IDMap : public base::NonThreadSafe {
// See description above setter.
bool check_on_null_data_;
+ base::SequenceChecker sequence_checker_;
+
DISALLOW_COPY_AND_ASSIGN(IDMap);
};
diff --git a/chromium/base/id_map_unittest.cc b/chromium/base/id_map_unittest.cc
index 2cd63093805..7a07a28db52 100644
--- a/chromium/base/id_map_unittest.cc
+++ b/chromium/base/id_map_unittest.cc
@@ -4,6 +4,8 @@
#include "base/id_map.h"
+#include <stdint.h>
+
#include "testing/gtest/include/gtest/gtest.h"
namespace {
@@ -28,12 +30,12 @@ TEST(IDMapTest, Basic) {
TestObject obj1;
TestObject obj2;
- int32 id1 = map.Add(&obj1);
+ int32_t id1 = map.Add(&obj1);
EXPECT_FALSE(map.IsEmpty());
EXPECT_EQ(1U, map.size());
EXPECT_EQ(&obj1, map.Lookup(id1));
- int32 id2 = map.Add(&obj2);
+ int32_t id2 = map.Add(&obj2);
EXPECT_FALSE(map.IsEmpty());
EXPECT_EQ(2U, map.size());
@@ -102,7 +104,7 @@ TEST(IDMapTest, IteratorRemainsValidWhenRemovingOtherElements) {
map.Add(&obj[i]);
// IDMap uses a hash_map, which has no predictable iteration order.
- int32 ids_in_iteration_order[kCount];
+ int32_t ids_in_iteration_order[kCount];
const TestObject* objs_in_iteration_order[kCount];
int counter = 0;
for (IDMap<TestObject>::const_iterator iter(&map);
@@ -212,7 +214,7 @@ TEST(IDMapTest, IteratorRemainsValidWhenClearing) {
map.Add(&obj[i]);
// IDMap uses a hash_map, which has no predictable iteration order.
- int32 ids_in_iteration_order[kCount];
+ int32_t ids_in_iteration_order[kCount];
const TestObject* objs_in_iteration_order[kCount];
int counter = 0;
for (IDMap<TestObject>::const_iterator iter(&map);
diff --git a/chromium/base/ios/crb_protocol_observers.mm b/chromium/base/ios/crb_protocol_observers.mm
index 90a277ba3f4..8c4172a345e 100644
--- a/chromium/base/ios/crb_protocol_observers.mm
+++ b/chromium/base/ios/crb_protocol_observers.mm
@@ -5,11 +5,13 @@
#import "base/ios/crb_protocol_observers.h"
#include <objc/runtime.h>
+#include <stddef.h>
#include <algorithm>
#include <vector>
#include "base/logging.h"
#include "base/mac/scoped_nsobject.h"
+#include "base/stl_util.h"
@interface CRBProtocolObservers () {
base::scoped_nsobject<Protocol> _protocol;
@@ -102,8 +104,7 @@ id Iterator::GetNext() {
DCHECK(observer);
DCHECK([observer conformsToProtocol:self.protocol]);
- if (std::find(_observers.begin(), _observers.end(), observer) !=
- _observers.end())
+ if (ContainsValue(_observers, observer))
return;
_observers.push_back(observer);
diff --git a/chromium/base/ios/crb_protocol_observers_unittest.mm b/chromium/base/ios/crb_protocol_observers_unittest.mm
index b8cf4231e4d..07f5cff035c 100644
--- a/chromium/base/ios/crb_protocol_observers_unittest.mm
+++ b/chromium/base/ios/crb_protocol_observers_unittest.mm
@@ -255,7 +255,7 @@ TEST_F(CRBProtocolObserversTest, NestedMutateObservers) {
@end
@implementation TestMutateObserver {
- __weak id _observers;
+ id _observers; // weak
}
- (instancetype)initWithObserver:(CRBProtocolObservers*)observers {
diff --git a/chromium/base/ios/device_util.h b/chromium/base/ios/device_util.h
index 1cd9a043bc9..b1bed5c706c 100644
--- a/chromium/base/ios/device_util.h
+++ b/chromium/base/ios/device_util.h
@@ -5,6 +5,8 @@
#ifndef BASE_IOS_DEVICE_UTIL_H_
#define BASE_IOS_DEVICE_UTIL_H_
+#include <stdint.h>
+
#include <string>
namespace ios {
diff --git a/chromium/base/ios/device_util.mm b/chromium/base/ios/device_util.mm
index 4af8234988f..44e7c6c90cd 100644
--- a/chromium/base/ios/device_util.mm
+++ b/chromium/base/ios/device_util.mm
@@ -9,6 +9,7 @@
#include <ifaddrs.h>
#include <net/if_dl.h>
+#include <stddef.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
diff --git a/chromium/base/ios/ios_util.h b/chromium/base/ios/ios_util.h
index 9f65339ef0d..3b276ff7998 100644
--- a/chromium/base/ios/ios_util.h
+++ b/chromium/base/ios/ios_util.h
@@ -5,8 +5,10 @@
#ifndef BASE_IOS_IOS_UTIL_H_
#define BASE_IOS_IOS_UTIL_H_
+#include <stdint.h>
+
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/files/file_path.h"
namespace base {
namespace ios {
@@ -18,7 +20,9 @@ BASE_EXPORT bool IsRunningOnIOS8OrLater();
BASE_EXPORT bool IsRunningOnIOS9OrLater();
// Returns whether the operating system is at the given version or later.
-BASE_EXPORT bool IsRunningOnOrLater(int32 major, int32 minor, int32 bug_fix);
+BASE_EXPORT bool IsRunningOnOrLater(int32_t major,
+ int32_t minor,
+ int32_t bug_fix);
// Returns whether iOS is signalling that an RTL text direction should be used
// regardless of the current locale. This should not return true if the current
@@ -27,6 +31,14 @@ BASE_EXPORT bool IsRunningOnOrLater(int32 major, int32 minor, int32 bug_fix);
// example by using the "RTL Psuedolanguage" option when launching from XCode).
BASE_EXPORT bool IsInForcedRTL();
+// Stores the |path| of the ICU dat file in a global to be referenced later by
+// FilePathOfICUFile(). This should only be called once.
+BASE_EXPORT void OverridePathOfEmbeddedICU(const char* path);
+
+// Returns the overriden path set by OverridePathOfEmbeddedICU(), otherwise
+// returns invalid FilePath.
+BASE_EXPORT FilePath FilePathOfEmbeddedICU();
+
} // namespace ios
} // namespace base
diff --git a/chromium/base/ios/ios_util.mm b/chromium/base/ios/ios_util.mm
index 554a2029c80..bc10d19e8f6 100644
--- a/chromium/base/ios/ios_util.mm
+++ b/chromium/base/ios/ios_util.mm
@@ -5,18 +5,24 @@
#include "base/ios/ios_util.h"
#import <Foundation/Foundation.h>
+#include <stddef.h>
+#include "base/macros.h"
#include "base/sys_info.h"
namespace {
+
// Return a 3 elements array containing the major, minor and bug fix version of
// the OS.
-const int32* OSVersionAsArray() {
- int32* digits = new int32[3];
+const int32_t* OSVersionAsArray() {
+ int32_t* digits = new int32_t[3];
base::SysInfo::OperatingSystemVersionNumbers(
&digits[0], &digits[1], &digits[2]);
return digits;
}
+
+std::string* g_icudtl_path_override = nullptr;
+
} // namespace
namespace base {
@@ -31,9 +37,9 @@ bool IsRunningOnIOS9OrLater() {
return IsRunningOnOrLater(9, 0, 0);
}
-bool IsRunningOnOrLater(int32 major, int32 minor, int32 bug_fix) {
- static const int32* current_version = OSVersionAsArray();
- int32 version[] = { major, minor, bug_fix };
+bool IsRunningOnOrLater(int32_t major, int32_t minor, int32_t bug_fix) {
+ static const int32_t* current_version = OSVersionAsArray();
+ int32_t version[] = {major, minor, bug_fix};
for (size_t i = 0; i < arraysize(version); i++) {
if (current_version[i] != version[i])
return current_version[i] > version[i];
@@ -46,5 +52,17 @@ bool IsInForcedRTL() {
return [defaults boolForKey:@"NSForceRightToLeftWritingDirection"];
}
+void OverridePathOfEmbeddedICU(const char* path) {
+ DCHECK(!g_icudtl_path_override);
+ g_icudtl_path_override = new std::string(path);
+}
+
+FilePath FilePathOfEmbeddedICU() {
+ if (g_icudtl_path_override) {
+ return FilePath(*g_icudtl_path_override);
+ }
+ return FilePath();
+}
+
} // namespace ios
} // namespace base
diff --git a/chromium/base/ios/scoped_critical_action.h b/chromium/base/ios/scoped_critical_action.h
index 803d5875176..61c471e2d25 100644
--- a/chromium/base/ios/scoped_critical_action.h
+++ b/chromium/base/ios/scoped_critical_action.h
@@ -5,6 +5,7 @@
#ifndef BASE_IOS_SCOPED_CRITICAL_ACTION_H_
#define BASE_IOS_SCOPED_CRITICAL_ACTION_H_
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/synchronization/lock.h"
diff --git a/chromium/base/ios/weak_nsobject.h b/chromium/base/ios/weak_nsobject.h
index fc3a7c38dc4..136e430d55a 100644
--- a/chromium/base/ios/weak_nsobject.h
+++ b/chromium/base/ios/weak_nsobject.h
@@ -8,7 +8,6 @@
#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"
diff --git a/chromium/base/ios/weak_nsobject_unittest.mm b/chromium/base/ios/weak_nsobject_unittest.mm
index 81de993cf25..f7abfa13b01 100644
--- a/chromium/base/ios/weak_nsobject_unittest.mm
+++ b/chromium/base/ios/weak_nsobject_unittest.mm
@@ -2,7 +2,6 @@
// 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"
diff --git a/chromium/base/json/BUILD.gn b/chromium/base/json/BUILD.gn
deleted file mode 100644
index 70830c15e55..00000000000
--- a/chromium/base/json/BUILD.gn
+++ /dev/null
@@ -1,37 +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("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 72a09700161..516f8765c42 100644
--- a/chromium/base/json/json_file_value_serializer.cc
+++ b/chromium/base/json/json_file_value_serializer.cc
@@ -7,6 +7,7 @@
#include "base/files/file_util.h"
#include "base/json/json_string_value_serializer.h"
#include "base/logging.h"
+#include "build/build_config.h"
using base::FilePath;
@@ -100,8 +101,9 @@ const char* JSONFileValueDeserializer::GetErrorMessageForCode(int error_code) {
}
}
-base::Value* JSONFileValueDeserializer::Deserialize(int* error_code,
- std::string* error_str) {
+scoped_ptr<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) {
diff --git a/chromium/base/json/json_file_value_serializer.h b/chromium/base/json/json_file_value_serializer.h
index aab47eec2dc..f6b4e5fc223 100644
--- a/chromium/base/json/json_file_value_serializer.h
+++ b/chromium/base/json/json_file_value_serializer.h
@@ -5,11 +5,13 @@
#ifndef BASE_JSON_JSON_FILE_VALUE_SERIALIZER_H_
#define BASE_JSON_JSON_FILE_VALUE_SERIALIZER_H_
+#include <stddef.h>
+
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/files/file_path.h"
+#include "base/macros.h"
#include "base/values.h"
class BASE_EXPORT JSONFileValueSerializer : public base::ValueSerializer {
@@ -58,8 +60,8 @@ class BASE_EXPORT JSONFileValueDeserializer : public base::ValueDeserializer {
// If |error_message| is non-null, it will be filled in with a formatted
// error message including the location of the error if appropriate.
// The caller takes ownership of the returned value.
- base::Value* Deserialize(int* error_code,
- std::string* error_message) override;
+ scoped_ptr<base::Value> Deserialize(int* error_code,
+ std::string* error_message) override;
// This enum is designed to safely overlap with JSONReader::JsonParseError.
enum JsonFileError {
diff --git a/chromium/base/json/json_parser.cc b/chromium/base/json/json_parser.cc
index 9be690a6287..fbd4da45fb1 100644
--- a/chromium/base/json/json_parser.cc
+++ b/chromium/base/json/json_parser.cc
@@ -7,6 +7,7 @@
#include <cmath>
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
@@ -24,7 +25,7 @@ namespace {
const int kStackMaxDepth = 100;
-const int32 kExtendedASCIIStart = 0x80;
+const int32_t kExtendedASCIIStart = 0x80;
// This and the class below are used to own the JSON input string for when
// string tokens are stored as StringPiece instead of std::string. This
@@ -227,9 +228,9 @@ Value* JSONParser::Parse(const StringPiece& input) {
// <0xEF 0xBB 0xBF>, advance the start position to avoid the
// ParseNextToken function mis-treating a Unicode BOM as an invalid
// character and returning NULL.
- if (CanConsume(3) && static_cast<uint8>(*pos_) == 0xEF &&
- static_cast<uint8>(*(pos_ + 1)) == 0xBB &&
- static_cast<uint8>(*(pos_ + 2)) == 0xBF) {
+ if (CanConsume(3) && static_cast<uint8_t>(*pos_) == 0xEF &&
+ static_cast<uint8_t>(*(pos_ + 1)) == 0xBB &&
+ static_cast<uint8_t>(*(pos_ + 2)) == 0xBF) {
NextNChars(3);
}
@@ -274,6 +275,14 @@ std::string JSONParser::GetErrorMessage() const {
JSONReader::ErrorCodeToString(error_code_));
}
+int JSONParser::error_line() const {
+ return error_line_;
+}
+
+int JSONParser::error_column() const {
+ return error_column_;
+}
+
// StringBuilder ///////////////////////////////////////////////////////////////
JSONParser::StringBuilder::StringBuilder()
@@ -613,7 +622,7 @@ bool JSONParser::ConsumeStringRaw(StringBuilder* out) {
StringBuilder string(NextChar());
int length = end_pos_ - start_pos_;
- int32 next_char = 0;
+ int32_t next_char = 0;
while (CanConsume(1)) {
pos_ = start_pos_ + index_; // CBU8_NEXT is postcrement.
@@ -774,8 +783,8 @@ bool JSONParser::DecodeUTF16(std::string* dest_string) {
return false;
}
- uint32 code_point = CBU16_GET_SUPPLEMENTARY(code_unit16_high,
- code_unit16_low);
+ uint32_t code_point =
+ CBU16_GET_SUPPLEMENTARY(code_unit16_high, code_unit16_low);
if (!IsValidCharacter(code_point))
return false;
@@ -794,11 +803,11 @@ bool JSONParser::DecodeUTF16(std::string* dest_string) {
return true;
}
-void JSONParser::DecodeUTF8(const int32& point, StringBuilder* dest) {
+void JSONParser::DecodeUTF8(const int32_t& point, StringBuilder* dest) {
DCHECK(IsValidCharacter(point));
// Anything outside of the basic ASCII plane will need to be decoded from
- // int32 to a multi-byte sequence.
+ // int32_t to a multi-byte sequence.
if (point < kExtendedASCIIStart) {
dest->Append(static_cast<char>(point));
} else {
diff --git a/chromium/base/json/json_parser.h b/chromium/base/json/json_parser.h
index 4e23beb9289..fc04594a149 100644
--- a/chromium/base/json/json_parser.h
+++ b/chromium/base/json/json_parser.h
@@ -5,13 +5,16 @@
#ifndef BASE_JSON_JSON_PARSER_H_
#define BASE_JSON_JSON_PARSER_H_
+#include <stddef.h>
+#include <stdint.h>
+
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/gtest_prod_util.h"
#include "base/json/json_reader.h"
+#include "base/macros.h"
#include "base/strings/string_piece.h"
namespace base {
@@ -40,7 +43,7 @@ class JSONParserTest;
// of a token, such that the next iteration of the parser will be at the byte
// immediately following the token, which would likely be the first byte of the
// next token.
-class BASE_EXPORT_PRIVATE JSONParser {
+class BASE_EXPORT JSONParser {
public:
explicit JSONParser(int options);
~JSONParser();
@@ -55,6 +58,14 @@ class BASE_EXPORT_PRIVATE JSONParser {
// Returns the human-friendly error message.
std::string GetErrorMessage() const;
+ // Returns the error line number if parse error happened. Otherwise always
+ // returns 0.
+ int error_line() const;
+
+ // Returns the error column number if parse error happened. Otherwise always
+ // returns 0.
+ int error_column() const;
+
private:
enum Token {
T_OBJECT_BEGIN, // {
@@ -180,7 +191,7 @@ class BASE_EXPORT_PRIVATE JSONParser {
// Helper function for ConsumeStringRaw() that takes a single code point,
// decodes it into UTF-8 units, and appends it to the given builder. The
// point must be valid.
- void DecodeUTF8(const int32& point, StringBuilder* dest);
+ void DecodeUTF8(const int32_t& point, StringBuilder* dest);
// Assuming that the parser is wound to the start of a valid JSON number,
// this parses and converts it to either an int or double value.
diff --git a/chromium/base/json/json_parser_unittest.cc b/chromium/base/json/json_parser_unittest.cc
index d88f9ea7952..da86b332ea2 100644
--- a/chromium/base/json/json_parser_unittest.cc
+++ b/chromium/base/json/json_parser_unittest.cc
@@ -4,6 +4,8 @@
#include "base/json/json_parser.h"
+#include <stddef.h>
+
#include "base/json/json_reader.h"
#include "base/memory/scoped_ptr.h"
#include "base/values.h"
@@ -203,17 +205,16 @@ TEST_F(JSONParserTest, ErrorMessages) {
// Error strings should not be modified in case of success.
std::string error_message;
int error_code = 0;
- scoped_ptr<Value> root;
- root.reset(JSONReader::DeprecatedReadAndReturnError(
- "[42]", JSON_PARSE_RFC, &error_code, &error_message));
+ scoped_ptr<Value> root = JSONReader::ReadAndReturnError(
+ "[42]", JSON_PARSE_RFC, &error_code, &error_message);
EXPECT_TRUE(error_message.empty());
EXPECT_EQ(0, error_code);
// Test line and column counting
const char big_json[] = "[\n0,\n1,\n2,\n3,4,5,6 7,\n8,\n9\n]";
// error here ----------------------------------^
- root.reset(JSONReader::DeprecatedReadAndReturnError(
- big_json, JSON_PARSE_RFC, &error_code, &error_message));
+ root = JSONReader::ReadAndReturnError(big_json, JSON_PARSE_RFC, &error_code,
+ &error_message);
EXPECT_FALSE(root.get());
EXPECT_EQ(JSONParser::FormatErrorMessage(5, 10, JSONReader::kSyntaxError),
error_message);
@@ -225,16 +226,16 @@ TEST_F(JSONParserTest, ErrorMessages) {
const char big_json_crlf[] =
"[\r\n0,\r\n1,\r\n2,\r\n3,4,5,6 7,\r\n8,\r\n9\r\n]";
// error here ----------------------^
- root.reset(JSONReader::DeprecatedReadAndReturnError(
- big_json_crlf, JSON_PARSE_RFC, &error_code, &error_message));
+ root = JSONReader::ReadAndReturnError(big_json_crlf, JSON_PARSE_RFC,
+ &error_code, &error_message);
EXPECT_FALSE(root.get());
EXPECT_EQ(JSONParser::FormatErrorMessage(5, 10, JSONReader::kSyntaxError),
error_message);
EXPECT_EQ(JSONReader::JSON_SYNTAX_ERROR, error_code);
// Test each of the error conditions
- root.reset(JSONReader::DeprecatedReadAndReturnError(
- "{},{}", JSON_PARSE_RFC, &error_code, &error_message));
+ root = JSONReader::ReadAndReturnError("{},{}", JSON_PARSE_RFC, &error_code,
+ &error_message);
EXPECT_FALSE(root.get());
EXPECT_EQ(JSONParser::FormatErrorMessage(1, 3,
JSONReader::kUnexpectedDataAfterRoot), error_message);
@@ -245,56 +246,56 @@ TEST_F(JSONParserTest, ErrorMessages) {
nested_json.insert(nested_json.begin(), '[');
nested_json.append(1, ']');
}
- root.reset(JSONReader::DeprecatedReadAndReturnError(
- nested_json, JSON_PARSE_RFC, &error_code, &error_message));
+ root = JSONReader::ReadAndReturnError(nested_json, JSON_PARSE_RFC,
+ &error_code, &error_message);
EXPECT_FALSE(root.get());
EXPECT_EQ(JSONParser::FormatErrorMessage(1, 100, JSONReader::kTooMuchNesting),
error_message);
EXPECT_EQ(JSONReader::JSON_TOO_MUCH_NESTING, error_code);
- root.reset(JSONReader::DeprecatedReadAndReturnError(
- "[1,]", JSON_PARSE_RFC, &error_code, &error_message));
+ root = JSONReader::ReadAndReturnError("[1,]", JSON_PARSE_RFC, &error_code,
+ &error_message);
EXPECT_FALSE(root.get());
EXPECT_EQ(JSONParser::FormatErrorMessage(1, 4, JSONReader::kTrailingComma),
error_message);
EXPECT_EQ(JSONReader::JSON_TRAILING_COMMA, error_code);
- root.reset(JSONReader::DeprecatedReadAndReturnError(
- "{foo:\"bar\"}", JSON_PARSE_RFC, &error_code, &error_message));
+ root = JSONReader::ReadAndReturnError("{foo:\"bar\"}", JSON_PARSE_RFC,
+ &error_code, &error_message);
EXPECT_FALSE(root.get());
EXPECT_EQ(JSONParser::FormatErrorMessage(1, 2,
JSONReader::kUnquotedDictionaryKey), error_message);
EXPECT_EQ(JSONReader::JSON_UNQUOTED_DICTIONARY_KEY, error_code);
- root.reset(JSONReader::DeprecatedReadAndReturnError(
- "{\"foo\":\"bar\",}", JSON_PARSE_RFC, &error_code, &error_message));
+ root = JSONReader::ReadAndReturnError("{\"foo\":\"bar\",}", JSON_PARSE_RFC,
+ &error_code, &error_message);
EXPECT_FALSE(root.get());
EXPECT_EQ(JSONParser::FormatErrorMessage(1, 14, JSONReader::kTrailingComma),
error_message);
- root.reset(JSONReader::DeprecatedReadAndReturnError(
- "[nu]", JSON_PARSE_RFC, &error_code, &error_message));
+ root = JSONReader::ReadAndReturnError("[nu]", JSON_PARSE_RFC, &error_code,
+ &error_message);
EXPECT_FALSE(root.get());
EXPECT_EQ(JSONParser::FormatErrorMessage(1, 2, JSONReader::kSyntaxError),
error_message);
EXPECT_EQ(JSONReader::JSON_SYNTAX_ERROR, error_code);
- root.reset(JSONReader::DeprecatedReadAndReturnError(
- "[\"xxx\\xq\"]", JSON_PARSE_RFC, &error_code, &error_message));
+ root = JSONReader::ReadAndReturnError("[\"xxx\\xq\"]", JSON_PARSE_RFC,
+ &error_code, &error_message);
EXPECT_FALSE(root.get());
EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONReader::kInvalidEscape),
error_message);
EXPECT_EQ(JSONReader::JSON_INVALID_ESCAPE, error_code);
- root.reset(JSONReader::DeprecatedReadAndReturnError(
- "[\"xxx\\uq\"]", JSON_PARSE_RFC, &error_code, &error_message));
+ root = JSONReader::ReadAndReturnError("[\"xxx\\uq\"]", JSON_PARSE_RFC,
+ &error_code, &error_message);
EXPECT_FALSE(root.get());
EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONReader::kInvalidEscape),
error_message);
EXPECT_EQ(JSONReader::JSON_INVALID_ESCAPE, error_code);
- root.reset(JSONReader::DeprecatedReadAndReturnError(
- "[\"xxx\\q\"]", JSON_PARSE_RFC, &error_code, &error_message));
+ root = JSONReader::ReadAndReturnError("[\"xxx\\q\"]", JSON_PARSE_RFC,
+ &error_code, &error_message);
EXPECT_FALSE(root.get());
EXPECT_EQ(JSONParser::FormatErrorMessage(1, 7, JSONReader::kInvalidEscape),
error_message);
@@ -308,8 +309,8 @@ TEST_F(JSONParserTest, Decode4ByteUtf8Char) {
"[\"😇\",[],[],[],{\"google:suggesttype\":[]}]";
std::string error_message;
int error_code = 0;
- scoped_ptr<Value> root(JSONReader::DeprecatedReadAndReturnError(
- kUtf8Data, JSON_PARSE_RFC, &error_code, &error_message));
+ scoped_ptr<Value> root = JSONReader::ReadAndReturnError(
+ kUtf8Data, JSON_PARSE_RFC, &error_code, &error_message);
EXPECT_TRUE(root.get()) << error_message;
}
diff --git a/chromium/base/json/json_reader.cc b/chromium/base/json/json_reader.cc
index ad3ea98b314..3ab5f754b72 100644
--- a/chromium/base/json/json_reader.cc
+++ b/chromium/base/json/json_reader.cc
@@ -11,8 +11,8 @@
namespace base {
// Values 1000 and above are used by JSONFileValueSerializer::JsonFileError.
-COMPILE_ASSERT(JSONReader::JSON_PARSE_ERROR_COUNT < 1000,
- json_reader_error_out_of_bounds);
+static_assert(JSONReader::JSON_PARSE_ERROR_COUNT < 1000,
+ "JSONReader error out of bounds");
const char JSONReader::kInvalidEscape[] =
"Invalid escape sequence.";
@@ -43,41 +43,25 @@ JSONReader::~JSONReader() {
}
// static
-Value* JSONReader::DeprecatedRead(const StringPiece& json) {
- return Read(json).release();
-}
-
-// static
scoped_ptr<Value> JSONReader::Read(const StringPiece& json) {
internal::JSONParser parser(JSON_PARSE_RFC);
return make_scoped_ptr(parser.Parse(json));
}
// static
-Value* JSONReader::DeprecatedRead(const StringPiece& json, int options) {
- return Read(json, options).release();
-}
-
-// static
scoped_ptr<Value> JSONReader::Read(const StringPiece& json, int options) {
internal::JSONParser parser(options);
return make_scoped_ptr(parser.Parse(json));
}
-// static
-Value* JSONReader::DeprecatedReadAndReturnError(const StringPiece& json,
- int options,
- int* error_code_out,
- std::string* error_msg_out) {
- return ReadAndReturnError(json, options, error_code_out, error_msg_out)
- .release();
-}
// static
scoped_ptr<Value> JSONReader::ReadAndReturnError(const StringPiece& json,
int options,
int* error_code_out,
- std::string* error_msg_out) {
+ std::string* error_msg_out,
+ int* error_line_out,
+ int* error_column_out) {
internal::JSONParser parser(options);
scoped_ptr<Value> root(parser.Parse(json));
if (!root) {
@@ -85,6 +69,10 @@ scoped_ptr<Value> JSONReader::ReadAndReturnError(const StringPiece& json,
*error_code_out = parser.error_code();
if (error_msg_out)
*error_msg_out = parser.GetErrorMessage();
+ if (error_line_out)
+ *error_line_out = parser.error_line();
+ if (error_column_out)
+ *error_column_out = parser.error_column();
}
return root;
diff --git a/chromium/base/json/json_reader.h b/chromium/base/json/json_reader.h
index 378935a709e..c6bcb528e3b 100644
--- a/chromium/base/json/json_reader.h
+++ b/chromium/base/json/json_reader.h
@@ -31,7 +31,6 @@
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/string_piece.h"
@@ -95,15 +94,11 @@ class BASE_EXPORT JSONReader {
// Reads and parses |json|, returning a Value. The caller owns the returned
// instance. If |json| is not a properly formed JSON string, returns NULL.
static scoped_ptr<Value> Read(const StringPiece& json);
- // TODO(estade): remove this bare pointer version.
- static Value* DeprecatedRead(const StringPiece& json);
// Reads and parses |json|, returning a Value owned by the caller. The
// parser respects the given |options|. If the input is not properly formed,
// returns NULL.
static scoped_ptr<Value> Read(const StringPiece& json, int options);
- // TODO(estade): remove this bare pointer version.
- static Value* DeprecatedRead(const StringPiece& json, int options);
// Reads and parses |json| like Read(). |error_code_out| and |error_msg_out|
// are optional. If specified and NULL is returned, they will be populated
@@ -112,12 +107,9 @@ class BASE_EXPORT JSONReader {
static scoped_ptr<Value> ReadAndReturnError(const StringPiece& json,
int options, // JSONParserOptions
int* error_code_out,
- std::string* error_msg_out);
- // TODO(estade): remove this bare pointer version.
- static Value* DeprecatedReadAndReturnError(const StringPiece& json,
- int options, // JSONParserOptions
- int* error_code_out,
- std::string* error_msg_out);
+ std::string* error_msg_out,
+ int* error_line_out = nullptr,
+ int* error_column_out = nullptr);
// Converts a JSON parse error code into a human readable message.
// Returns an empty string if error_code is JSON_NO_ERROR.
diff --git a/chromium/base/json/json_reader_unittest.cc b/chromium/base/json/json_reader_unittest.cc
index 7d3a6d96477..21eec4a07d9 100644
--- a/chromium/base/json/json_reader_unittest.cc
+++ b/chromium/base/json/json_reader_unittest.cc
@@ -4,9 +4,12 @@
#include "base/json/json_reader.h"
+#include <stddef.h>
+
#include "base/base_paths.h"
#include "base/files/file_util.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/path_service.h"
#include "base/strings/string_piece.h"
@@ -19,8 +22,7 @@ namespace base {
TEST(JSONReaderTest, Reading) {
// some whitespace checking
- scoped_ptr<Value> root;
- root = JSONReader().ReadToValue(" null ");
+ scoped_ptr<Value> root = JSONReader().ReadToValue(" null ");
ASSERT_TRUE(root.get());
EXPECT_TRUE(root->IsType(Value::TYPE_NULL));
@@ -242,61 +244,56 @@ TEST(JSONReaderTest, Reading) {
EXPECT_FALSE(root.get());
// Basic array
- root.reset(JSONReader::DeprecatedRead("[true, false, null]"));
+ root = JSONReader::Read("[true, false, null]");
ASSERT_TRUE(root.get());
EXPECT_TRUE(root->IsType(Value::TYPE_LIST));
list = static_cast<ListValue*>(root.get());
EXPECT_EQ(3U, list->GetSize());
// Test with trailing comma. Should be parsed the same as above.
- scoped_ptr<Value> root2;
- root2.reset(JSONReader::DeprecatedRead("[true, false, null, ]",
- JSON_ALLOW_TRAILING_COMMAS));
+ scoped_ptr<Value> root2 =
+ JSONReader::Read("[true, false, null, ]", JSON_ALLOW_TRAILING_COMMAS);
EXPECT_TRUE(root->Equals(root2.get()));
// Empty array
- root.reset(JSONReader::DeprecatedRead("[]"));
+ root = JSONReader::Read("[]");
ASSERT_TRUE(root.get());
EXPECT_TRUE(root->IsType(Value::TYPE_LIST));
list = static_cast<ListValue*>(root.get());
EXPECT_EQ(0U, list->GetSize());
// Nested arrays
- root.reset(
- JSONReader::DeprecatedRead("[[true], [], [false, [], [null]], null]"));
+ root = JSONReader::Read("[[true], [], [false, [], [null]], null]");
ASSERT_TRUE(root.get());
EXPECT_TRUE(root->IsType(Value::TYPE_LIST));
list = static_cast<ListValue*>(root.get());
EXPECT_EQ(4U, list->GetSize());
// Lots of trailing commas.
- root2.reset(JSONReader::DeprecatedRead(
- "[[true], [], [false, [], [null, ] , ], null,]",
- JSON_ALLOW_TRAILING_COMMAS));
+ root2 = JSONReader::Read("[[true], [], [false, [], [null, ] , ], null,]",
+ JSON_ALLOW_TRAILING_COMMAS);
EXPECT_TRUE(root->Equals(root2.get()));
// Invalid, missing close brace.
- root.reset(
- JSONReader::DeprecatedRead("[[true], [], [false, [], [null]], null"));
+ root = JSONReader::Read("[[true], [], [false, [], [null]], null");
EXPECT_FALSE(root.get());
// Invalid, too many commas
- root.reset(JSONReader::DeprecatedRead("[true,, null]"));
+ root = JSONReader::Read("[true,, null]");
EXPECT_FALSE(root.get());
- root.reset(
- JSONReader::DeprecatedRead("[true,, null]", JSON_ALLOW_TRAILING_COMMAS));
+ root = JSONReader::Read("[true,, null]", JSON_ALLOW_TRAILING_COMMAS);
EXPECT_FALSE(root.get());
// Invalid, no commas
- root.reset(JSONReader::DeprecatedRead("[true null]"));
+ root = JSONReader::Read("[true null]");
EXPECT_FALSE(root.get());
// Invalid, trailing comma
- root.reset(JSONReader::DeprecatedRead("[true,]"));
+ root = JSONReader::Read("[true,]");
EXPECT_FALSE(root.get());
// Valid if we set |allow_trailing_comma| to true.
- root.reset(JSONReader::DeprecatedRead("[true,]", JSON_ALLOW_TRAILING_COMMAS));
+ root = JSONReader::Read("[true,]", JSON_ALLOW_TRAILING_COMMAS);
ASSERT_TRUE(root.get());
EXPECT_TRUE(root->IsType(Value::TYPE_LIST));
list = static_cast<ListValue*>(root.get());
@@ -310,25 +307,22 @@ TEST(JSONReaderTest, Reading) {
// Don't allow empty elements, even if |allow_trailing_comma| is
// true.
- root.reset(JSONReader::DeprecatedRead("[,]", JSON_ALLOW_TRAILING_COMMAS));
+ root = JSONReader::Read("[,]", JSON_ALLOW_TRAILING_COMMAS);
EXPECT_FALSE(root.get());
- root.reset(
- JSONReader::DeprecatedRead("[true,,]", JSON_ALLOW_TRAILING_COMMAS));
+ root = JSONReader::Read("[true,,]", JSON_ALLOW_TRAILING_COMMAS);
EXPECT_FALSE(root.get());
- root.reset(
- JSONReader::DeprecatedRead("[,true,]", JSON_ALLOW_TRAILING_COMMAS));
+ root = JSONReader::Read("[,true,]", JSON_ALLOW_TRAILING_COMMAS);
EXPECT_FALSE(root.get());
- root.reset(
- JSONReader::DeprecatedRead("[true,,false]", JSON_ALLOW_TRAILING_COMMAS));
+ root = JSONReader::Read("[true,,false]", JSON_ALLOW_TRAILING_COMMAS);
EXPECT_FALSE(root.get());
// Test objects
- root.reset(JSONReader::DeprecatedRead("{}"));
+ root = JSONReader::Read("{}");
ASSERT_TRUE(root.get());
EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
- root.reset(JSONReader::DeprecatedRead(
- "{\"number\":9.87654321, \"null\":null , \"\\x53\" : \"str\" }"));
+ root = JSONReader::Read(
+ "{\"number\":9.87654321, \"null\":null , \"\\x53\" : \"str\" }");
ASSERT_TRUE(root.get());
EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
DictionaryValue* dict_val = static_cast<DictionaryValue*>(root.get());
@@ -342,36 +336,36 @@ TEST(JSONReaderTest, Reading) {
EXPECT_TRUE(dict_val->GetString("S", &str_val));
EXPECT_EQ("str", str_val);
- root2.reset(JSONReader::DeprecatedRead(
+ root2 = JSONReader::Read(
"{\"number\":9.87654321, \"null\":null , \"\\x53\" : \"str\", }",
- JSON_ALLOW_TRAILING_COMMAS));
+ JSON_ALLOW_TRAILING_COMMAS);
ASSERT_TRUE(root2.get());
EXPECT_TRUE(root->Equals(root2.get()));
// Test newline equivalence.
- root2.reset(JSONReader::DeprecatedRead(
+ root2 = JSONReader::Read(
"{\n"
" \"number\":9.87654321,\n"
" \"null\":null,\n"
" \"\\x53\":\"str\",\n"
"}\n",
- JSON_ALLOW_TRAILING_COMMAS));
+ JSON_ALLOW_TRAILING_COMMAS);
ASSERT_TRUE(root2.get());
EXPECT_TRUE(root->Equals(root2.get()));
- root2.reset(JSONReader::DeprecatedRead(
+ root2 = JSONReader::Read(
"{\r\n"
" \"number\":9.87654321,\r\n"
" \"null\":null,\r\n"
" \"\\x53\":\"str\",\r\n"
"}\r\n",
- JSON_ALLOW_TRAILING_COMMAS));
+ JSON_ALLOW_TRAILING_COMMAS);
ASSERT_TRUE(root2.get());
EXPECT_TRUE(root->Equals(root2.get()));
// Test nesting
- root.reset(JSONReader::DeprecatedRead(
- "{\"inner\":{\"array\":[true]},\"false\":false,\"d\":{}}"));
+ root = JSONReader::Read(
+ "{\"inner\":{\"array\":[true]},\"false\":false,\"d\":{}}");
ASSERT_TRUE(root.get());
EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
dict_val = static_cast<DictionaryValue*>(root.get());
@@ -386,14 +380,13 @@ TEST(JSONReaderTest, Reading) {
inner_dict = NULL;
EXPECT_TRUE(dict_val->GetDictionary("d", &inner_dict));
- root2.reset(JSONReader::DeprecatedRead(
+ root2 = JSONReader::Read(
"{\"inner\": {\"array\":[true] , },\"false\":false,\"d\":{},}",
- JSON_ALLOW_TRAILING_COMMAS));
+ JSON_ALLOW_TRAILING_COMMAS);
EXPECT_TRUE(root->Equals(root2.get()));
// Test keys with periods
- root.reset(JSONReader::DeprecatedRead(
- "{\"a.b\":3,\"c\":2,\"d.e.f\":{\"g.h.i.j\":1}}"));
+ root = JSONReader::Read("{\"a.b\":3,\"c\":2,\"d.e.f\":{\"g.h.i.j\":1}}");
ASSERT_TRUE(root.get());
EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
dict_val = static_cast<DictionaryValue*>(root.get());
@@ -410,7 +403,7 @@ TEST(JSONReaderTest, Reading) {
&integer_value));
EXPECT_EQ(1, integer_value);
- root.reset(JSONReader::DeprecatedRead("{\"a\":{\"b\":2},\"a.b\":1}"));
+ root = JSONReader::Read("{\"a\":{\"b\":2},\"a.b\":1}");
ASSERT_TRUE(root.get());
EXPECT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
dict_val = static_cast<DictionaryValue*>(root.get());
@@ -420,47 +413,45 @@ TEST(JSONReaderTest, Reading) {
EXPECT_EQ(1, integer_value);
// Invalid, no closing brace
- root.reset(JSONReader::DeprecatedRead("{\"a\": true"));
+ root = JSONReader::Read("{\"a\": true");
EXPECT_FALSE(root.get());
// Invalid, keys must be quoted
- root.reset(JSONReader::DeprecatedRead("{foo:true}"));
+ root = JSONReader::Read("{foo:true}");
EXPECT_FALSE(root.get());
// Invalid, trailing comma
- root.reset(JSONReader::DeprecatedRead("{\"a\":true,}"));
+ root = JSONReader::Read("{\"a\":true,}");
EXPECT_FALSE(root.get());
// Invalid, too many commas
- root.reset(JSONReader::DeprecatedRead("{\"a\":true,,\"b\":false}"));
+ root = JSONReader::Read("{\"a\":true,,\"b\":false}");
EXPECT_FALSE(root.get());
- root.reset(JSONReader::DeprecatedRead("{\"a\":true,,\"b\":false}",
- JSON_ALLOW_TRAILING_COMMAS));
+ root =
+ JSONReader::Read("{\"a\":true,,\"b\":false}", JSON_ALLOW_TRAILING_COMMAS);
EXPECT_FALSE(root.get());
// Invalid, no separator
- root.reset(JSONReader::DeprecatedRead("{\"a\" \"b\"}"));
+ root = JSONReader::Read("{\"a\" \"b\"}");
EXPECT_FALSE(root.get());
// Invalid, lone comma.
- root.reset(JSONReader::DeprecatedRead("{,}"));
+ root = JSONReader::Read("{,}");
EXPECT_FALSE(root.get());
- root.reset(JSONReader::DeprecatedRead("{,}", JSON_ALLOW_TRAILING_COMMAS));
+ root = JSONReader::Read("{,}", JSON_ALLOW_TRAILING_COMMAS);
EXPECT_FALSE(root.get());
- root.reset(
- JSONReader::DeprecatedRead("{\"a\":true,,}", JSON_ALLOW_TRAILING_COMMAS));
+ root = JSONReader::Read("{\"a\":true,,}", JSON_ALLOW_TRAILING_COMMAS);
EXPECT_FALSE(root.get());
- root.reset(
- JSONReader::DeprecatedRead("{,\"a\":true}", JSON_ALLOW_TRAILING_COMMAS));
+ root = JSONReader::Read("{,\"a\":true}", JSON_ALLOW_TRAILING_COMMAS);
EXPECT_FALSE(root.get());
- root.reset(JSONReader::DeprecatedRead("{\"a\":true,,\"b\":false}",
- JSON_ALLOW_TRAILING_COMMAS));
+ root =
+ JSONReader::Read("{\"a\":true,,\"b\":false}", JSON_ALLOW_TRAILING_COMMAS);
EXPECT_FALSE(root.get());
// Test stack overflow
std::string evil(1000000, '[');
evil.append(std::string(1000000, ']'));
- root.reset(JSONReader::DeprecatedRead(evil));
+ root = JSONReader::Read(evil);
EXPECT_FALSE(root.get());
// A few thousand adjacent lists is fine.
@@ -470,7 +461,7 @@ TEST(JSONReaderTest, Reading) {
not_evil.append("[],");
}
not_evil.append("[]]");
- root.reset(JSONReader::DeprecatedRead(not_evil));
+ root = JSONReader::Read(not_evil);
ASSERT_TRUE(root.get());
EXPECT_TRUE(root->IsType(Value::TYPE_LIST));
list = static_cast<ListValue*>(root.get());
@@ -532,20 +523,20 @@ TEST(JSONReaderTest, Reading) {
}
// Test literal root objects.
- root.reset(JSONReader::DeprecatedRead("null"));
+ root = JSONReader::Read("null");
EXPECT_TRUE(root->IsType(Value::TYPE_NULL));
- root.reset(JSONReader::DeprecatedRead("true"));
+ root = JSONReader::Read("true");
ASSERT_TRUE(root.get());
EXPECT_TRUE(root->GetAsBoolean(&bool_value));
EXPECT_TRUE(bool_value);
- root.reset(JSONReader::DeprecatedRead("10"));
+ root = JSONReader::Read("10");
ASSERT_TRUE(root.get());
EXPECT_TRUE(root->GetAsInteger(&integer_value));
EXPECT_EQ(10, integer_value);
- root.reset(JSONReader::DeprecatedRead("\"root\""));
+ root = JSONReader::Read("\"root\"");
ASSERT_TRUE(root.get());
EXPECT_TRUE(root->GetAsString(&str_val));
EXPECT_EQ("root", str_val);
diff --git a/chromium/base/json/json_string_value_serializer.cc b/chromium/base/json/json_string_value_serializer.cc
index 5425c7e7b94..af7e010a3ab 100644
--- a/chromium/base/json/json_string_value_serializer.cc
+++ b/chromium/base/json/json_string_value_serializer.cc
@@ -48,9 +48,10 @@ JSONStringValueDeserializer::JSONStringValueDeserializer(
JSONStringValueDeserializer::~JSONStringValueDeserializer() {}
-Value* JSONStringValueDeserializer::Deserialize(int* error_code,
- std::string* error_str) {
- return base::JSONReader::DeprecatedReadAndReturnError(
+scoped_ptr<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 bc0e66d127f..2459f48a8a4 100644
--- a/chromium/base/json/json_string_value_serializer.h
+++ b/chromium/base/json/json_string_value_serializer.h
@@ -8,8 +8,8 @@
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/files/file_path.h"
+#include "base/macros.h"
#include "base/strings/string_piece.h"
#include "base/values.h"
@@ -59,8 +59,8 @@ class BASE_EXPORT JSONStringValueDeserializer : public base::ValueDeserializer {
// If |error_message| is non-null, it will be filled in with a formatted
// error message including the location of the error if appropriate.
// The caller takes ownership of the returned value.
- base::Value* Deserialize(int* error_code,
- std::string* error_message) override;
+ scoped_ptr<base::Value> Deserialize(int* error_code,
+ std::string* error_message) override;
void set_allow_trailing_comma(bool new_value) {
allow_trailing_comma_ = new_value;
diff --git a/chromium/base/json/json_value_converter.h b/chromium/base/json/json_value_converter.h
index f94d46e3ccf..a1e0d5bb5a5 100644
--- a/chromium/base/json/json_value_converter.h
+++ b/chromium/base/json/json_value_converter.h
@@ -5,12 +5,14 @@
#ifndef BASE_JSON_JSON_VALUE_CONVERTER_H_
#define BASE_JSON_JSON_VALUE_CONVERTER_H_
+#include <stddef.h>
+
#include <string>
#include <vector>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
#include "base/stl_util.h"
diff --git a/chromium/base/json/json_value_serializer_unittest.cc b/chromium/base/json/json_value_serializer_unittest.cc
index a4d7cdce06b..a8531f08e17 100644
--- a/chromium/base/json/json_value_serializer_unittest.cc
+++ b/chromium/base/json/json_value_serializer_unittest.cc
@@ -16,6 +16,7 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
@@ -93,8 +94,8 @@ TEST(JSONValueDeserializerTest, ReadProperJSONFromString) {
int error_code = 0;
std::string error_message;
- scoped_ptr<Value> value(
- str_deserializer.Deserialize(&error_code, &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());
@@ -112,8 +113,8 @@ TEST(JSONValueDeserializerTest, ReadProperJSONFromStringPiece) {
int error_code = 0;
std::string error_message;
- scoped_ptr<Value> value(
- str_deserializer.Deserialize(&error_code, &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());
@@ -129,14 +130,14 @@ TEST(JSONValueDeserializerTest, ReadJSONWithTrailingCommasFromString) {
int error_code = 0;
std::string error_message;
- scoped_ptr<Value> value(
- str_deserializer.Deserialize(&error_code, &error_message));
+ scoped_ptr<Value> value =
+ str_deserializer.Deserialize(&error_code, &error_message);
ASSERT_FALSE(value.get());
ASSERT_NE(0, error_code);
ASSERT_FALSE(error_message.empty());
// Now the flag is set and it must pass.
str_deserializer.set_allow_trailing_comma(true);
- value.reset(str_deserializer.Deserialize(&error_code, &error_message));
+ value = str_deserializer.Deserialize(&error_code, &error_message);
ASSERT_TRUE(value.get());
ASSERT_EQ(JSONReader::JSON_TRAILING_COMMA, error_code);
// Verify if the same JSON is still there.
@@ -157,8 +158,8 @@ TEST(JSONValueDeserializerTest, ReadProperJSONFromFile) {
int error_code = 0;
std::string error_message;
- scoped_ptr<Value> value(
- file_deserializer.Deserialize(&error_code, &error_message));
+ scoped_ptr<Value> value =
+ file_deserializer.Deserialize(&error_code, &error_message);
ASSERT_TRUE(value.get());
ASSERT_EQ(0, error_code);
ASSERT_TRUE(error_message.empty());
@@ -182,14 +183,14 @@ TEST(JSONValueDeserializerTest, ReadJSONWithCommasFromFile) {
// This must fail without the proper flag.
int error_code = 0;
std::string error_message;
- scoped_ptr<Value> value(
- file_deserializer.Deserialize(&error_code, &error_message));
+ scoped_ptr<Value> value =
+ file_deserializer.Deserialize(&error_code, &error_message);
ASSERT_FALSE(value.get());
ASSERT_NE(0, error_code);
ASSERT_FALSE(error_message.empty());
// Now the flag is set and it must pass.
file_deserializer.set_allow_trailing_comma(true);
- value.reset(file_deserializer.Deserialize(&error_code, &error_message));
+ value = file_deserializer.Deserialize(&error_code, &error_message);
ASSERT_TRUE(value.get());
ASSERT_EQ(JSONReader::JSON_TRAILING_COMMA, error_code);
// Verify if the same JSON is still there.
@@ -205,9 +206,9 @@ TEST(JSONValueDeserializerTest, AllowTrailingComma) {
JSONStringValueDeserializer deserializer(kTestWithCommas);
deserializer.set_allow_trailing_comma(true);
JSONStringValueDeserializer deserializer_expected(kTestNoCommas);
- root.reset(deserializer.Deserialize(NULL, NULL));
+ root = deserializer.Deserialize(NULL, NULL);
ASSERT_TRUE(root.get());
- root_expected.reset(deserializer_expected.Deserialize(NULL, NULL));
+ root_expected = deserializer_expected.Deserialize(NULL, NULL);
ASSERT_TRUE(root_expected.get());
ASSERT_TRUE(root->Equals(root_expected.get()));
}
@@ -216,7 +217,7 @@ TEST(JSONValueSerializerTest, Roundtrip) {
static const char kOriginalSerialization[] =
"{\"bool\":true,\"double\":3.14,\"int\":42,\"list\":[1,2],\"null\":null}";
JSONStringValueDeserializer deserializer(kOriginalSerialization);
- scoped_ptr<Value> root(deserializer.Deserialize(NULL, NULL));
+ scoped_ptr<Value> root = deserializer.Deserialize(NULL, NULL);
ASSERT_TRUE(root.get());
ASSERT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
@@ -326,7 +327,7 @@ TEST(JSONValueSerializerTest, UnicodeStrings) {
// escaped ascii text -> json
JSONStringValueDeserializer deserializer(kExpected);
- scoped_ptr<Value> deserial_root(deserializer.Deserialize(NULL, NULL));
+ scoped_ptr<Value> deserial_root = deserializer.Deserialize(NULL, NULL);
ASSERT_TRUE(deserial_root.get());
DictionaryValue* dict_root =
static_cast<DictionaryValue*>(deserial_root.get());
@@ -350,7 +351,7 @@ TEST(JSONValueSerializerTest, HexStrings) {
// escaped ascii text -> json
JSONStringValueDeserializer deserializer(kExpected);
- scoped_ptr<Value> deserial_root(deserializer.Deserialize(NULL, NULL));
+ scoped_ptr<Value> deserial_root = deserializer.Deserialize(NULL, NULL);
ASSERT_TRUE(deserial_root.get());
DictionaryValue* dict_root =
static_cast<DictionaryValue*>(deserial_root.get());
@@ -361,7 +362,7 @@ TEST(JSONValueSerializerTest, HexStrings) {
// Test converting escaped regular chars
static const char kEscapedChars[] = "{\"test\":\"\\u0067\\u006f\"}";
JSONStringValueDeserializer deserializer2(kEscapedChars);
- deserial_root.reset(deserializer2.Deserialize(NULL, NULL));
+ deserial_root = deserializer2.Deserialize(NULL, NULL);
ASSERT_TRUE(deserial_root.get());
dict_root = static_cast<DictionaryValue*>(deserial_root.get());
ASSERT_TRUE(dict_root->GetString("test", &test_value));
@@ -376,10 +377,8 @@ TEST(JSONValueSerializerTest, JSONReaderComments) {
ValidateJsonList("[ 1 /* one */ ] /* end */");
ValidateJsonList("[ 1 //// ,2\r\n ]");
- scoped_ptr<Value> root;
-
// It's ok to have a comment in a string.
- root.reset(JSONReader::DeprecatedRead("[\"// ok\\n /* foo */ \"]"));
+ scoped_ptr<Value> root = JSONReader::Read("[\"// ok\\n /* foo */ \"]");
ASSERT_TRUE(root.get() && root->IsType(Value::TYPE_LIST));
ListValue* list = static_cast<ListValue*>(root.get());
ASSERT_EQ(1U, list->GetSize());
@@ -390,11 +389,11 @@ TEST(JSONValueSerializerTest, JSONReaderComments) {
ASSERT_EQ("// ok\n /* foo */ ", value);
// You can't nest comments.
- root.reset(JSONReader::DeprecatedRead("/* /* inner */ outer */ [ 1 ]"));
+ root = JSONReader::Read("/* /* inner */ outer */ [ 1 ]");
ASSERT_FALSE(root.get());
// Not a open comment token.
- root.reset(JSONReader::DeprecatedRead("/ * * / [1]"));
+ root = JSONReader::Read("/ * * / [1]");
ASSERT_FALSE(root.get());
}
@@ -415,7 +414,7 @@ TEST_F(JSONFileValueSerializerTest, Roundtrip) {
JSONFileValueDeserializer deserializer(original_file_path);
scoped_ptr<Value> root;
- root.reset(deserializer.Deserialize(NULL, NULL));
+ root = deserializer.Deserialize(NULL, NULL);
ASSERT_TRUE(root.get());
ASSERT_TRUE(root->IsType(Value::TYPE_DICTIONARY));
@@ -463,7 +462,7 @@ TEST_F(JSONFileValueSerializerTest, RoundtripNested) {
JSONFileValueDeserializer deserializer(original_file_path);
scoped_ptr<Value> root;
- root.reset(deserializer.Deserialize(NULL, NULL));
+ root = deserializer.Deserialize(NULL, NULL);
ASSERT_TRUE(root.get());
// Now try writing.
@@ -488,7 +487,7 @@ TEST_F(JSONFileValueSerializerTest, NoWhitespace) {
ASSERT_TRUE(PathExists(source_file_path));
JSONFileValueDeserializer deserializer(source_file_path);
scoped_ptr<Value> root;
- root.reset(deserializer.Deserialize(NULL, NULL));
+ root = deserializer.Deserialize(NULL, NULL);
ASSERT_TRUE(root.get());
}
diff --git a/chromium/base/json/json_writer.cc b/chromium/base/json/json_writer.cc
index abfead80070..19bc0da972f 100644
--- a/chromium/base/json/json_writer.cc
+++ b/chromium/base/json/json_writer.cc
@@ -4,13 +4,17 @@
#include "base/json/json_writer.h"
+#include <stdint.h>
+
#include <cmath>
+#include <limits>
#include "base/json/string_escape.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
+#include "build/build_config.h"
namespace base {
@@ -79,10 +83,10 @@ bool JSONWriter::BuildJSONString(const Value& node, size_t depth) {
bool result = node.GetAsDouble(&value);
DCHECK(result);
if (omit_double_type_preservation_ &&
- value <= kint64max &&
- value >= kint64min &&
+ value <= std::numeric_limits<int64_t>::max() &&
+ value >= std::numeric_limits<int64_t>::min() &&
std::floor(value) == value) {
- json_string_->append(Int64ToString(static_cast<int64>(value)));
+ json_string_->append(Int64ToString(static_cast<int64_t>(value)));
return result;
}
std::string real = DoubleToString(value);
diff --git a/chromium/base/json/json_writer.h b/chromium/base/json/json_writer.h
index 5711665cbec..ef433414090 100644
--- a/chromium/base/json/json_writer.h
+++ b/chromium/base/json/json_writer.h
@@ -5,10 +5,12 @@
#ifndef BASE_JSON_JSON_WRITER_H_
#define BASE_JSON_JSON_WRITER_H_
+#include <stddef.h>
+
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
namespace base {
diff --git a/chromium/base/json/json_writer_unittest.cc b/chromium/base/json/json_writer_unittest.cc
index 0daeafce1d7..a62b3ba989b 100644
--- a/chromium/base/json/json_writer_unittest.cc
+++ b/chromium/base/json/json_writer_unittest.cc
@@ -4,6 +4,7 @@
#include "base/json/json_writer.h"
#include "base/values.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
@@ -57,10 +58,10 @@ TEST(JSONWriterTest, NestedTypes) {
scoped_ptr<ListValue> list(new ListValue());
scoped_ptr<DictionaryValue> inner_dict(new DictionaryValue());
inner_dict->SetInteger("inner int", 10);
- list->Append(inner_dict.Pass());
+ list->Append(std::move(inner_dict));
list->Append(make_scoped_ptr(new ListValue()));
list->AppendBoolean(true);
- root_dict.Set("list", list.Pass());
+ root_dict.Set("list", std::move(list));
// Test the pretty-printer.
EXPECT_TRUE(JSONWriter::Write(root_dict, &output_js));
@@ -92,7 +93,7 @@ TEST(JSONWriterTest, KeysWithPeriods) {
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());
+ period_dict.SetWithoutPathExpansion("d.e.f", std::move(period_dict2));
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);
diff --git a/chromium/base/json/string_escape.cc b/chromium/base/json/string_escape.cc
index f5d6a760218..f67fa93bf26 100644
--- a/chromium/base/json/string_escape.cc
+++ b/chromium/base/json/string_escape.cc
@@ -4,6 +4,10 @@
#include "base/json/string_escape.h"
+#include <stddef.h>
+#include <stdint.h>
+
+#include <limits>
#include <string>
#include "base/strings/string_util.h"
@@ -20,15 +24,15 @@ namespace {
const char kU16EscapeFormat[] = "\\u%04X";
// The code point to output for an invalid input code unit.
-const uint32 kReplacementCodePoint = 0xFFFD;
+const uint32_t kReplacementCodePoint = 0xFFFD;
// Used below in EscapeSpecialCodePoint().
-COMPILE_ASSERT('<' == 0x3C, less_than_sign_is_0x3c);
+static_assert('<' == 0x3C, "less than sign must be 0x3c");
// Try to escape the |code_point| if it is a known special character. If
// successful, returns true and appends the escape sequence to |dest|. This
// isn't required by the spec, but it's more readable by humans.
-bool EscapeSpecialCodePoint(uint32 code_point, std::string* dest) {
+bool EscapeSpecialCodePoint(uint32_t code_point, std::string* dest) {
// WARNING: if you add a new case here, you need to update the reader as well.
// Note: \v is in the reader, but not here since the JSON spec doesn't
// allow it.
@@ -80,12 +84,13 @@ bool EscapeJSONStringImpl(const S& str, bool put_in_quotes, std::string* dest) {
if (put_in_quotes)
dest->push_back('"');
- // Casting is necessary because ICU uses int32. Try and do so safely.
- CHECK_LE(str.length(), static_cast<size_t>(kint32max));
- const int32 length = static_cast<int32>(str.length());
+ // Casting is necessary because ICU uses int32_t. Try and do so safely.
+ CHECK_LE(str.length(),
+ static_cast<size_t>(std::numeric_limits<int32_t>::max()));
+ const int32_t length = static_cast<int32_t>(str.length());
- for (int32 i = 0; i < length; ++i) {
- uint32 code_point;
+ for (int32_t i = 0; i < length; ++i) {
+ uint32_t code_point;
if (!ReadUnicodeCharacter(str.data(), length, &i, &code_point)) {
code_point = kReplacementCodePoint;
did_replacement = true;
diff --git a/chromium/base/json/string_escape_unittest.cc b/chromium/base/json/string_escape_unittest.cc
index f7ccafc9cb5..ae3d82ad5e8 100644
--- a/chromium/base/json/string_escape_unittest.cc
+++ b/chromium/base/json/string_escape_unittest.cc
@@ -4,6 +4,9 @@
#include "base/json/string_escape.h"
+#include <stddef.h>
+
+#include "base/macros.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/base/lazy_instance.cc b/chromium/base/lazy_instance.cc
index 594c1fee4ff..54680655a2a 100644
--- a/chromium/base/lazy_instance.cc
+++ b/chromium/base/lazy_instance.cc
@@ -6,7 +6,6 @@
#include "base/at_exit.h"
#include "base/atomicops.h"
-#include "base/basictypes.h"
#include "base/threading/platform_thread.h"
namespace base {
diff --git a/chromium/base/lazy_instance.h b/chromium/base/lazy_instance.h
index d52b5431c29..fd0321017df 100644
--- a/chromium/base/lazy_instance.h
+++ b/chromium/base/lazy_instance.h
@@ -39,7 +39,6 @@
#include "base/atomicops.h"
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/debug/leak_annotations.h"
#include "base/logging.h"
#include "base/memory/aligned_memory.h"
diff --git a/chromium/base/lazy_instance_unittest.cc b/chromium/base/lazy_instance_unittest.cc
index ec9ef267320..8947b1291f6 100644
--- a/chromium/base/lazy_instance_unittest.cc
+++ b/chromium/base/lazy_instance_unittest.cc
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
+
#include "base/at_exit.h"
#include "base/atomic_sequence_num.h"
#include "base/lazy_instance.h"
diff --git a/chromium/base/linux_util.cc b/chromium/base/linux_util.cc
index d94588f98c6..744a2311fe6 100644
--- a/chromium/base/linux_util.cc
+++ b/chromium/base/linux_util.cc
@@ -7,6 +7,7 @@
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
+#include <limits.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -21,6 +22,7 @@
#include "base/process/launch.h"
#include "base/strings/string_util.h"
#include "base/synchronization/lock.h"
+#include "build/build_config.h"
namespace {
diff --git a/chromium/base/location.h b/chromium/base/location.h
index 477dc022273..d3bb23c63ea 100644
--- a/chromium/base/location.h
+++ b/chromium/base/location.h
@@ -5,11 +5,12 @@
#ifndef BASE_LOCATION_H_
#define BASE_LOCATION_H_
+#include <stddef.h>
+
#include <cassert>
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/containers/hash_tables.h"
namespace tracked_objects {
@@ -58,11 +59,7 @@ class BASE_EXPORT Location {
// 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()),
+ return base::HashPair(reinterpret_cast<uintptr_t>(location.file_name()),
location.line_number());
}
};
diff --git a/chromium/base/logging.cc b/chromium/base/logging.cc
index dc0b8b2472f..9ad50e8d993 100644
--- a/chromium/base/logging.cc
+++ b/chromium/base/logging.cc
@@ -4,6 +4,12 @@
#include "base/logging.h"
+#include <limits.h>
+#include <stdint.h>
+
+#include "base/macros.h"
+#include "build/build_config.h"
+
#if defined(OS_WIN)
#include <io.h>
#include <windows.h>
@@ -16,6 +22,8 @@ typedef HANDLE MutexHandle;
// Windows doesn't define STDERR_FILENO. Define it here.
#define STDERR_FILENO 2
#elif defined(OS_MACOSX)
+#include <asl.h>
+#include <CoreFoundation/CoreFoundation.h>
#include <mach/mach.h>
#include <mach/mach_time.h>
#include <mach-o/dyld.h>
@@ -30,10 +38,12 @@ typedef HANDLE MutexHandle;
#if defined(OS_POSIX)
#include <errno.h>
+#include <paths.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/stat.h>
#include <unistd.h>
#define MAX_PATH PATH_MAX
typedef FILE* FileHandle;
@@ -56,6 +66,7 @@ typedef pthread_mutex_t* MutexHandle;
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
+#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/lock_impl.h"
#include "base/threading/platform_thread.h"
@@ -121,7 +132,7 @@ LogMessageHandlerFunction log_message_handler = nullptr;
// Helper functions to wrap platform differences.
-int32 CurrentProcessId() {
+int32_t CurrentProcessId() {
#if defined(OS_WIN)
return GetCurrentProcessId();
#elif defined(OS_POSIX)
@@ -129,7 +140,7 @@ int32 CurrentProcessId() {
#endif
}
-uint64 TickCount() {
+uint64_t TickCount() {
#if defined(OS_WIN)
return GetTickCount();
#elif defined(OS_MACOSX)
@@ -142,9 +153,8 @@ uint64 TickCount() {
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
- uint64 absolute_micro =
- static_cast<int64>(ts.tv_sec) * 1000000 +
- static_cast<int64>(ts.tv_nsec) / 1000;
+ uint64_t absolute_micro = static_cast<int64_t>(ts.tv_sec) * 1000000 +
+ static_cast<int64_t>(ts.tv_nsec) / 1000;
return absolute_micro;
#endif
@@ -385,6 +395,17 @@ int GetMinLogLevel() {
return g_min_log_level;
}
+bool ShouldCreateLogMessage(int severity) {
+ if (severity < g_min_log_level)
+ return false;
+
+ // Return true here unless we know ~LogMessage won't do anything. Note that
+ // ~LogMessage writes to stderr if severity_ >= kAlwaysPrintErrorLevel, even
+ // when g_logging_destination is LOG_NONE.
+ return g_logging_destination != LOG_NONE || log_message_handler ||
+ severity >= kAlwaysPrintErrorLevel;
+}
+
int GetVlogVerbosity() {
return std::max(-1, LOG_INFO - GetMinLogLevel());
}
@@ -516,6 +537,121 @@ LogMessage::~LogMessage() {
if ((g_logging_destination & LOG_TO_SYSTEM_DEBUG_LOG) != 0) {
#if defined(OS_WIN)
OutputDebugStringA(str_newline.c_str());
+#elif defined(OS_MACOSX)
+ // In LOG_TO_SYSTEM_DEBUG_LOG mode, log messages are always written to
+ // stderr. If stderr is /dev/null, also log via ASL (Apple System Log). If
+ // there's something weird about stderr, assume that log messages are going
+ // nowhere and log via ASL too. Messages logged via ASL show up in
+ // Console.app.
+ //
+ // Programs started by launchd, as UI applications normally are, have had
+ // stderr connected to /dev/null since OS X 10.8. Prior to that, stderr was
+ // a pipe to launchd, which logged what it received (see log_redirect_fd in
+ // 10.7.5 launchd-392.39/launchd/src/launchd_core_logic.c).
+ //
+ // Another alternative would be to determine whether stderr is a pipe to
+ // launchd and avoid logging via ASL only in that case. See 10.7.5
+ // CF-635.21/CFUtilities.c also_do_stderr(). This would result in logging to
+ // both stderr and ASL even in tests, where it's undesirable to log to the
+ // system log at all.
+ //
+ // Note that the ASL client by default discards messages whose levels are
+ // below ASL_LEVEL_NOTICE. It's possible to change that with
+ // asl_set_filter(), but this is pointless because syslogd normally applies
+ // the same filter.
+ const bool log_via_asl = []() {
+ struct stat stderr_stat;
+ if (fstat(fileno(stderr), &stderr_stat) == -1) {
+ return true;
+ }
+ if (!S_ISCHR(stderr_stat.st_mode)) {
+ return false;
+ }
+
+ struct stat dev_null_stat;
+ if (stat(_PATH_DEVNULL, &dev_null_stat) == -1) {
+ return true;
+ }
+
+ return !S_ISCHR(dev_null_stat.st_mode) ||
+ stderr_stat.st_rdev == dev_null_stat.st_rdev;
+ }();
+
+ if (log_via_asl) {
+ // Log roughly the same way that CFLog() and NSLog() would. See 10.10.5
+ // CF-1153.18/CFUtilities.c __CFLogCString().
+ //
+ // The ASL facility is set to the main bundle ID if available. Otherwise,
+ // "com.apple.console" is used.
+ CFBundleRef main_bundle = CFBundleGetMainBundle();
+ CFStringRef main_bundle_id_cf =
+ main_bundle ? CFBundleGetIdentifier(main_bundle) : nullptr;
+ std::string asl_facility =
+ main_bundle_id_cf ? base::SysCFStringRefToUTF8(main_bundle_id_cf)
+ : std::string("com.apple.console");
+
+ class ASLClient {
+ public:
+ explicit ASLClient(const std::string& asl_facility)
+ : client_(asl_open(nullptr,
+ asl_facility.c_str(),
+ ASL_OPT_NO_DELAY)) {}
+ ~ASLClient() { asl_close(client_); }
+
+ aslclient get() const { return client_; }
+
+ private:
+ aslclient client_;
+ DISALLOW_COPY_AND_ASSIGN(ASLClient);
+ } asl_client(asl_facility);
+
+ class ASLMessage {
+ public:
+ ASLMessage() : message_(asl_new(ASL_TYPE_MSG)) {}
+ ~ASLMessage() { asl_free(message_); }
+
+ aslmsg get() const { return message_; }
+
+ private:
+ aslmsg message_;
+ DISALLOW_COPY_AND_ASSIGN(ASLMessage);
+ } asl_message;
+
+ // By default, messages are only readable by the admin group. Explicitly
+ // make them readable by the user generating the messages.
+ char euid_string[12];
+ snprintf(euid_string, arraysize(euid_string), "%d", geteuid());
+ asl_set(asl_message.get(), ASL_KEY_READ_UID, euid_string);
+
+ // Map Chrome log severities to ASL log levels.
+ const char* const asl_level_string = [](LogSeverity severity) {
+ // ASL_LEVEL_* are ints, but ASL needs equivalent strings. This
+ // non-obvious two-step macro trick achieves what's needed.
+ // https://gcc.gnu.org/onlinedocs/cpp/Stringification.html
+#define ASL_LEVEL_STR(level) ASL_LEVEL_STR_X(level)
+#define ASL_LEVEL_STR_X(level) #level
+ switch (severity) {
+ case LOG_INFO:
+ return ASL_LEVEL_STR(ASL_LEVEL_INFO);
+ case LOG_WARNING:
+ return ASL_LEVEL_STR(ASL_LEVEL_WARNING);
+ case LOG_ERROR:
+ return ASL_LEVEL_STR(ASL_LEVEL_ERR);
+ case LOG_FATAL:
+ return ASL_LEVEL_STR(ASL_LEVEL_CRIT);
+ default:
+ return severity < 0 ? ASL_LEVEL_STR(ASL_LEVEL_DEBUG)
+ : ASL_LEVEL_STR(ASL_LEVEL_NOTICE);
+ }
+#undef ASL_LEVEL_STR
+#undef ASL_LEVEL_STR_X
+ }(severity_);
+ asl_set(asl_message.get(), ASL_KEY_LEVEL, asl_level_string);
+
+ asl_set(asl_message.get(), ASL_KEY_MSG, str_newline.c_str());
+
+ asl_send(asl_client.get(), asl_message.get());
+ }
#elif defined(OS_ANDROID)
android_LogPriority priority =
(severity_ < 0) ? ANDROID_LOG_VERBOSE : ANDROID_LOG_UNKNOWN;
diff --git a/chromium/base/logging.h b/chromium/base/logging.h
index f49511832bd..300c9b52694 100644
--- a/chromium/base/logging.h
+++ b/chromium/base/logging.h
@@ -5,14 +5,16 @@
#ifndef BASE_LOGGING_H_
#define BASE_LOGGING_H_
+#include <stddef.h>
+
#include <cassert>
-#include <string>
#include <cstring>
#include <sstream>
+#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/debug/debugger.h"
+#include "base/macros.h"
#include "build/build_config.h"
//
@@ -238,6 +240,9 @@ BASE_EXPORT void SetMinLogLevel(int level);
// Gets the current log level.
BASE_EXPORT int GetMinLogLevel();
+// Used by LOG_IS_ON to lazy-evaluate stream arguments.
+BASE_EXPORT bool ShouldCreateLogMessage(int severity);
+
// Gets the VLOG default verbosity level.
BASE_EXPORT int GetVlogVerbosity();
@@ -340,7 +345,7 @@ const LogSeverity LOG_0 = LOG_ERROR;
// LOG_IS_ON(DFATAL) always holds in debug mode. In particular, CHECK()s will
// always fire if they fail.
#define LOG_IS_ON(severity) \
- ((::logging::LOG_ ## severity) >= ::logging::GetMinLogLevel())
+ (::logging::ShouldCreateLogMessage(::logging::LOG_##severity))
// We can't do any caching tricks with VLOG_IS_ON() like the
// google-glog version since it requires GCC extensions. This means
@@ -571,7 +576,6 @@ DEFINE_CHECK_OP_IMPL(GT, > )
#define CHECK_LT(val1, val2) CHECK_OP(LT, < , val1, val2)
#define CHECK_GE(val1, val2) CHECK_OP(GE, >=, val1, val2)
#define CHECK_GT(val1, val2) CHECK_OP(GT, > , val1, val2)
-#define CHECK_IMPLIES(val1, val2) CHECK(!(val1) || (val2))
#if defined(NDEBUG)
#define ENABLE_DLOG 0
@@ -725,7 +729,6 @@ const LogSeverity LOG_DCHECK = LOG_INFO;
#define DCHECK_LT(val1, val2) DCHECK_OP(LT, < , val1, val2)
#define DCHECK_GE(val1, val2) DCHECK_OP(GE, >=, val1, val2)
#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)
// Implement logging of NOTREACHED() as a dedicated function to get function
@@ -954,9 +957,9 @@ inline std::ostream& operator<<(std::ostream& out, const std::wstring& wstr) {
#define NOTIMPLEMENTED() EAT_STREAM_PARAMETERS
#elif NOTIMPLEMENTED_POLICY == 1
// TODO, figure out how to generate a warning
-#define NOTIMPLEMENTED() COMPILE_ASSERT(false, NOT_IMPLEMENTED)
+#define NOTIMPLEMENTED() static_assert(false, "NOT_IMPLEMENTED")
#elif NOTIMPLEMENTED_POLICY == 2
-#define NOTIMPLEMENTED() COMPILE_ASSERT(false, NOT_IMPLEMENTED)
+#define NOTIMPLEMENTED() static_assert(false, "NOT_IMPLEMENTED")
#elif NOTIMPLEMENTED_POLICY == 3
#define NOTIMPLEMENTED() NOTREACHED()
#elif NOTIMPLEMENTED_POLICY == 4
diff --git a/chromium/base/logging_unittest.cc b/chromium/base/logging_unittest.cc
index e0619425f75..22fb855b62a 100644
--- a/chromium/base/logging_unittest.cc
+++ b/chromium/base/logging_unittest.cc
@@ -2,9 +2,9 @@
// 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/compiler_specific.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -122,7 +122,7 @@ TEST_F(LoggingTest, LogIsOn) {
EXPECT_TRUE(kDfatalIsFatal == LOG_IS_ON(DFATAL));
}
-TEST_F(LoggingTest, LoggingIsLazy) {
+TEST_F(LoggingTest, LoggingIsLazyBySeverity) {
MockLogSource mock_log_source;
EXPECT_CALL(mock_log_source, Log()).Times(0);
@@ -151,6 +151,24 @@ TEST_F(LoggingTest, LoggingIsLazy) {
DVPLOG_IF(1, true) << mock_log_source.Log();
}
+TEST_F(LoggingTest, LoggingIsLazyByDestination) {
+ MockLogSource mock_log_source;
+ MockLogSource mock_log_source_error;
+ EXPECT_CALL(mock_log_source, Log()).Times(0);
+
+ // Severity >= ERROR is always printed to stderr.
+ EXPECT_CALL(mock_log_source_error, Log()).Times(1).
+ WillRepeatedly(Return("log message"));
+
+ LoggingSettings settings;
+ settings.logging_dest = LOG_NONE;
+ InitLogging(settings);
+
+ LOG(INFO) << mock_log_source.Log();
+ LOG(WARNING) << mock_log_source.Log();
+ LOG(ERROR) << mock_log_source_error.Log();
+}
+
// Official builds have CHECKs directly call BreakDebugger.
#if !defined(OFFICIAL_BUILD)
diff --git a/chromium/base/logging_win.h b/chromium/base/logging_win.h
index de34a644093..cdde7bb687c 100644
--- a/chromium/base/logging_win.h
+++ b/chromium/base/logging_win.h
@@ -5,12 +5,14 @@
#ifndef BASE_LOGGING_WIN_H_
#define BASE_LOGGING_WIN_H_
+#include <stddef.h>
+
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
-#include "base/win/event_trace_provider.h"
#include "base/logging.h"
+#include "base/macros.h"
+#include "base/win/event_trace_provider.h"
namespace base {
template <typename Type>
diff --git a/chromium/base/mac/authorization_util.mm b/chromium/base/mac/authorization_util.mm
index 1dfd5a019f2..d09b95d8005 100644
--- a/chromium/base/mac/authorization_util.mm
+++ b/chromium/base/mac/authorization_util.mm
@@ -5,16 +5,17 @@
#include "base/mac/authorization_util.h"
#import <Foundation/Foundation.h>
+#include <stddef.h>
#include <sys/wait.h>
#include <string>
-#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"
#include "base/mac/scoped_authorizationref.h"
+#include "base/macros.h"
#include "base/posix/eintr_wrapper.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
@@ -50,8 +51,8 @@ AuthorizationRef GetAuthorizationRightsWithPrompt(
const char* icon_path_c = [icon_path fileSystemRepresentation];
size_t icon_path_length = icon_path_c ? strlen(icon_path_c) : 0;
- // The OS will append " Type an administrator's name and password to allow
- // <CFBundleDisplayName> to make changes."
+ // The OS will dispay |prompt| along with a sentence asking the user to type
+ // the "password to allow this."
NSString* prompt_ns = base::mac::CFToNSCast(prompt);
const char* prompt_c = [prompt_ns UTF8String];
size_t prompt_length = prompt_c ? strlen(prompt_c) : 0;
diff --git a/chromium/base/mac/call_with_eh_frame.cc b/chromium/base/mac/call_with_eh_frame.cc
index 8ea6f75b4bf..7267676d666 100644
--- a/chromium/base/mac/call_with_eh_frame.cc
+++ b/chromium/base/mac/call_with_eh_frame.cc
@@ -4,6 +4,7 @@
#include "base/mac/call_with_eh_frame.h"
+#include <stdint.h>
#include <unwind.h>
#include "build/build_config.h"
diff --git a/chromium/base/mac/call_with_eh_frame_unittest.mm b/chromium/base/mac/call_with_eh_frame_unittest.mm
index 46bf285c2cd..4dad822093c 100644
--- a/chromium/base/mac/call_with_eh_frame_unittest.mm
+++ b/chromium/base/mac/call_with_eh_frame_unittest.mm
@@ -15,7 +15,9 @@ namespace {
class CallWithEHFrameTest : public testing::Test {
protected:
void ThrowException() {
- [NSArray arrayWithObject:nil];
+ @throw [NSException exceptionWithName:@"TestException"
+ reason:@"Testing exceptions"
+ userInfo:nil];
}
};
diff --git a/chromium/base/mac/foundation_util.h b/chromium/base/mac/foundation_util.h
index 6e8505da21b..ee23a17fb16 100644
--- a/chromium/base/mac/foundation_util.h
+++ b/chromium/base/mac/foundation_util.h
@@ -13,6 +13,7 @@
#include "base/base_export.h"
#include "base/logging.h"
#include "base/mac/scoped_cftyperef.h"
+#include "build/build_config.h"
#if defined(__OBJC__)
#import <Foundation/Foundation.h>
diff --git a/chromium/base/mac/foundation_util.mm b/chromium/base/mac/foundation_util.mm
index bd5d51452dc..524f17cdb63 100644
--- a/chromium/base/mac/foundation_util.mm
+++ b/chromium/base/mac/foundation_util.mm
@@ -4,6 +4,7 @@
#include "base/mac/foundation_util.h"
+#include <stddef.h>
#include <stdlib.h>
#include <string.h>
@@ -11,8 +12,10 @@
#include "base/logging.h"
#include "base/mac/bundle_locations.h"
#include "base/mac/mac_logging.h"
+#include "base/macros.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/sys_string_conversions.h"
+#include "build/build_config.h"
#if !defined(OS_IOS)
extern "C" {
diff --git a/chromium/base/mac/foundation_util_unittest.mm b/chromium/base/mac/foundation_util_unittest.mm
index c688442a688..e15daf4d20e 100644
--- a/chromium/base/mac/foundation_util_unittest.mm
+++ b/chromium/base/mac/foundation_util_unittest.mm
@@ -4,13 +4,17 @@
#include "base/mac/foundation_util.h"
-#include "base/basictypes.h"
+#include <limits.h>
+#include <stddef.h>
+
#include "base/compiler_specific.h"
#include "base/files/file_path.h"
#include "base/format_macros.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/mac/scoped_nsautorelease_pool.h"
+#include "base/macros.h"
#include "base/strings/stringprintf.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#import "testing/gtest_mac.h"
@@ -281,8 +285,8 @@ TEST(FoundationUtilTest, GetValueFromDictionary) {
CFStringRef keys[] = { CFSTR("one"), CFSTR("two"), CFSTR("three") };
CFNumberRef values[] = { cf_one, cf_two, cf_three };
- COMPILE_ASSERT(arraysize(keys) == arraysize(values),
- keys_and_values_arraysizes_are_different);
+ static_assert(arraysize(keys) == arraysize(values),
+ "keys and values arrays must have the same size");
ScopedCFTypeRef<CFDictionaryRef> test_dict(
CFDictionaryCreate(kCFAllocatorDefault,
diff --git a/chromium/base/mac/launchd.cc b/chromium/base/mac/launchd.cc
index 1d384c93a27..0337d2e6097 100644
--- a/chromium/base/mac/launchd.cc
+++ b/chromium/base/mac/launchd.cc
@@ -18,7 +18,7 @@ launch_data_t MessageForJob(const std::string& job_label,
const char* operation) {
// launch_data_alloc returns something that needs to be freed.
ScopedLaunchData message(launch_data_alloc(LAUNCH_DATA_DICTIONARY));
- if (!message) {
+ if (!message.is_valid()) {
LOG(ERROR) << "launch_data_alloc";
return NULL;
}
@@ -28,38 +28,38 @@ launch_data_t MessageForJob(const std::string& job_label,
// called, so put it in a scoper and .release() it when given to the
// dictionary.
ScopedLaunchData job_label_launchd(launch_data_new_string(job_label.c_str()));
- if (!job_label_launchd) {
+ if (!job_label_launchd.is_valid()) {
LOG(ERROR) << "launch_data_new_string";
return NULL;
}
- if (!launch_data_dict_insert(message,
- job_label_launchd.release(),
+ if (!launch_data_dict_insert(message.get(), job_label_launchd.release(),
operation)) {
return NULL;
}
- return launch_msg(message);
+ return launch_msg(message.get());
}
pid_t PIDForJob(const std::string& job_label) {
ScopedLaunchData response(MessageForJob(job_label, LAUNCH_KEY_GETJOB));
- if (!response) {
+ if (!response.is_valid()) {
return -1;
}
- launch_data_type_t response_type = launch_data_get_type(response);
+ launch_data_type_t response_type = launch_data_get_type(response.get());
if (response_type != LAUNCH_DATA_DICTIONARY) {
if (response_type == LAUNCH_DATA_ERRNO) {
- LOG(ERROR) << "PIDForJob: error " << launch_data_get_errno(response);
+ LOG(ERROR) << "PIDForJob: error "
+ << launch_data_get_errno(response.get());
} else {
LOG(ERROR) << "PIDForJob: expected dictionary, got " << response_type;
}
return -1;
}
- launch_data_t pid_data = launch_data_dict_lookup(response,
- LAUNCH_JOBKEY_PID);
+ launch_data_t pid_data =
+ launch_data_dict_lookup(response.get(), LAUNCH_JOBKEY_PID);
if (!pid_data)
return 0;
diff --git a/chromium/base/mac/libdispatch_task_runner.cc b/chromium/base/mac/libdispatch_task_runner.cc
index 4b5abaf30c9..adf12619d67 100644
--- a/chromium/base/mac/libdispatch_task_runner.cc
+++ b/chromium/base/mac/libdispatch_task_runner.cc
@@ -4,6 +4,8 @@
#include "base/mac/libdispatch_task_runner.h"
+#include <stdint.h>
+
#include "base/callback.h"
namespace base {
@@ -31,7 +33,7 @@ bool LibDispatchTaskRunner::PostDelayedTask(
task_copy.Run();
};
- int64 delay_nano =
+ int64_t delay_nano =
delay.InMicroseconds() * base::Time::kNanosecondsPerMicrosecond;
if (delay_nano > 0) {
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, delay_nano);
diff --git a/chromium/base/mac/libdispatch_task_runner_unittest.cc b/chromium/base/mac/libdispatch_task_runner_unittest.cc
index 49b0c9ae9d7..bfe776c6970 100644
--- a/chromium/base/mac/libdispatch_task_runner_unittest.cc
+++ b/chromium/base/mac/libdispatch_task_runner_unittest.cc
@@ -4,8 +4,11 @@
#include "base/mac/libdispatch_task_runner.h"
+#include <stddef.h>
+
#include "base/bind.h"
#include "base/mac/bind_objc_block.h"
+#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/stringprintf.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/base/mac/mac_logging.cc b/chromium/base/mac/mac_logging.cc
index d58220fe897..e82b0ed5f6c 100644
--- a/chromium/base/mac/mac_logging.cc
+++ b/chromium/base/mac/mac_logging.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "base/mac/mac_logging.h"
+#include "build/build_config.h"
#include <iomanip>
diff --git a/chromium/base/mac/mac_logging.h b/chromium/base/mac/mac_logging.h
index 5192b208f1c..f55890285e0 100644
--- a/chromium/base/mac/mac_logging.h
+++ b/chromium/base/mac/mac_logging.h
@@ -6,8 +6,8 @@
#define BASE_MAC_MAC_LOGGING_H_
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "build/build_config.h"
#if defined(OS_IOS)
diff --git a/chromium/base/mac/mac_util.h b/chromium/base/mac/mac_util.h
index a452a39bdd4..7772e883fad 100644
--- a/chromium/base/mac/mac_util.h
+++ b/chromium/base/mac/mac_util.h
@@ -7,6 +7,7 @@
#include <AvailabilityMacros.h>
#include <Carbon/Carbon.h>
+#include <stdint.h>
#include <string>
#include "base/base_export.h"
@@ -240,8 +241,8 @@ BASE_EXPORT std::string GetModelIdentifier();
// If any error occurs, none of the input pointers are touched.
BASE_EXPORT bool ParseModelIdentifier(const std::string& ident,
std::string* type,
- int32* major,
- int32* minor);
+ int32_t* major,
+ int32_t* minor);
} // namespace mac
} // namespace base
diff --git a/chromium/base/mac/mac_util.mm b/chromium/base/mac/mac_util.mm
index 647faf3866f..75d53c90961 100644
--- a/chromium/base/mac/mac_util.mm
+++ b/chromium/base/mac/mac_util.mm
@@ -6,8 +6,8 @@
#import <Cocoa/Cocoa.h>
#import <IOKit/IOKitLib.h>
-
#include <errno.h>
+#include <stddef.h>
#include <string.h>
#include <sys/utsname.h>
#include <sys/xattr.h>
@@ -582,15 +582,15 @@ std::string GetModelIdentifier() {
bool ParseModelIdentifier(const std::string& ident,
std::string* type,
- int32* major,
- int32* minor) {
+ int32_t* major,
+ int32_t* minor) {
size_t number_loc = ident.find_first_of("0123456789");
if (number_loc == std::string::npos)
return false;
size_t comma_loc = ident.find(',', number_loc);
if (comma_loc == std::string::npos)
return false;
- int32 major_tmp, minor_tmp;
+ int32_t major_tmp, minor_tmp;
std::string::const_iterator begin = ident.begin();
if (!StringToInt(
StringPiece(begin + number_loc, begin + comma_loc), &major_tmp) ||
diff --git a/chromium/base/mac/mac_util_unittest.mm b/chromium/base/mac/mac_util_unittest.mm
index 35b6e568f05..c5042a05f0b 100644
--- a/chromium/base/mac/mac_util_unittest.mm
+++ b/chromium/base/mac/mac_util_unittest.mm
@@ -3,6 +3,8 @@
// found in the LICENSE file.
#import <Cocoa/Cocoa.h>
+#include <stddef.h>
+#include <stdint.h>
#include "base/mac/mac_util.h"
@@ -12,6 +14,7 @@
#include "base/mac/foundation_util.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/mac/scoped_nsobject.h"
+#include "base/macros.h"
#include "base/sys_info.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
@@ -138,7 +141,7 @@ TEST_F(MacUtilTest, NSObjectRetainRelease) {
}
TEST_F(MacUtilTest, IsOSEllipsis) {
- int32 major, minor, bugfix;
+ int32_t major, minor, bugfix;
base::SysInfo::OperatingSystemVersionNumbers(&major, &minor, &bugfix);
if (major == 10) {
@@ -256,7 +259,7 @@ TEST_F(MacUtilTest, IsOSEllipsis) {
TEST_F(MacUtilTest, ParseModelIdentifier) {
std::string model;
- int32 major = 1, minor = 2;
+ int32_t major = 1, minor = 2;
EXPECT_FALSE(ParseModelIdentifier("", &model, &major, &minor));
EXPECT_EQ(0U, model.length());
diff --git a/chromium/base/mac/mach_logging.cc b/chromium/base/mac/mach_logging.cc
index c5ff85e662f..7b939b3dd9a 100644
--- a/chromium/base/mac/mach_logging.cc
+++ b/chromium/base/mac/mach_logging.cc
@@ -8,6 +8,7 @@
#include <string>
#include "base/strings/stringprintf.h"
+#include "build/build_config.h"
#if !defined(OS_IOS)
#include <servers/bootstrap.h>
diff --git a/chromium/base/mac/mach_logging.h b/chromium/base/mac/mach_logging.h
index b12e274ea80..59ab762c3c4 100644
--- a/chromium/base/mac/mach_logging.h
+++ b/chromium/base/mac/mach_logging.h
@@ -8,8 +8,8 @@
#include <mach/mach.h>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "build/build_config.h"
// Use the MACH_LOG family of macros along with a mach_error_t (kern_return_t)
diff --git a/chromium/base/mac/os_crash_dumps.cc b/chromium/base/mac/os_crash_dumps.cc
index 5d65b469ddd..95af0097941 100644
--- a/chromium/base/mac/os_crash_dumps.cc
+++ b/chromium/base/mac/os_crash_dumps.cc
@@ -5,10 +5,11 @@
#include "base/mac/os_crash_dumps.h"
#include <signal.h>
+#include <stddef.h>
#include <unistd.h>
-#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/macros.h"
namespace base {
namespace mac {
diff --git a/chromium/base/mac/scoped_aedesc.h b/chromium/base/mac/scoped_aedesc.h
index a1323c0cb7d..73270920dda 100644
--- a/chromium/base/mac/scoped_aedesc.h
+++ b/chromium/base/mac/scoped_aedesc.h
@@ -7,7 +7,7 @@
#import <CoreServices/CoreServices.h>
-#include "base/basictypes.h"
+#include "base/macros.h"
namespace base {
namespace mac {
diff --git a/chromium/base/mac/scoped_authorizationref.h b/chromium/base/mac/scoped_authorizationref.h
index 18114883800..39afa8c9a5d 100644
--- a/chromium/base/mac/scoped_authorizationref.h
+++ b/chromium/base/mac/scoped_authorizationref.h
@@ -7,8 +7,8 @@
#include <Security/Authorization.h>
-#include "base/basictypes.h"
#include "base/compiler_specific.h"
+#include "base/macros.h"
// ScopedAuthorizationRef maintains ownership of an AuthorizationRef. It is
// patterned after the scoped_ptr interface.
diff --git a/chromium/base/mac/scoped_block.h b/chromium/base/mac/scoped_block.h
index 509a1c2c19d..bc2688f13ac 100644
--- a/chromium/base/mac/scoped_block.h
+++ b/chromium/base/mac/scoped_block.h
@@ -7,84 +7,27 @@
#include <Block.h>
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/memory/scoped_policy.h"
+#include "base/mac/scoped_typeref.h"
namespace base {
namespace mac {
-// ScopedBlock<> is patterned after ScopedCFTypeRef<>, but uses Block_copy() and
-// Block_release() instead of CFRetain() and CFRelease().
-
-template<typename B>
-class ScopedBlock {
- public:
- explicit ScopedBlock(
- B block = NULL,
- base::scoped_policy::OwnershipPolicy policy = base::scoped_policy::ASSUME)
- : block_(block) {
- if (block_ && policy == base::scoped_policy::RETAIN)
- block_ = Block_copy(block);
- }
-
- ScopedBlock(const ScopedBlock<B>& that)
- : block_(that.block_) {
- if (block_)
- block_ = Block_copy(block_);
- }
-
- ~ScopedBlock() {
- if (block_)
- Block_release(block_);
- }
-
- ScopedBlock& operator=(const ScopedBlock<B>& that) {
- reset(that.get(), base::scoped_policy::RETAIN);
- return *this;
- }
-
- void reset(B block = NULL,
- base::scoped_policy::OwnershipPolicy policy =
- base::scoped_policy::ASSUME) {
- if (block && policy == base::scoped_policy::RETAIN)
- block = Block_copy(block);
- if (block_)
- Block_release(block_);
- block_ = block;
- }
+namespace internal {
- bool operator==(B that) const {
- return block_ == that;
- }
-
- bool operator!=(B that) const {
- return block_ != that;
- }
-
- operator B() const {
- return block_;
- }
-
- B get() const {
- return block_;
- }
+template <typename B>
+struct ScopedBlockTraits {
+ static B InvalidValue() { return nullptr; }
+ static B Retain(B block) { return Block_copy(block); }
+ static void Release(B block) { Block_release(block); }
+};
- void swap(ScopedBlock& that) {
- B temp = that.block_;
- that.block_ = block_;
- block_ = temp;
- }
+} // namespace internal
- B release() WARN_UNUSED_RESULT {
- B temp = block_;
- block_ = NULL;
- return temp;
- }
+// ScopedBlock<> is patterned after ScopedCFTypeRef<>, but uses Block_copy() and
+// Block_release() instead of CFRetain() and CFRelease().
- private:
- B block_;
-};
+template <typename B>
+using ScopedBlock = ScopedTypeRef<B, internal::ScopedBlockTraits<B>>;
} // namespace mac
} // namespace base
diff --git a/chromium/base/mac/scoped_cffiledescriptorref.h b/chromium/base/mac/scoped_cffiledescriptorref.h
index 07196aa9212..923a159c768 100644
--- a/chromium/base/mac/scoped_cffiledescriptorref.h
+++ b/chromium/base/mac/scoped_cffiledescriptorref.h
@@ -7,67 +7,31 @@
#include <CoreFoundation/CoreFoundation.h>
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
+#include "base/scoped_generic.h"
namespace base {
namespace mac {
+namespace internal {
+
+struct ScopedCFFileDescriptorRefTraits {
+ static CFFileDescriptorRef InvalidValue() { return nullptr; }
+ static void Free(CFFileDescriptorRef ref) {
+ CFFileDescriptorInvalidate(ref);
+ CFRelease(ref);
+ }
+};
+
+} // namespace internal
+
// ScopedCFFileDescriptorRef is designed after ScopedCFTypeRef<>. On
// destruction, it will invalidate the file descriptor.
// ScopedCFFileDescriptorRef (unlike ScopedCFTypeRef<>) does not support RETAIN
// semantics, copying, or assignment, as doing so would increase the chances
// that a file descriptor is invalidated while still in use.
-class ScopedCFFileDescriptorRef {
- public:
- explicit ScopedCFFileDescriptorRef(CFFileDescriptorRef fdref = NULL)
- : fdref_(fdref) {
- }
-
- ~ScopedCFFileDescriptorRef() {
- if (fdref_) {
- CFFileDescriptorInvalidate(fdref_);
- CFRelease(fdref_);
- }
- }
-
- void reset(CFFileDescriptorRef fdref = NULL) {
- if (fdref_ == fdref)
- return;
- if (fdref_) {
- CFFileDescriptorInvalidate(fdref_);
- CFRelease(fdref_);
- }
- fdref_ = fdref;
- }
-
- bool operator==(CFFileDescriptorRef that) const {
- return fdref_ == that;
- }
-
- bool operator!=(CFFileDescriptorRef that) const {
- return fdref_ != that;
- }
-
- operator CFFileDescriptorRef() const {
- return fdref_;
- }
-
- CFFileDescriptorRef get() const {
- return fdref_;
- }
-
- CFFileDescriptorRef release() WARN_UNUSED_RESULT {
- CFFileDescriptorRef temp = fdref_;
- fdref_ = NULL;
- return temp;
- }
-
- private:
- CFFileDescriptorRef fdref_;
-
- DISALLOW_COPY_AND_ASSIGN(ScopedCFFileDescriptorRef);
-};
+using ScopedCFFileDescriptorRef =
+ ScopedGeneric<CFFileDescriptorRef,
+ internal::ScopedCFFileDescriptorRefTraits>;
} // namespace mac
} // namespace base
diff --git a/chromium/base/mac/scoped_cftyperef.h b/chromium/base/mac/scoped_cftyperef.h
index 8567f85ffcd..1be0fbe56d1 100644
--- a/chromium/base/mac/scoped_cftyperef.h
+++ b/chromium/base/mac/scoped_cftyperef.h
@@ -27,11 +27,14 @@ namespace base {
namespace internal {
+template<typename CFT>
struct ScopedCFTypeRefTraits {
- static void Retain(CFTypeRef object) {
+ static CFT InvalidValue() { return nullptr; }
+ static CFT Retain(CFT object) {
CFRetain(object);
+ return object;
}
- static void Release(CFTypeRef object) {
+ static void Release(CFT object) {
CFRelease(object);
}
};
@@ -39,20 +42,8 @@ struct ScopedCFTypeRefTraits {
} // namespace internal
template<typename CFT>
-class ScopedCFTypeRef
- : public ScopedTypeRef<CFT, internal::ScopedCFTypeRefTraits> {
- public:
- typedef CFT element_type;
-
- explicit ScopedCFTypeRef(
- CFT object = NULL,
- base::scoped_policy::OwnershipPolicy policy = base::scoped_policy::ASSUME)
- : ScopedTypeRef<CFT,
- internal::ScopedCFTypeRefTraits>(object, policy) {}
-
- ScopedCFTypeRef(const ScopedCFTypeRef<CFT>& that)
- : ScopedTypeRef<CFT, internal::ScopedCFTypeRefTraits>(that) {}
-};
+using ScopedCFTypeRef =
+ ScopedTypeRef<CFT, internal::ScopedCFTypeRefTraits<CFT>>;
} // namespace base
diff --git a/chromium/base/mac/scoped_ioobject.h b/chromium/base/mac/scoped_ioobject.h
index 854039b5537..c948cb55423 100644
--- a/chromium/base/mac/scoped_ioobject.h
+++ b/chromium/base/mac/scoped_ioobject.h
@@ -7,66 +7,28 @@
#include <IOKit/IOKitLib.h>
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
+#include "base/mac/scoped_typeref.h"
namespace base {
namespace mac {
-// Just like ScopedCFTypeRef but for io_object_t and subclasses.
-template<typename IOT>
-class ScopedIOObject {
- public:
- typedef IOT element_type;
-
- explicit ScopedIOObject(IOT object = IO_OBJECT_NULL)
- : object_(object) {
- }
-
- ~ScopedIOObject() {
- if (object_)
- IOObjectRelease(object_);
- }
-
- void reset(IOT object = IO_OBJECT_NULL) {
- if (object_)
- IOObjectRelease(object_);
- object_ = object;
- }
-
- bool operator==(IOT that) const {
- return object_ == that;
- }
-
- bool operator!=(IOT that) const {
- return object_ != that;
- }
-
- operator IOT() const {
- return object_;
- }
-
- IOT get() const {
- return object_;
- }
+namespace internal {
- void swap(ScopedIOObject& that) {
- IOT temp = that.object_;
- that.object_ = object_;
- object_ = temp;
- }
-
- IOT release() WARN_UNUSED_RESULT {
- IOT temp = object_;
- object_ = IO_OBJECT_NULL;
- return temp;
+template <typename IOT>
+struct ScopedIOObjectTraits {
+ static IOT InvalidValue() { return IO_OBJECT_NULL; }
+ static IOT Retain(IOT iot) {
+ IOObjectRetain(iot);
+ return iot;
}
+ static void Release(IOT iot) { IOObjectRelease(iot); }
+};
- private:
- IOT object_;
+} // namespce internal
- DISALLOW_COPY_AND_ASSIGN(ScopedIOObject);
-};
+// Just like ScopedCFTypeRef but for io_object_t and subclasses.
+template <typename IOT>
+using ScopedIOObject = ScopedTypeRef<IOT, internal::ScopedIOObjectTraits<IOT>>;
} // namespace mac
} // namespace base
diff --git a/chromium/base/mac/scoped_ioplugininterface.h b/chromium/base/mac/scoped_ioplugininterface.h
index 503980c3ef8..872da8eaa53 100644
--- a/chromium/base/mac/scoped_ioplugininterface.h
+++ b/chromium/base/mac/scoped_ioplugininterface.h
@@ -7,68 +7,30 @@
#include <IOKit/IOKitLib.h>
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
+#include "base/mac/scoped_typeref.h"
namespace base {
namespace mac {
-// Just like ScopedCFTypeRef but for IOCFPlugInInterface and friends
-// (IOUSBInterfaceStruct and IOUSBDeviceStruct320 in particular).
-template<typename T>
-class ScopedIOPluginInterface {
- public:
- typedef T** InterfaceT;
- typedef InterfaceT element_type;
-
- explicit ScopedIOPluginInterface(InterfaceT object = NULL)
- : object_(object) {
- }
-
- ~ScopedIOPluginInterface() {
- if (object_)
- (*object_)->Release(object_);
- }
-
- void reset(InterfaceT object = NULL) {
- if (object_)
- (*object_)->Release(object_);
- object_ = object;
- }
-
- bool operator==(InterfaceT that) const {
- return object_ == that;
- }
-
- bool operator!=(InterfaceT that) const {
- return object_ != that;
- }
-
- operator InterfaceT() const {
- return object_;
- }
+namespace internal {
- InterfaceT get() const {
- return object_;
- }
-
- void swap(ScopedIOPluginInterface& that) {
- InterfaceT temp = that.object_;
- that.object_ = object_;
- object_ = temp;
- }
-
- InterfaceT release() WARN_UNUSED_RESULT {
- InterfaceT temp = object_;
- object_ = NULL;
- return temp;
+template <typename T>
+struct ScopedIOPluginInterfaceTraits {
+ static T InvalidValue() { return nullptr; }
+ static T Retain(T t) {
+ (*t)->AddRef(t);
+ return t;
}
+ static void Release(T t) { (*t)->Release(t); }
+};
- private:
- InterfaceT object_;
+} // namespace internal
- DISALLOW_COPY_AND_ASSIGN(ScopedIOPluginInterface);
-};
+// Just like ScopedCFTypeRef but for IOCFPlugInInterface and friends
+// (IOUSBInterfaceStruct and IOUSBDeviceStruct320 in particular).
+template <typename T>
+using ScopedIOPluginInterface =
+ ScopedTypeRef<T**, internal::ScopedIOPluginInterfaceTraits<T**>>;
} // namespace mac
} // namespace base
diff --git a/chromium/base/mac/scoped_launch_data.h b/chromium/base/mac/scoped_launch_data.h
index e4343b89399..da62006bfb2 100644
--- a/chromium/base/mac/scoped_launch_data.h
+++ b/chromium/base/mac/scoped_launch_data.h
@@ -7,67 +7,23 @@
#include <launch.h>
-#include <algorithm>
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
+#include "base/scoped_generic.h"
namespace base {
namespace mac {
-// Just like scoped_ptr<> but for launch_data_t.
-class ScopedLaunchData {
- public:
- typedef launch_data_t element_type;
-
- explicit ScopedLaunchData(launch_data_t object = NULL)
- : object_(object) {
- }
-
- ~ScopedLaunchData() {
- if (object_)
- launch_data_free(object_);
- }
-
- void reset(launch_data_t object = NULL) {
- if (object != object_) {
- if (object_)
- launch_data_free(object_);
- object_ = object;
- }
- }
-
- bool operator==(launch_data_t that) const {
- return object_ == that;
- }
-
- bool operator!=(launch_data_t that) const {
- return object_ != that;
- }
+namespace internal {
- operator launch_data_t() const {
- return object_;
- }
-
- launch_data_t get() const {
- return object_;
- }
-
- void swap(ScopedLaunchData& that) {
- std::swap(object_, that.object_);
- }
-
- launch_data_t release() WARN_UNUSED_RESULT {
- launch_data_t temp = object_;
- object_ = NULL;
- return temp;
- }
+struct ScopedLaunchDataTraits {
+ static launch_data_t InvalidValue() { return nullptr; }
+ static void Free(launch_data_t ldt) { launch_data_free(ldt); }
+};
- private:
- launch_data_t object_;
+} // namespace internal
- DISALLOW_COPY_AND_ASSIGN(ScopedLaunchData);
-};
+// Just like scoped_ptr<> but for launch_data_t.
+using ScopedLaunchData =
+ ScopedGeneric<launch_data_t, internal::ScopedLaunchDataTraits>;
} // namespace mac
} // namespace base
diff --git a/chromium/base/mac/scoped_mach_port.h b/chromium/base/mac/scoped_mach_port.h
index beb62b03213..67fed6bcfd8 100644
--- a/chromium/base/mac/scoped_mach_port.h
+++ b/chromium/base/mac/scoped_mach_port.h
@@ -45,40 +45,21 @@ struct PortSetTraits {
// reference counted, and this takes ownership of the right on construction
// and then removes a reference to the right on destruction. If the reference
// is the last one on the right, the right is deallocated.
-class BASE_EXPORT ScopedMachSendRight :
- public base::ScopedGeneric<mach_port_t, internal::SendRightTraits> {
- public:
- explicit ScopedMachSendRight(mach_port_t port = traits_type::InvalidValue())
- : ScopedGeneric(port) {}
-
- operator mach_port_t() const { return get(); }
-};
+using ScopedMachSendRight =
+ ScopedGeneric<mach_port_t, internal::SendRightTraits>;
// A scoper for handling a Mach port's receive right. There is only one
// receive right per port. This takes ownership of the receive right on
// construction and then destroys the right on destruction, turning all
// outstanding send rights into dead names.
-class BASE_EXPORT ScopedMachReceiveRight :
- public base::ScopedGeneric<mach_port_t, internal::ReceiveRightTraits> {
- public:
- explicit ScopedMachReceiveRight(
- mach_port_t port = traits_type::InvalidValue()) : ScopedGeneric(port) {}
-
- operator mach_port_t() const { return get(); }
-};
+using ScopedMachReceiveRight =
+ ScopedGeneric<mach_port_t, internal::ReceiveRightTraits>;
// 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(); }
-};
+using ScopedMachPortSet = ScopedGeneric<mach_port_t, internal::PortSetTraits>;
} // namespace mac
} // namespace base
diff --git a/chromium/base/mac/scoped_mach_vm.h b/chromium/base/mac/scoped_mach_vm.h
index ffc00d5a5d2..58a13f66497 100644
--- a/chromium/base/mac/scoped_mach_vm.h
+++ b/chromium/base/mac/scoped_mach_vm.h
@@ -6,12 +6,13 @@
#define BASE_MAC_SCOPED_MACH_VM_H_
#include <mach/mach.h>
+#include <stddef.h>
#include <algorithm>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/macros.h"
// Use ScopedMachVM to supervise ownership of pages in the current process
// through the Mach VM subsystem. Pages allocated with vm_allocate can be
diff --git a/chromium/base/mac/scoped_nsautorelease_pool.h b/chromium/base/mac/scoped_nsautorelease_pool.h
index 60af71ae055..4d15e6da4cf 100644
--- a/chromium/base/mac/scoped_nsautorelease_pool.h
+++ b/chromium/base/mac/scoped_nsautorelease_pool.h
@@ -6,7 +6,7 @@
#define BASE_MAC_SCOPED_NSAUTORELEASE_POOL_H_
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
#if defined(__OBJC__)
@class NSAutoreleasePool;
diff --git a/chromium/base/mac/scoped_nsobject.h b/chromium/base/mac/scoped_nsobject.h
index 836bdcc3507..04c5877db71 100644
--- a/chromium/base/mac/scoped_nsobject.h
+++ b/chromium/base/mac/scoped_nsobject.h
@@ -5,13 +5,15 @@
#ifndef BASE_MAC_SCOPED_NSOBJECT_H_
#define BASE_MAC_SCOPED_NSOBJECT_H_
+#include <type_traits>
+
// 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"
+#include "base/mac/scoped_typeref.h"
@class NSAutoreleasePool;
@@ -37,71 +39,26 @@ namespace base {
// We check for bad uses of scoped_nsobject and NSAutoreleasePool at compile
// time with a template specialization (see below).
-template<typename NST>
-class scoped_nsprotocol {
+namespace internal {
+
+template <typename NST>
+struct ScopedNSProtocolTraits {
+ static NST InvalidValue() { return nil; }
+ static NST Retain(NST nst) { return [nst retain]; }
+ static void Release(NST nst) { [nst release]; }
+};
+
+} // namespace internal
+
+template <typename NST>
+class scoped_nsprotocol
+ : public ScopedTypeRef<NST, internal::ScopedNSProtocolTraits<NST>> {
public:
- explicit scoped_nsprotocol(NST object = nil) : object_(object) {}
-
- scoped_nsprotocol(const scoped_nsprotocol<NST>& that)
- : object_([that.object_ retain]) {
- }
-
- template <typename NSU>
- scoped_nsprotocol(const scoped_nsprotocol<NSU>& that)
- : object_([that.get() retain]) {
- }
-
- ~scoped_nsprotocol() {
- [object_ release];
- }
-
- scoped_nsprotocol& operator=(const scoped_nsprotocol<NST>& that) {
- reset([that.get() retain]);
- return *this;
- }
-
- void reset(NST object = nil) {
- // We intentionally do not check that object != object_ as the caller must
- // either already have an ownership claim over whatever it passes to this
- // method, or call it with the |RETAIN| policy which will have ensured that
- // the object is retained once more when reaching this point.
- [object_ release];
- object_ = object;
- }
-
- bool operator==(NST that) const { return object_ == that; }
- bool operator!=(NST that) const { return object_ != that; }
-
- operator NST() const {
- return object_;
- }
-
- NST get() const {
- return object_;
- }
-
- void swap(scoped_nsprotocol& that) {
- NST temp = that.object_;
- that.object_ = object_;
- object_ = temp;
- }
-
- // scoped_nsprotocol<>::release() is like scoped_ptr<>::release. It is NOT a
- // wrapper for [object_ release]. To force a scoped_nsprotocol<> to call
- // [object_ release], use scoped_nsprotocol<>::reset().
- NST release() WARN_UNUSED_RESULT {
- NST temp = object_;
- object_ = nil;
- return temp;
- }
+ using ScopedTypeRef<NST,
+ internal::ScopedNSProtocolTraits<NST>>::ScopedTypeRef;
// Shift reference to the autorelease pool to be released later.
- NST autorelease() {
- return [release() autorelease];
- }
-
- private:
- NST object_;
+ NST autorelease() { return [this->release() autorelease]; }
};
// Free functions
@@ -120,56 +77,20 @@ bool operator!=(C p1, const scoped_nsprotocol<C>& p2) {
return p1 != p2.get();
}
-template<typename NST>
+template <typename NST>
class scoped_nsobject : public scoped_nsprotocol<NST*> {
public:
- explicit scoped_nsobject(NST* object = nil)
- : scoped_nsprotocol<NST*>(object) {}
-
- scoped_nsobject(const scoped_nsobject<NST>& that)
- : 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;
- }
+ using scoped_nsprotocol<NST*>::scoped_nsprotocol;
+
+ static_assert(std::is_same<NST, NSAutoreleasePool>::value == false,
+ "Use ScopedNSAutoreleasePool instead");
};
// Specialization to make scoped_nsobject<id> work.
template<>
class scoped_nsobject<id> : public scoped_nsprotocol<id> {
public:
- explicit scoped_nsobject(id object = nil) : scoped_nsprotocol<id>(object) {}
-
- scoped_nsobject(const scoped_nsobject<id>& that)
- : 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;
- }
-};
-
-// Do not use scoped_nsobject for NSAutoreleasePools, use
-// ScopedNSAutoreleasePool instead. This is a compile time check. See details
-// at top of header.
-template<>
-class scoped_nsobject<NSAutoreleasePool> {
- private:
- explicit scoped_nsobject(NSAutoreleasePool* object = nil);
- DISALLOW_COPY_AND_ASSIGN(scoped_nsobject);
+ using scoped_nsprotocol<id>::scoped_nsprotocol;
};
} // namespace base
diff --git a/chromium/base/mac/scoped_nsobject_unittest.mm b/chromium/base/mac/scoped_nsobject_unittest.mm
index f290c3aef09..8b0b97df3a7 100644
--- a/chromium/base/mac/scoped_nsobject_unittest.mm
+++ b/chromium/base/mac/scoped_nsobject_unittest.mm
@@ -4,7 +4,6 @@
#include <vector>
-#include "base/basictypes.h"
#include "base/mac/scoped_nsautorelease_pool.h"
#include "base/mac/scoped_nsobject.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -53,6 +52,14 @@ TEST(ScopedNSObjectTest, ScopedNSObject) {
ASSERT_EQ(2u, [p1 retainCount]);
}
+// Instantiating scoped_nsobject<> with T=NSAutoreleasePool should trip a
+// static_assert.
+#if 0
+TEST(ScopedNSObjectTest, FailToCreateScopedNSObjectAutoreleasePool) {
+ base::scoped_nsobject<NSAutoreleasePool> pool;
+}
+#endif
+
TEST(ScopedNSObjectTest, ScopedNSObjectInContainer) {
base::scoped_nsobject<id> p([[NSObject alloc] init]);
ASSERT_TRUE(p.get());
diff --git a/chromium/base/mac/scoped_sending_event.h b/chromium/base/mac/scoped_sending_event.h
index 92c2155e155..c579cefc6de 100644
--- a/chromium/base/mac/scoped_sending_event.h
+++ b/chromium/base/mac/scoped_sending_event.h
@@ -6,7 +6,7 @@
#define BASE_MAC_SCOPED_SENDING_EVENT_H_
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/message_loop/message_pump_mac.h"
// Nested event loops can pump IPC messages, including
diff --git a/chromium/base/mac/scoped_sending_event_unittest.mm b/chromium/base/mac/scoped_sending_event_unittest.mm
index 02ef2dbe292..52f18c6f5fb 100644
--- a/chromium/base/mac/scoped_sending_event_unittest.mm
+++ b/chromium/base/mac/scoped_sending_event_unittest.mm
@@ -9,7 +9,7 @@
#include "base/mac/scoped_nsobject.h"
#include "testing/gtest/include/gtest/gtest.h"
-@interface ScopedSendingEventTestCrApp : NSObject <CrAppControlProtocol> {
+@interface ScopedSendingEventTestCrApp : NSApplication <CrAppControlProtocol> {
@private
BOOL handlingSendEvent_;
}
diff --git a/chromium/base/mac/scoped_typeref.h b/chromium/base/mac/scoped_typeref.h
index 61ee3119817..42114141e12 100644
--- a/chromium/base/mac/scoped_typeref.h
+++ b/chromium/base/mac/scoped_typeref.h
@@ -5,7 +5,6 @@
#ifndef BASE_MAC_SCOPED_TYPEREF_H_
#define BASE_MAC_SCOPED_TYPEREF_H_
-#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/logging.h"
#include "base/memory/scoped_policy.h"
@@ -22,8 +21,12 @@ namespace base {
//
// template<>
// struct ScopedTypeRefTraits<CGLContextObj> {
-// void Retain(CGLContextObj object) { CGLContextRetain(object); }
-// void Release(CGLContextObj object) { CGLContextRelease(object); }
+// static CGLContextObj InvalidValue() { return nullptr; }
+// static CGLContextObj Retain(CGLContextObj object) {
+// CGLContextRetain(object);
+// return object;
+// }
+// static void Release(CGLContextObj object) { CGLContextRelease(object); }
// };
//
// For the many types that have pass-by-pointer create functions, the function
@@ -51,17 +54,17 @@ class ScopedTypeRef {
typedef T element_type;
ScopedTypeRef(
- T object = NULL,
+ T object = Traits::InvalidValue(),
base::scoped_policy::OwnershipPolicy policy = base::scoped_policy::ASSUME)
: object_(object) {
if (object_ && policy == base::scoped_policy::RETAIN)
- Traits::Retain(object_);
+ object_ = Traits::Retain(object_);
}
ScopedTypeRef(const ScopedTypeRef<T, Traits>& that)
: object_(that.object_) {
if (object_)
- Traits::Retain(object_);
+ object_ = Traits::Retain(object_);
}
~ScopedTypeRef() {
@@ -82,11 +85,11 @@ class ScopedTypeRef {
return &object_;
}
- void reset(T object = NULL,
+ void reset(T object = Traits::InvalidValue(),
base::scoped_policy::OwnershipPolicy policy =
base::scoped_policy::ASSUME) {
if (object && policy == base::scoped_policy::RETAIN)
- Traits::Retain(object);
+ object = Traits::Retain(object);
if (object_)
Traits::Release(object_);
object_ = object;
@@ -119,7 +122,7 @@ class ScopedTypeRef {
// Release(), use ScopedTypeRef<>::reset().
T release() WARN_UNUSED_RESULT {
T temp = object_;
- object_ = NULL;
+ object_ = Traits::InvalidValue();
return temp;
}
diff --git a/chromium/base/mac/sdk_forward_declarations.h b/chromium/base/mac/sdk_forward_declarations.h
index 057e951ce27..363ada1ecf7 100644
--- a/chromium/base/mac/sdk_forward_declarations.h
+++ b/chromium/base/mac/sdk_forward_declarations.h
@@ -15,6 +15,7 @@
#import <CoreWLAN/CoreWLAN.h>
#import <ImageCaptureCore/ImageCaptureCore.h>
#import <IOBluetooth/IOBluetooth.h>
+#include <stdint.h>
#include "base/base_export.h"
@@ -224,6 +225,26 @@ enum { NSWorkspaceLaunchWithErrorPresentation = 0x00000040 };
#endif // MAC_OS_X_VERSION_10_9
+#if !defined(MAC_OS_X_VERSION_10_11) || \
+ MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_11
+
+enum {
+ NSPressureBehaviorUnknown = -1,
+ NSPressureBehaviorPrimaryDefault = 0,
+ NSPressureBehaviorPrimaryClick = 1,
+ NSPressureBehaviorPrimaryGeneric = 2,
+ NSPressureBehaviorPrimaryAccelerator = 3,
+ NSPressureBehaviorPrimaryDeepClick = 5,
+ NSPressureBehaviorPrimaryDeepDrag = 6
+};
+typedef NSInteger NSPressureBehavior;
+
+@interface NSPressureConfiguration : NSObject
+- (instancetype)initWithPressureBehavior:(NSPressureBehavior)pressureBehavior;
+@end
+
+#endif // MAC_OS_X_VERSION_10_11
+
// ----------------------------------------------------------------------------
// Define NSStrings only available in newer versions of the OSX SDK to force
// them to be statically linked.
@@ -271,6 +292,7 @@ BASE_EXPORT extern NSString* const NSAppearanceNameVibrantDark;
MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7
@interface NSEvent (LionSDK)
+@property(readonly) NSInteger stage;
+ (BOOL)isSwipeTrackingFromScrollEventsEnabled;
- (NSEventPhase)momentumPhase;
- (NSEventPhase)phase;
@@ -308,6 +330,7 @@ BASE_EXPORT extern NSString* const NSAppearanceNameVibrantDark;
- (void)toggleFullScreen:(id)sender;
- (void)setRestorable:(BOOL)flag;
- (NSRect)convertRectFromScreen:(NSRect)aRect;
+- (NSSize)convertRectToScreen:(NSRect)aRect;
@end
@interface NSCursor (LionSDKDeclarations)
@@ -392,6 +415,11 @@ BASE_EXPORT extern NSString* const NSAppearanceNameVibrantDark;
+ (CBUUID*)UUIDWithString:(NSString*)theString;
@end
+BASE_EXPORT extern "C" void NSAccessibilityPostNotificationWithUserInfo(
+ id object,
+ NSString* notification,
+ NSDictionary* user_info);
+
#endif // MAC_OS_X_VERSION_10_7
// Once Chrome no longer supports OSX 10.7, everything within this preprocessor
@@ -495,22 +523,12 @@ BASE_EXPORT extern NSString* const NSAppearanceNameVibrantDark;
- (void)viewDidLoad;
@end
-enum {
- NSPressureBehaviorUnknown = -1,
- NSPressureBehaviorPrimaryDefault = 0,
- NSPressureBehaviorPrimaryClick = 1,
- NSPressureBehaviorPrimaryGeneric = 2,
- NSPressureBehaviorPrimaryAccelerator = 3,
- NSPressureBehaviorPrimaryDeepClick = 5,
- NSPressureBehaviorPrimaryDeepDrag = 6
-};
-typedef NSInteger NSPressureBehavior;
-
-@interface NSPressureConfiguration : NSObject
-- (instancetype)initWithPressureBehavior:(NSPressureBehavior)pressureBehavior;
-@end
+#endif // MAC_OS_X_VERSION_10_10
-@class NSPressureConfiguration;
+// Once Chrome no longer supports OSX 10.10.2, everything within this
+// preprocessor block can be removed.
+#if !defined(MAC_OS_X_VERSION_10_10_3) || \
+ MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10_3
@interface NSView (YosemiteSDK)
- (void)setPressureConfiguration:(NSPressureConfiguration*)aConfiguration;
diff --git a/chromium/base/macros.h b/chromium/base/macros.h
index c5f503fbc3a..46ee1dadb47 100644
--- a/chromium/base/macros.h
+++ b/chromium/base/macros.h
@@ -11,7 +11,6 @@
#define BASE_MACROS_H_
#include <stddef.h> // For size_t.
-#include <string.h> // For memcpy.
// Put this in the declarations for a class to be uncopyable.
#define DISALLOW_COPY(TypeName) \
@@ -27,13 +26,6 @@
TypeName(const TypeName&); \
void operator=(const TypeName&)
-// An older, deprecated, politically incorrect name for the above.
-// NOTE: The usage of this macro was banned from our code base, but some
-// third_party libraries are yet using it.
-// TODO(tfarina): Figure out how to fix the usage of this macro in the
-// third_party libraries and get rid of it.
-#define DISALLOW_EVIL_CONSTRUCTORS(TypeName) DISALLOW_COPY_AND_ASSIGN(TypeName)
-
// A macro to disallow all the implicit constructors, namely the
// default constructor, copy constructor and operator= functions.
//
@@ -44,10 +36,11 @@
TypeName() = delete; \
DISALLOW_COPY_AND_ASSIGN(TypeName)
-// The arraysize(arr) macro returns the # of elements in an array arr.
-// The expression is a compile-time constant, and therefore can be
-// used in defining new arrays, for example. If you use arraysize on
-// a pointer by mistake, you will get a compile-time error.
+// The arraysize(arr) macro returns the # of elements in an array arr. The
+// expression is a compile-time constant, and therefore can be used in defining
+// new arrays, for example. If you use arraysize on a pointer by mistake, you
+// will get a compile-time error. For the technical details, refer to
+// http://blogs.msdn.com/b/the1/archive/2004/05/07/128242.aspx.
// This template function declaration is used in defining arraysize.
// Note that the function doesn't need an implementation, as we only
@@ -55,87 +48,6 @@
template <typename T, size_t N> char (&ArraySizeHelper(T (&array)[N]))[N];
#define arraysize(array) (sizeof(ArraySizeHelper(array)))
-// The COMPILE_ASSERT macro can be used to verify that a compile time
-// expression is true. For example, you could use it to verify the
-// size of a static array:
-//
-// COMPILE_ASSERT(arraysize(content_type_names) == CONTENT_NUM_TYPES,
-// content_type_names_incorrect_size);
-//
-// or to make sure a struct is smaller than a certain size:
-//
-// COMPILE_ASSERT(sizeof(foo) < 128, foo_too_large);
-//
-// The second argument to the macro is the name of the variable. If
-// the expression is false, most compilers will issue a warning/error
-// containing the name of the variable.
-
-#undef COMPILE_ASSERT
-#define COMPILE_ASSERT(expr, msg) static_assert(expr, #msg)
-
-// bit_cast<Dest,Source> is a template function that implements the
-// equivalent of "*reinterpret_cast<Dest*>(&source)". We need this in
-// very low-level functions like the protobuf library and fast math
-// support.
-//
-// float f = 3.14159265358979;
-// int i = bit_cast<int32>(f);
-// // i = 0x40490fdb
-//
-// The classical address-casting method is:
-//
-// // WRONG
-// float f = 3.14159265358979; // WRONG
-// int i = * reinterpret_cast<int*>(&f); // WRONG
-//
-// The address-casting method actually produces undefined behavior
-// according to ISO C++ specification section 3.10 -15 -. Roughly, this
-// section says: if an object in memory has one type, and a program
-// accesses it with a different type, then the result is undefined
-// behavior for most values of "different type".
-//
-// This is true for any cast syntax, either *(int*)&f or
-// *reinterpret_cast<int*>(&f). And it is particularly true for
-// conversions between integral lvalues and floating-point lvalues.
-//
-// The purpose of 3.10 -15- is to allow optimizing compilers to assume
-// that expressions with different types refer to different memory. gcc
-// 4.0.1 has an optimizer that takes advantage of this. So a
-// non-conforming program quietly produces wildly incorrect output.
-//
-// The problem is not the use of reinterpret_cast. The problem is type
-// punning: holding an object in memory of one type and reading its bits
-// back using a different type.
-//
-// The C++ standard is more subtle and complex than this, but that
-// is the basic idea.
-//
-// Anyways ...
-//
-// bit_cast<> calls memcpy() which is blessed by the standard,
-// especially by the example in section 3.9 . Also, of course,
-// bit_cast<> wraps up the nasty logic in one place.
-//
-// Fortunately memcpy() is very fast. In optimized mode, with a
-// constant size, gcc 2.95.3, gcc 4.0.1, and msvc 7.1 produce inline
-// code with the minimal amount of data movement. On a 32-bit system,
-// memcpy(d,s,4) compiles to one load and one store, and memcpy(d,s,8)
-// compiles to two loads and two stores.
-//
-// I tested this code with gcc 2.95.3, gcc 4.0.1, icc 8.1, and msvc 7.1.
-//
-// WARNING: if Dest or Source is a non-POD type, the result of the memcpy
-// is likely to surprise you.
-
-template <class Dest, class Source>
-inline Dest bit_cast(const Source& source) {
- COMPILE_ASSERT(sizeof(Dest) == sizeof(Source), VerifySizesAreEqual);
-
- Dest dest;
- memcpy(&dest, &source, sizeof(dest));
- return dest;
-}
-
// Used to explicitly mark the return value of a function as unused. If you are
// really sure you don't want to do anything with the return value of a function
// that has been marked WARN_UNUSED_RESULT, wrap it with this. Example:
diff --git a/chromium/base/md5.h b/chromium/base/md5.h
index 0b4cbcef3a8..ef64178994c 100644
--- a/chromium/base/md5.h
+++ b/chromium/base/md5.h
@@ -5,6 +5,7 @@
#ifndef BASE_MD5_H_
#define BASE_MD5_H_
+#include <stddef.h>
#include <stdint.h>
#include "base/base_export.h"
diff --git a/chromium/base/md5_unittest.cc b/chromium/base/md5_unittest.cc
index 08c99f19049..3926b66ae30 100644
--- a/chromium/base/md5_unittest.cc
+++ b/chromium/base/md5_unittest.cc
@@ -5,7 +5,6 @@
#include <string.h>
#include <string>
-#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "base/md5.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/base/memory/BUILD.gn b/chromium/base/memory/BUILD.gn
deleted file mode 100644
index 20704472ca9..00000000000
--- a/chromium/base/memory/BUILD.gn
+++ /dev/null
@@ -1,84 +0,0 @@
-# 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",
- "memory_pressure_monitor_chromeos.cc",
- "memory_pressure_monitor_chromeos.h",
- "memory_pressure_monitor_mac.cc",
- "memory_pressure_monitor_mac.h",
- "memory_pressure_monitor_win.cc",
- "memory_pressure_monitor_win.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_handle.h",
- "shared_memory_handle_mac.cc",
- "shared_memory_handle_win.cc",
- "shared_memory_mac.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_ios) {
- sources -= [
- "discardable_shared_memory.cc",
- "discardable_shared_memory.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" ]
- }
-
- if (is_mac) {
- sources -= [ "shared_memory_posix.cc" ]
- }
-
- if (is_android) {
- deps = [
- "//third_party/ashmem",
- ]
- }
-
- configs += [ "//base:base_implementation" ]
-
- visibility = [ "//base/*" ]
-}
diff --git a/chromium/base/memory/aligned_memory.cc b/chromium/base/memory/aligned_memory.cc
index 5ec88b16b81..526a49587a4 100644
--- a/chromium/base/memory/aligned_memory.cc
+++ b/chromium/base/memory/aligned_memory.cc
@@ -5,6 +5,7 @@
#include "base/memory/aligned_memory.h"
#include "base/logging.h"
+#include "build/build_config.h"
#if defined(OS_ANDROID)
#include <malloc.h>
diff --git a/chromium/base/memory/aligned_memory.h b/chromium/base/memory/aligned_memory.h
index 1a4cba9ad84..bb7bd872cfb 100644
--- a/chromium/base/memory/aligned_memory.h
+++ b/chromium/base/memory/aligned_memory.h
@@ -34,8 +34,10 @@
#ifndef BASE_MEMORY_ALIGNED_MEMORY_H_
#define BASE_MEMORY_ALIGNED_MEMORY_H_
+#include <stddef.h>
+#include <stdint.h>
+
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/compiler_specific.h"
#if defined(COMPILER_MSVC)
@@ -51,25 +53,26 @@ namespace base {
template <size_t Size, size_t ByteAlignment>
struct AlignedMemory {};
-#define BASE_DECL_ALIGNED_MEMORY(byte_alignment) \
- template <size_t Size> \
- class AlignedMemory<Size, byte_alignment> { \
- public: \
- ALIGNAS(byte_alignment) uint8 data_[Size]; \
- void* void_data() { return static_cast<void*>(data_); } \
- const void* void_data() const { \
- return static_cast<const void*>(data_); \
- } \
- template<typename Type> \
- Type* data_as() { return static_cast<Type*>(void_data()); } \
- template<typename Type> \
- const Type* data_as() const { \
- return static_cast<const Type*>(void_data()); \
- } \
- private: \
- void* operator new(size_t); \
- void operator delete(void*); \
- }
+#define BASE_DECL_ALIGNED_MEMORY(byte_alignment) \
+ template <size_t Size> \
+ class AlignedMemory<Size, byte_alignment> { \
+ public: \
+ ALIGNAS(byte_alignment) uint8_t data_[Size]; \
+ void* void_data() { return static_cast<void*>(data_); } \
+ const void* void_data() const { return static_cast<const void*>(data_); } \
+ template <typename Type> \
+ Type* data_as() { \
+ return static_cast<Type*>(void_data()); \
+ } \
+ template <typename Type> \
+ const Type* data_as() const { \
+ return static_cast<const Type*>(void_data()); \
+ } \
+ \
+ private: \
+ void* operator new(size_t); \
+ void operator delete(void*); \
+ }
// Specialization for all alignments is required because MSVC (as of VS 2008)
// does not understand ALIGNAS(ALIGNOF(Type)) or ALIGNAS(template_param).
diff --git a/chromium/base/memory/aligned_memory_unittest.cc b/chromium/base/memory/aligned_memory_unittest.cc
index 5d681f9a388..b89e341faa7 100644
--- a/chromium/base/memory/aligned_memory_unittest.cc
+++ b/chromium/base/memory/aligned_memory_unittest.cc
@@ -4,6 +4,7 @@
#include "base/memory/aligned_memory.h"
#include "base/memory/scoped_ptr.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#define EXPECT_ALIGNED(ptr, align) \
diff --git a/chromium/base/memory/discardable_memory.h b/chromium/base/memory/discardable_memory.h
index c64fc4f7cf3..5c632d1c95e 100644
--- a/chromium/base/memory/discardable_memory.h
+++ b/chromium/base/memory/discardable_memory.h
@@ -6,7 +6,6 @@
#define BASE_MEMORY_DISCARDABLE_MEMORY_H_
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/compiler_specific.h"
namespace base {
diff --git a/chromium/base/memory/discardable_memory_allocator.h b/chromium/base/memory/discardable_memory_allocator.h
index 400f87aeee0..ea7947e1ccf 100644
--- a/chromium/base/memory/discardable_memory_allocator.h
+++ b/chromium/base/memory/discardable_memory_allocator.h
@@ -5,6 +5,8 @@
#ifndef BASE_MEMORY_DISCARDABLE_MEMORY_ALLOCATOR_H_
#define BASE_MEMORY_DISCARDABLE_MEMORY_ALLOCATOR_H_
+#include <stddef.h>
+
#include "base/base_export.h"
#include "base/memory/scoped_ptr.h"
diff --git a/chromium/base/memory/discardable_shared_memory.cc b/chromium/base/memory/discardable_shared_memory.cc
index d0eaca1a662..860fed6dd16 100644
--- a/chromium/base/memory/discardable_shared_memory.cc
+++ b/chromium/base/memory/discardable_shared_memory.cc
@@ -4,9 +4,7 @@
#include "base/memory/discardable_shared_memory.h"
-#if defined(OS_POSIX)
-#include <unistd.h>
-#endif
+#include <stdint.h>
#include <algorithm>
@@ -15,11 +13,21 @@
#include "base/logging.h"
#include "base/numerics/safe_math.h"
#include "base/process/process_metrics.h"
+#include "build/build_config.h"
+
+#if defined(OS_POSIX) && !defined(OS_NACL)
+// For madvise() which is available on all POSIX compatible systems.
+#include <sys/mman.h>
+#endif
#if defined(OS_ANDROID)
#include "third_party/ashmem/ashmem.h"
#endif
+#if defined(OS_WIN)
+#include "base/win/windows_version.h"
+#endif
+
namespace base {
namespace {
@@ -33,28 +41,28 @@ typedef uintptr_t UAtomicType;
// does not have enough precision to contain a timestamp in the standard
// serialized format.
template <int>
-Time TimeFromWireFormat(int64 value);
+Time TimeFromWireFormat(int64_t value);
template <int>
-int64 TimeToWireFormat(Time time);
+int64_t TimeToWireFormat(Time time);
// Serialize to Unix time when using 4-byte wire format.
// Note: 19 January 2038, this will cease to work.
template <>
-Time ALLOW_UNUSED_TYPE TimeFromWireFormat<4>(int64 value) {
+Time ALLOW_UNUSED_TYPE TimeFromWireFormat<4>(int64_t value) {
return value ? Time::UnixEpoch() + TimeDelta::FromSeconds(value) : Time();
}
template <>
-int64 ALLOW_UNUSED_TYPE TimeToWireFormat<4>(Time time) {
+int64_t ALLOW_UNUSED_TYPE TimeToWireFormat<4>(Time time) {
return time > Time::UnixEpoch() ? (time - Time::UnixEpoch()).InSeconds() : 0;
}
// Standard serialization format when using 8-byte wire format.
template <>
-Time ALLOW_UNUSED_TYPE TimeFromWireFormat<8>(int64 value) {
+Time ALLOW_UNUSED_TYPE TimeFromWireFormat<8>(int64_t value) {
return Time::FromInternalValue(value);
}
template <>
-int64 ALLOW_UNUSED_TYPE TimeToWireFormat<8>(Time time) {
+int64_t ALLOW_UNUSED_TYPE TimeToWireFormat<8>(Time time) {
return time.ToInternalValue();
}
@@ -63,7 +71,7 @@ struct SharedState {
explicit SharedState(AtomicType ivalue) { value.i = ivalue; }
SharedState(LockState lock_state, Time timestamp) {
- int64 wire_timestamp = TimeToWireFormat<sizeof(AtomicType)>(timestamp);
+ int64_t wire_timestamp = TimeToWireFormat<sizeof(AtomicType)>(timestamp);
DCHECK_GE(wire_timestamp, 0);
DCHECK_EQ(lock_state & ~1, 0);
value.u = (static_cast<UAtomicType>(wire_timestamp) << 1) | lock_state;
@@ -213,6 +221,7 @@ DiscardableSharedMemory::LockResult DiscardableSharedMemory::Lock(
DCHECK_EQ(locked_pages_.size(), locked_page_count_);
#endif
+// Pin pages if supported.
#if defined(OS_ANDROID)
SharedMemoryHandle handle = shared_memory_.handle();
if (SharedMemory::IsHandleValid(handle)) {
@@ -221,6 +230,14 @@ DiscardableSharedMemory::LockResult DiscardableSharedMemory::Lock(
return PURGED;
}
}
+#elif defined(OS_WIN)
+ if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
+ if (!VirtualAlloc(reinterpret_cast<char*>(shared_memory_.memory()) +
+ AlignToPageSize(sizeof(SharedState)) + offset,
+ length, MEM_RESET_UNDO, PAGE_READWRITE)) {
+ return PURGED;
+ }
+ }
#endif
return SUCCESS;
@@ -239,6 +256,7 @@ void DiscardableSharedMemory::Unlock(size_t offset, size_t length) {
DCHECK(shared_memory_.memory());
+// Unpin pages if supported.
#if defined(OS_ANDROID)
SharedMemoryHandle handle = shared_memory_.handle();
if (SharedMemory::IsHandleValid(handle)) {
@@ -247,6 +265,18 @@ void DiscardableSharedMemory::Unlock(size_t offset, size_t length) {
DPLOG(ERROR) << "ashmem_unpin_region() failed";
}
}
+#elif defined(OS_WIN)
+ if (base::win::GetVersion() >= base::win::VERSION_WIN8) {
+ // Note: MEM_RESET is not technically gated on Win8. However, this Unlock
+ // function needs to match the Lock behaviour (MEM_RESET_UNDO) to properly
+ // implement memory pinning. It needs to bias towards preserving the
+ // contents of memory between an Unlock and next Lock.
+ if (!VirtualAlloc(reinterpret_cast<char*>(shared_memory_.memory()) +
+ AlignToPageSize(sizeof(SharedState)) + offset,
+ length, MEM_RESET, PAGE_READWRITE)) {
+ DPLOG(ERROR) << "VirtualAlloc() MEM_RESET failed in Unlock()";
+ }
+ }
#endif
size_t start = offset / base::GetPageSize();
@@ -294,18 +324,14 @@ void DiscardableSharedMemory::Unlock(size_t offset, size_t length) {
}
void* DiscardableSharedMemory::memory() const {
- return reinterpret_cast<uint8*>(shared_memory_.memory()) +
+ return reinterpret_cast<uint8_t*>(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())
- return true;
+ DCHECK(shared_memory_.memory());
SharedState old_state(SharedState::UNLOCKED, last_known_usage_);
SharedState new_state(SharedState::UNLOCKED, Time());
@@ -326,6 +352,39 @@ bool DiscardableSharedMemory::Purge(Time current_time) {
return false;
}
+// The next section will release as much resource as can be done
+// from the purging process, until the client process notices the
+// purge and releases its own references.
+// Note: this memory will not be accessed again. The segment will be
+// freed asynchronously at a later time, so just do the best
+// immediately.
+#if defined(OS_POSIX) && !defined(OS_NACL)
+// Linux and Android provide MADV_REMOVE which is preferred as it has a
+// behavior that can be verified in tests. Other POSIX flavors (MacOSX, BSDs),
+// provide MADV_FREE which has the same result but memory is purged lazily.
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+#define MADV_PURGE_ARGUMENT MADV_REMOVE
+#else
+#define MADV_PURGE_ARGUMENT MADV_FREE
+#endif
+ // Advise the kernel to remove resources associated with purged pages.
+ // Subsequent accesses of memory pages will succeed, but might result in
+ // zero-fill-on-demand pages.
+ if (madvise(reinterpret_cast<char*>(shared_memory_.memory()) +
+ AlignToPageSize(sizeof(SharedState)),
+ AlignToPageSize(mapped_size_), MADV_PURGE_ARGUMENT)) {
+ DPLOG(ERROR) << "madvise() failed";
+ }
+#elif defined(OS_WIN)
+ // MEM_DECOMMIT the purged pages to release the physical storage,
+ // either in memory or in the paging file on disk. Pages remain RESERVED.
+ if (!VirtualFree(reinterpret_cast<char*>(shared_memory_.memory()) +
+ AlignToPageSize(sizeof(SharedState)),
+ AlignToPageSize(mapped_size_), MEM_DECOMMIT)) {
+ DPLOG(ERROR) << "VirtualFree() MEM_DECOMMIT failed in Purge()";
+ }
+#endif
+
last_known_usage_ = Time();
return true;
}
@@ -353,26 +412,6 @@ 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(SharedMemory::GetFdFromSharedMemoryHandle(handle),
- 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 5dca884ca82..b391ef1541b 100644
--- a/chromium/base/memory/discardable_shared_memory.h
+++ b/chromium/base/memory/discardable_shared_memory.h
@@ -5,20 +5,29 @@
#ifndef BASE_MEMORY_DISCARDABLE_SHARED_MEMORY_H_
#define BASE_MEMORY_DISCARDABLE_SHARED_MEMORY_H_
+#include <stddef.h>
+
#include "base/base_export.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/shared_memory.h"
#include "base/threading/thread_collision_warner.h"
#include "base/time/time.h"
+#include "build/build_config.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
+// Linux (including Android) support the MADV_REMOVE argument with madvise()
+// which has the behavior of reliably causing zero-fill-on-demand pages to
+// be returned after a call. Here we define
+// DISCARDABLE_SHARED_MEMORY_ZERO_FILL_ON_DEMAND_PAGES_AFTER_PURGE on Linux
+// and Android to indicate that this type of behavior can be expected on
+// those platforms. Note that madvise() will still be used on other POSIX
+// platforms but doesn't provide the zero-fill-on-demand pages guarantee.
+#if defined(OS_LINUX) || defined(OS_ANDROID)
+#define DISCARDABLE_SHARED_MEMORY_ZERO_FILL_ON_DEMAND_PAGES_AFTER_PURGE
#endif
namespace base {
@@ -124,12 +133,6 @@ 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;
diff --git a/chromium/base/memory/discardable_shared_memory_unittest.cc b/chromium/base/memory/discardable_shared_memory_unittest.cc
index d5b71d31cb0..3348ed1a884 100644
--- a/chromium/base/memory/discardable_shared_memory_unittest.cc
+++ b/chromium/base/memory/discardable_shared_memory_unittest.cc
@@ -2,7 +2,8 @@
// 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 <stdint.h>
+
#include "base/memory/discardable_shared_memory.h"
#include "base/process/process_metrics.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -27,7 +28,7 @@ class TestDiscardableSharedMemory : public DiscardableSharedMemory {
};
TEST(DiscardableSharedMemoryTest, CreateAndMap) {
- const uint32 kDataSize = 1024;
+ const uint32_t kDataSize = 1024;
TestDiscardableSharedMemory memory;
bool rv = memory.CreateAndMap(kDataSize);
@@ -37,7 +38,7 @@ TEST(DiscardableSharedMemoryTest, CreateAndMap) {
}
TEST(DiscardableSharedMemoryTest, CreateFromHandle) {
- const uint32 kDataSize = 1024;
+ const uint32_t kDataSize = 1024;
TestDiscardableSharedMemory memory1;
bool rv = memory1.CreateAndMap(kDataSize);
@@ -55,7 +56,7 @@ TEST(DiscardableSharedMemoryTest, CreateFromHandle) {
}
TEST(DiscardableSharedMemoryTest, LockAndUnlock) {
- const uint32 kDataSize = 1024;
+ const uint32_t kDataSize = 1024;
TestDiscardableSharedMemory memory1;
bool rv = memory1.CreateAndMap(kDataSize);
@@ -109,7 +110,7 @@ TEST(DiscardableSharedMemoryTest, LockAndUnlock) {
}
TEST(DiscardableSharedMemoryTest, Purge) {
- const uint32 kDataSize = 1024;
+ const uint32_t kDataSize = 1024;
TestDiscardableSharedMemory memory1;
bool rv = memory1.CreateAndMap(kDataSize);
@@ -151,7 +152,7 @@ TEST(DiscardableSharedMemoryTest, Purge) {
}
TEST(DiscardableSharedMemoryTest, LastUsed) {
- const uint32 kDataSize = 1024;
+ const uint32_t kDataSize = 1024;
TestDiscardableSharedMemory memory1;
bool rv = memory1.CreateAndMap(kDataSize);
@@ -219,7 +220,7 @@ TEST(DiscardableSharedMemoryTest, LastUsed) {
}
TEST(DiscardableSharedMemoryTest, LockShouldAlwaysFailAfterSuccessfulPurge) {
- const uint32 kDataSize = 1024;
+ const uint32_t kDataSize = 1024;
TestDiscardableSharedMemory memory1;
bool rv = memory1.CreateAndMap(kDataSize);
@@ -246,9 +247,9 @@ TEST(DiscardableSharedMemoryTest, LockShouldAlwaysFailAfterSuccessfulPurge) {
}
TEST(DiscardableSharedMemoryTest, LockAndUnlockRange) {
- const uint32 kDataSize = 32;
+ const uint32_t kDataSize = 32;
- uint32 data_size_in_bytes = kDataSize * base::GetPageSize();
+ uint32_t data_size_in_bytes = kDataSize * base::GetPageSize();
TestDiscardableSharedMemory memory1;
bool rv = memory1.CreateAndMap(data_size_in_bytes);
@@ -307,7 +308,7 @@ TEST(DiscardableSharedMemoryTest, LockAndUnlockRange) {
}
TEST(DiscardableSharedMemoryTest, MappedSize) {
- const uint32 kDataSize = 1024;
+ const uint32_t kDataSize = 1024;
TestDiscardableSharedMemory memory;
bool rv = memory.CreateAndMap(kDataSize);
@@ -322,7 +323,7 @@ TEST(DiscardableSharedMemoryTest, MappedSize) {
}
TEST(DiscardableSharedMemoryTest, Close) {
- const uint32 kDataSize = 1024;
+ const uint32_t kDataSize = 1024;
TestDiscardableSharedMemory memory;
bool rv = memory.CreateAndMap(kDataSize);
@@ -343,19 +344,44 @@ TEST(DiscardableSharedMemoryTest, Close) {
memory.Unlock(0, 0);
}
-#if defined(DISCARDABLE_SHARED_MEMORY_SHRINKING)
-TEST(DiscardableSharedMemoryTest, Shrink) {
- const uint32 kDataSize = 1024;
+// This test checks that zero-filled pages are returned after purging a segment
+// when DISCARDABLE_SHARED_MEMORY_ZERO_FILL_ON_DEMAND_PAGES_AFTER_PURGE is
+// defined and MADV_REMOVE is supported.
+#if defined(DISCARDABLE_SHARED_MEMORY_ZERO_FILL_ON_DEMAND_PAGES_AFTER_PURGE)
+TEST(DiscardableSharedMemoryTest, ZeroFilledPagesAfterPurge) {
+ const uint32_t kDataSize = 1024;
- TestDiscardableSharedMemory memory;
- bool rv = memory.CreateAndMap(kDataSize);
+ TestDiscardableSharedMemory memory1;
+ bool rv = memory1.CreateAndMap(kDataSize);
ASSERT_TRUE(rv);
- EXPECT_NE(0u, memory.mapped_size());
+ SharedMemoryHandle shared_handle;
+ ASSERT_TRUE(
+ memory1.ShareToProcess(GetCurrentProcessHandle(), &shared_handle));
+ ASSERT_TRUE(SharedMemory::IsHandleValid(shared_handle));
- // Mapped size should be 0 after shrinking memory segment.
- memory.Shrink();
- EXPECT_EQ(0u, memory.mapped_size());
+ TestDiscardableSharedMemory memory2(shared_handle);
+ rv = memory2.Map(kDataSize);
+ ASSERT_TRUE(rv);
+
+ // Initialize all memory to '0xaa'.
+ memset(memory2.memory(), 0xaa, kDataSize);
+
+ // Unlock memory.
+ memory2.SetNow(Time::FromDoubleT(1));
+ memory2.Unlock(0, 0);
+ EXPECT_FALSE(memory1.IsMemoryLocked());
+
+ // Memory is unlocked, but our usage timestamp is incorrect.
+ rv = memory1.Purge(Time::FromDoubleT(2));
+ EXPECT_FALSE(rv);
+ rv = memory1.Purge(Time::FromDoubleT(3));
+ EXPECT_TRUE(rv);
+
+ // Check that reading memory after it has been purged is returning
+ // zero-filled pages.
+ uint8_t expected_data[kDataSize] = {};
+ EXPECT_EQ(memcmp(memory2.memory(), expected_data, kDataSize), 0);
}
#endif
diff --git a/chromium/base/memory/linked_ptr.h b/chromium/base/memory/linked_ptr.h
index 80044add81c..649dc10db7b 100644
--- a/chromium/base/memory/linked_ptr.h
+++ b/chromium/base/memory/linked_ptr.h
@@ -17,10 +17,6 @@
// If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS
// will happen (double deletion).
//
-// A good use of this class is storing object references in STL containers.
-// You can safely put linked_ptr<> in a vector<>.
-// Other uses may not be as good.
-//
// Note: If you use an incomplete type with linked_ptr<>, the class
// *containing* linked_ptr<> must have a constructor and destructor (even
// if they do nothing!).
@@ -73,6 +69,8 @@ class linked_ptr_internal {
mutable linked_ptr_internal const* next_;
};
+// TODO(http://crbug.com/556939): DEPRECATED: Use scoped_ptr instead (now that
+// we have support for moveable types inside STL containers).
template <typename T>
class linked_ptr {
public:
diff --git a/chromium/base/memory/memory_pressure_listener.h b/chromium/base/memory/memory_pressure_listener.h
index 290657e7260..a6ce702ccb0 100644
--- a/chromium/base/memory/memory_pressure_listener.h
+++ b/chromium/base/memory/memory_pressure_listener.h
@@ -11,8 +11,8 @@
#define BASE_MEMORY_MEMORY_PRESSURE_LISTENER_H_
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/callback.h"
+#include "base/macros.h"
namespace base {
diff --git a/chromium/base/memory/memory_pressure_monitor.h b/chromium/base/memory/memory_pressure_monitor.h
index 90c94209653..6073bd3f44c 100644
--- a/chromium/base/memory/memory_pressure_monitor.h
+++ b/chromium/base/memory/memory_pressure_monitor.h
@@ -6,6 +6,7 @@
#define BASE_MEMORY_MEMORY_PRESSURE_MONITOR_H_
#include "base/base_export.h"
+#include "base/macros.h"
#include "base/memory/memory_pressure_listener.h"
namespace base {
diff --git a/chromium/base/memory/memory_pressure_monitor_chromeos_unittest.cc b/chromium/base/memory/memory_pressure_monitor_chromeos_unittest.cc
index e0afa448a41..a82cef4b604 100644
--- a/chromium/base/memory/memory_pressure_monitor_chromeos_unittest.cc
+++ b/chromium/base/memory/memory_pressure_monitor_chromeos_unittest.cc
@@ -4,7 +4,7 @@
#include "base/memory/memory_pressure_monitor_chromeos.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/memory/memory_pressure_listener.h"
#include "base/message_loop/message_loop.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/base/memory/memory_pressure_monitor_mac.cc b/chromium/base/memory/memory_pressure_monitor_mac.cc
index f394935acb9..a80631eb7f8 100644
--- a/chromium/base/memory/memory_pressure_monitor_mac.cc
+++ b/chromium/base/memory/memory_pressure_monitor_mac.cc
@@ -5,6 +5,7 @@
#include "base/memory/memory_pressure_monitor_mac.h"
#include <dlfcn.h>
+#include <stddef.h>
#include <sys/sysctl.h>
#include "base/mac/mac_util.h"
diff --git a/chromium/base/memory/memory_pressure_monitor_mac.h b/chromium/base/memory/memory_pressure_monitor_mac.h
index 8d4c26a55f0..7604656b7fe 100644
--- a/chromium/base/memory/memory_pressure_monitor_mac.h
+++ b/chromium/base/memory/memory_pressure_monitor_mac.h
@@ -8,6 +8,7 @@
#include <dispatch/dispatch.h>
#include "base/base_export.h"
+#include "base/macros.h"
#include "base/memory/memory_pressure_listener.h"
#include "base/memory/memory_pressure_monitor.h"
diff --git a/chromium/base/memory/memory_pressure_monitor_mac_unittest.cc b/chromium/base/memory/memory_pressure_monitor_mac_unittest.cc
index e037a9dcdd6..b7c29cd13cb 100644
--- a/chromium/base/memory/memory_pressure_monitor_mac_unittest.cc
+++ b/chromium/base/memory/memory_pressure_monitor_mac_unittest.cc
@@ -4,6 +4,7 @@
#include "base/memory/memory_pressure_monitor_mac.h"
+#include "base/macros.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
diff --git a/chromium/base/memory/memory_pressure_monitor_win.h b/chromium/base/memory/memory_pressure_monitor_win.h
index 030b8b33e28..5689ac6ac74 100644
--- a/chromium/base/memory/memory_pressure_monitor_win.h
+++ b/chromium/base/memory/memory_pressure_monitor_win.h
@@ -6,6 +6,7 @@
#define BASE_MEMORY_MEMORY_PRESSURE_MONITOR_WIN_H_
#include "base/base_export.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"
diff --git a/chromium/base/memory/memory_pressure_monitor_win_unittest.cc b/chromium/base/memory/memory_pressure_monitor_win_unittest.cc
index d9a9575aecc..0461e7dcdea 100644
--- a/chromium/base/memory/memory_pressure_monitor_win_unittest.cc
+++ b/chromium/base/memory/memory_pressure_monitor_win_unittest.cc
@@ -4,7 +4,7 @@
#include "base/memory/memory_pressure_monitor_win.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/memory/memory_pressure_listener.h"
#include "base/message_loop/message_loop.h"
#include "testing/gmock/include/gmock/gmock.h"
diff --git a/chromium/base/memory/ptr_util.h b/chromium/base/memory/ptr_util.h
new file mode 100644
index 00000000000..04f2c025892
--- /dev/null
+++ b/chromium/base/memory/ptr_util.h
@@ -0,0 +1,22 @@
+// 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_PTR_UTIL_H_
+#define BASE_MEMORY_PTR_UTIL_H_
+
+#include <memory>
+
+namespace base {
+
+// Helper to transfer ownership of a raw pointer to a std::unique_ptr<T>.
+// Note that std::unique_ptr<T> has very different semantics from
+// std::unique_ptr<T[]>: do not use this helper for array allocations.
+template <typename T>
+std::unique_ptr<T> WrapUnique(T* ptr) {
+ return std::unique_ptr<T>(ptr);
+}
+
+} // namespace base
+
+#endif // BASE_MEMORY_PTR_UTIL_H_
diff --git a/chromium/base/memory/ptr_util_unittest.cc b/chromium/base/memory/ptr_util_unittest.cc
new file mode 100644
index 00000000000..3fa40d8098d
--- /dev/null
+++ b/chromium/base/memory/ptr_util_unittest.cc
@@ -0,0 +1,40 @@
+// 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/ptr_util.h"
+
+#include <stddef.h>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+namespace {
+
+class DeleteCounter {
+ public:
+ DeleteCounter() { ++count_; }
+ ~DeleteCounter() { --count_; }
+
+ static size_t count() { return count_; }
+
+ private:
+ static size_t count_;
+};
+
+size_t DeleteCounter::count_ = 0;
+
+} // namespace
+
+TEST(PtrUtilTest, WrapUnique) {
+ EXPECT_EQ(0u, DeleteCounter::count());
+ DeleteCounter* counter = new DeleteCounter;
+ EXPECT_EQ(1u, DeleteCounter::count());
+ std::unique_ptr<DeleteCounter> owned_counter = WrapUnique(counter);
+ EXPECT_EQ(1u, DeleteCounter::count());
+ owned_counter.reset();
+ EXPECT_EQ(0u, DeleteCounter::count());
+}
+
+} // namespace base
diff --git a/chromium/base/memory/raw_scoped_refptr_mismatch_checker.h b/chromium/base/memory/raw_scoped_refptr_mismatch_checker.h
index 01905588058..09f982b1294 100644
--- a/chromium/base/memory/raw_scoped_refptr_mismatch_checker.h
+++ b/chromium/base/memory/raw_scoped_refptr_mismatch_checker.h
@@ -51,75 +51,10 @@ struct ParamsUseScopedRefptrCorrectly<Tuple<>> {
enum { value = 1 };
};
-template <typename A>
-struct ParamsUseScopedRefptrCorrectly<Tuple<A>> {
- enum { value = !NeedsScopedRefptrButGetsRawPtr<A>::value };
-};
-
-template <typename A, typename B>
-struct ParamsUseScopedRefptrCorrectly<Tuple<A, B>> {
- enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
- NeedsScopedRefptrButGetsRawPtr<B>::value) };
-};
-
-template <typename A, typename B, typename 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<Tuple<A, B, C, D>> {
- enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
- NeedsScopedRefptrButGetsRawPtr<B>::value ||
- NeedsScopedRefptrButGetsRawPtr<C>::value ||
- NeedsScopedRefptrButGetsRawPtr<D>::value) };
-};
-
-template <typename A, typename B, typename C, typename D, typename E>
-struct ParamsUseScopedRefptrCorrectly<Tuple<A, B, C, D, E>> {
- enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
- NeedsScopedRefptrButGetsRawPtr<B>::value ||
- NeedsScopedRefptrButGetsRawPtr<C>::value ||
- NeedsScopedRefptrButGetsRawPtr<D>::value ||
- NeedsScopedRefptrButGetsRawPtr<E>::value) };
-};
-
-template <typename A, typename B, typename C, typename D, typename E,
- typename F>
-struct ParamsUseScopedRefptrCorrectly<Tuple<A, B, C, D, E, F>> {
- enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
- NeedsScopedRefptrButGetsRawPtr<B>::value ||
- NeedsScopedRefptrButGetsRawPtr<C>::value ||
- NeedsScopedRefptrButGetsRawPtr<D>::value ||
- NeedsScopedRefptrButGetsRawPtr<E>::value ||
- NeedsScopedRefptrButGetsRawPtr<F>::value) };
-};
-
-template <typename A, typename B, typename C, typename D, typename E,
- typename F, typename G>
-struct ParamsUseScopedRefptrCorrectly<Tuple<A, B, C, D, E, F, G>> {
- enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
- NeedsScopedRefptrButGetsRawPtr<B>::value ||
- NeedsScopedRefptrButGetsRawPtr<C>::value ||
- NeedsScopedRefptrButGetsRawPtr<D>::value ||
- NeedsScopedRefptrButGetsRawPtr<E>::value ||
- NeedsScopedRefptrButGetsRawPtr<F>::value ||
- NeedsScopedRefptrButGetsRawPtr<G>::value) };
-};
-
-template <typename A, typename B, typename C, typename D, typename E,
- typename F, typename G, typename H>
-struct ParamsUseScopedRefptrCorrectly<Tuple<A, B, C, D, E, F, G, H>> {
- enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
- NeedsScopedRefptrButGetsRawPtr<B>::value ||
- NeedsScopedRefptrButGetsRawPtr<C>::value ||
- NeedsScopedRefptrButGetsRawPtr<D>::value ||
- NeedsScopedRefptrButGetsRawPtr<E>::value ||
- NeedsScopedRefptrButGetsRawPtr<F>::value ||
- NeedsScopedRefptrButGetsRawPtr<G>::value ||
- NeedsScopedRefptrButGetsRawPtr<H>::value) };
+template <typename Head, typename... Tail>
+struct ParamsUseScopedRefptrCorrectly<Tuple<Head, Tail...>> {
+ enum { value = !NeedsScopedRefptrButGetsRawPtr<Head>::value &&
+ ParamsUseScopedRefptrCorrectly<Tuple<Tail...>>::value };
};
} // namespace internal
diff --git a/chromium/base/memory/ref_counted.h b/chromium/base/memory/ref_counted.h
index 5f94b4c37ae..a1c12696990 100644
--- a/chromium/base/memory/ref_counted.h
+++ b/chromium/base/memory/ref_counted.h
@@ -11,10 +11,10 @@
#include "base/atomic_ref_count.h"
#include "base/base_export.h"
#include "base/compiler_specific.h"
+#include "base/macros.h"
#ifndef NDEBUG
#include "base/logging.h"
#endif
-#include "base/move.h"
#include "base/threading/thread_collision_warner.h"
#include "build/build_config.h"
@@ -118,7 +118,7 @@ class BASE_EXPORT RefCountedThreadSafeBase {
// ~MyFoo();
// };
//
-// You should always make your destructor private, to avoid any code deleting
+// You should always make your destructor non-public, to avoid any code deleting
// the object accidently while there are references to it.
template <class T>
class RefCounted : public subtle::RefCountedBase {
@@ -265,7 +265,6 @@ class RefCountedData
//
template <class T>
class scoped_refptr {
- TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(scoped_refptr)
public:
typedef T element_type;
@@ -277,17 +276,24 @@ class scoped_refptr {
AddRef(ptr_);
}
+ // Copy constructor.
scoped_refptr(const scoped_refptr<T>& r) : ptr_(r.ptr_) {
if (ptr_)
AddRef(ptr_);
}
+ // Copy conversion constructor.
template <typename U>
scoped_refptr(const scoped_refptr<U>& r) : ptr_(r.get()) {
if (ptr_)
AddRef(ptr_);
}
+ // Move constructor. This is required in addition to the conversion
+ // constructor below in order for clang to warn about pessimizing moves.
+ scoped_refptr(scoped_refptr&& r) : ptr_(r.get()) { r.ptr_ = nullptr; }
+
+ // Move conversion constructor.
template <typename U>
scoped_refptr(scoped_refptr<U>&& r) : ptr_(r.get()) {
r.ptr_ = nullptr;
@@ -331,13 +337,13 @@ class scoped_refptr {
}
scoped_refptr<T>& operator=(scoped_refptr<T>&& r) {
- scoped_refptr<T>(r.Pass()).swap(*this);
+ scoped_refptr<T>(std::move(r)).swap(*this);
return *this;
}
template <typename U>
scoped_refptr<T>& operator=(scoped_refptr<U>&& r) {
- scoped_refptr<T>(r.Pass()).swap(*this);
+ scoped_refptr<T>(std::move(r)).swap(*this);
return *this;
}
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 d278a445d51..84f80d8d8f2 100644
--- a/chromium/base/memory/ref_counted_delete_on_message_loop.h
+++ b/chromium/base/memory/ref_counted_delete_on_message_loop.h
@@ -7,6 +7,7 @@
#include "base/location.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/single_thread_task_runner.h"
diff --git a/chromium/base/memory/ref_counted_memory.cc b/chromium/base/memory/ref_counted_memory.cc
index 477c941355c..7bbd3171ca5 100644
--- a/chromium/base/memory/ref_counted_memory.cc
+++ b/chromium/base/memory/ref_counted_memory.cc
@@ -4,8 +4,6 @@
#include "base/memory/ref_counted_memory.h"
-#include <stdlib.h>
-
#include "base/logging.h"
namespace base {
@@ -64,8 +62,9 @@ RefCountedString::RefCountedString() {}
RefCountedString::~RefCountedString() {}
// static
-RefCountedString* RefCountedString::TakeString(std::string* to_destroy) {
- RefCountedString* self = new RefCountedString;
+scoped_refptr<RefCountedString> RefCountedString::TakeString(
+ std::string* to_destroy) {
+ scoped_refptr<RefCountedString> self(new RefCountedString);
to_destroy->swap(self->data_);
return self;
}
@@ -79,22 +78,4 @@ size_t RefCountedString::size() const {
return data_.size();
}
-RefCountedMallocedMemory::RefCountedMallocedMemory(
- void* data, size_t length)
- : data_(reinterpret_cast<unsigned char*>(data)), length_(length) {
- DCHECK(data || length == 0);
-}
-
-const unsigned char* RefCountedMallocedMemory::front() const {
- return length_ ? data_ : NULL;
-}
-
-size_t RefCountedMallocedMemory::size() const {
- return length_;
-}
-
-RefCountedMallocedMemory::~RefCountedMallocedMemory() {
- free(data_);
-}
-
} // namespace base
diff --git a/chromium/base/memory/ref_counted_memory.h b/chromium/base/memory/ref_counted_memory.h
index 66dc65ff425..f37a86011af 100644
--- a/chromium/base/memory/ref_counted_memory.h
+++ b/chromium/base/memory/ref_counted_memory.h
@@ -5,11 +5,14 @@
#ifndef BASE_MEMORY_REF_COUNTED_MEMORY_H_
#define BASE_MEMORY_REF_COUNTED_MEMORY_H_
+#include <stddef.h>
+
#include <string>
#include <vector>
#include "base/base_export.h"
#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
namespace base {
@@ -104,7 +107,7 @@ class BASE_EXPORT RefCountedString : public RefCountedMemory {
// Constructs a RefCountedString object by performing a swap. (To non
// destructively build a RefCountedString, use the default constructor and
// copy into object->data()).
- static RefCountedString* TakeString(std::string* to_destroy);
+ static scoped_refptr<RefCountedString> TakeString(std::string* to_destroy);
// Overridden from RefCountedMemory:
const unsigned char* front() const override;
@@ -121,26 +124,6 @@ class BASE_EXPORT RefCountedString : public RefCountedMemory {
DISALLOW_COPY_AND_ASSIGN(RefCountedString);
};
-// An implementation of RefCountedMemory that holds a chunk of memory
-// previously allocated with malloc or calloc, and that therefore must be freed
-// using free().
-class BASE_EXPORT RefCountedMallocedMemory : public base::RefCountedMemory {
- public:
- RefCountedMallocedMemory(void* data, size_t length);
-
- // Overridden from RefCountedMemory:
- const unsigned char* front() const override;
- size_t size() const override;
-
- private:
- ~RefCountedMallocedMemory() override;
-
- unsigned char* data_;
- size_t length_;
-
- DISALLOW_COPY_AND_ASSIGN(RefCountedMallocedMemory);
-};
-
} // namespace base
#endif // BASE_MEMORY_REF_COUNTED_MEMORY_H_
diff --git a/chromium/base/memory/ref_counted_memory_unittest.cc b/chromium/base/memory/ref_counted_memory_unittest.cc
index 5bfc1c79a69..bd2ed01f54b 100644
--- a/chromium/base/memory/ref_counted_memory_unittest.cc
+++ b/chromium/base/memory/ref_counted_memory_unittest.cc
@@ -4,6 +4,8 @@
#include "base/memory/ref_counted_memory.h"
+#include <stdint.h>
+
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
@@ -17,7 +19,7 @@ TEST(RefCountedMemoryUnitTest, RefCountedStaticMemory) {
}
TEST(RefCountedMemoryUnitTest, RefCountedBytes) {
- std::vector<uint8> data;
+ std::vector<uint8_t> data;
data.push_back(45);
data.push_back(99);
scoped_refptr<RefCountedMemory> mem = RefCountedBytes::TakeVector(&data);
@@ -50,16 +52,6 @@ TEST(RefCountedMemoryUnitTest, RefCountedString) {
EXPECT_EQ('e', mem->front()[1]);
}
-TEST(RefCountedMemoryUnitTest, RefCountedMallocedMemory) {
- void* data = malloc(6);
- memcpy(data, "hello", 6);
-
- scoped_refptr<RefCountedMemory> mem = new RefCountedMallocedMemory(data, 6);
-
- EXPECT_EQ(6U, mem->size());
- EXPECT_EQ(0, memcmp("hello", mem->front(), 6));
-}
-
TEST(RefCountedMemoryUnitTest, Equals) {
std::string s1("same");
scoped_refptr<RefCountedMemory> mem1 = RefCountedString::TakeString(&s1);
diff --git a/chromium/base/memory/ref_counted_unittest.cc b/chromium/base/memory/ref_counted_unittest.cc
index 6f8e599cbdc..dbc6f33d0d0 100644
--- a/chromium/base/memory/ref_counted_unittest.cc
+++ b/chromium/base/memory/ref_counted_unittest.cc
@@ -180,26 +180,6 @@ TEST(RefCountedUnitTest, ConvertibleEquality) {
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();
@@ -212,7 +192,7 @@ TEST(RefCountedUnitTest, MoveAssignment1) {
{
scoped_refptr<ScopedRefPtrCountBase> p2;
- p2 = p1.Pass();
+ p2 = std::move(p1);
EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
EXPECT_EQ(nullptr, p1.get());
@@ -243,7 +223,7 @@ TEST(RefCountedUnitTest, MoveAssignment2) {
EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
- p1 = p2.Pass();
+ p1 = std::move(p2);
EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
EXPECT_EQ(raw, p1.get());
@@ -274,7 +254,7 @@ TEST(RefCountedUnitTest, MoveAssignmentSameInstance1) {
EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
- p1 = p2.Pass();
+ p1 = std::move(p2);
EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
EXPECT_EQ(raw, p1.get());
@@ -305,7 +285,7 @@ TEST(RefCountedUnitTest, MoveAssignmentSameInstance2) {
EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
- p2 = p1.Pass();
+ p2 = std::move(p1);
EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
EXPECT_EQ(nullptr, p1.get());
@@ -337,7 +317,7 @@ TEST(RefCountedUnitTest, MoveAssignmentDifferentInstances) {
EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
- p1 = p2.Pass();
+ p1 = std::move(p2);
EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
EXPECT_EQ(raw2, p1.get());
@@ -374,7 +354,7 @@ TEST(RefCountedUnitTest, MoveAssignmentDerived) {
EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count());
- p1 = p2.Pass();
+ p1 = std::move(p2);
EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
@@ -407,7 +387,7 @@ TEST(RefCountedUnitTest, MoveConstructor) {
EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
{
- scoped_refptr<ScopedRefPtrCountBase> p2(p1.Pass());
+ scoped_refptr<ScopedRefPtrCountBase> p2(std::move(p1));
EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
EXPECT_EQ(nullptr, p1.get());
@@ -437,7 +417,7 @@ TEST(RefCountedUnitTest, MoveConstructorDerived) {
EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count());
{
- scoped_refptr<ScopedRefPtrCountBase> p2(p1.Pass());
+ scoped_refptr<ScopedRefPtrCountBase> p2(std::move(p1));
EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
diff --git a/chromium/base/memory/scoped_ptr.h b/chromium/base/memory/scoped_ptr.h
index 2399e954cc6..282a014869b 100644
--- a/chromium/base/memory/scoped_ptr.h
+++ b/chromium/base/memory/scoped_ptr.h
@@ -37,42 +37,43 @@
// in that they are "movable but not copyable." You can use the scopers in
// the parameter and return types of functions to signify ownership transfer
// in to and out of a function. When calling a function that has a scoper
-// as the argument type, it must be called with the result of an analogous
-// scoper's Pass() function or another function that generates a temporary;
-// passing by copy will NOT work. Here is an example using scoped_ptr:
+// as the argument type, it must be called with an rvalue of a scoper, which
+// can be created by using std::move(), or the result of another function that
+// generates a temporary; passing by copy will NOT work. Here is an example
+// using scoped_ptr:
//
// void TakesOwnership(scoped_ptr<Foo> arg) {
-// // Do something with arg
+// // Do something with arg.
// }
// scoped_ptr<Foo> CreateFoo() {
-// // No need for calling Pass() because we are constructing a temporary
-// // for the return value.
+// // No need for calling std::move() for returning a move-only value, or
+// // when you already have an rvalue as we do here.
// return scoped_ptr<Foo>(new Foo("new"));
// }
// scoped_ptr<Foo> PassThru(scoped_ptr<Foo> arg) {
-// return arg.Pass();
+// return arg;
// }
//
// {
// scoped_ptr<Foo> ptr(new Foo("yay")); // ptr manages Foo("yay").
-// TakesOwnership(ptr.Pass()); // ptr no longer owns Foo("yay").
+// TakesOwnership(std::move(ptr)); // ptr no longer owns Foo("yay").
// scoped_ptr<Foo> ptr2 = CreateFoo(); // ptr2 owns the return Foo.
// scoped_ptr<Foo> ptr3 = // ptr3 now owns what was in ptr2.
-// PassThru(ptr2.Pass()); // ptr2 is correspondingly nullptr.
+// PassThru(std::move(ptr2)); // ptr2 is correspondingly nullptr.
// }
//
-// Notice that if you do not call Pass() when returning from PassThru(), or
+// Notice that if you do not call std::move() when returning from PassThru(), or
// when invoking TakesOwnership(), the code will not compile because scopers
// are not copyable; they only implement move semantics which require calling
-// the Pass() function to signify a destructive transfer of state. CreateFoo()
-// is different though because we are constructing a temporary on the return
-// line and thus can avoid needing to call Pass().
+// the std::move() function to signify a destructive transfer of state.
+// CreateFoo() is different though because we are constructing a temporary on
+// the return line and thus can avoid needing to call std::move().
//
-// Pass() properly handles upcast in initialization, i.e. you can use a
-// scoped_ptr<Child> to initialize a scoped_ptr<Parent>:
+// The conversion move-constructor properly handles upcast in initialization,
+// i.e. you can use a scoped_ptr<Child> to initialize a scoped_ptr<Parent>:
//
// scoped_ptr<Foo> foo(new Foo());
-// scoped_ptr<FooParent> parent(foo.Pass());
+// scoped_ptr<FooParent> parent(std::move(foo));
#ifndef BASE_MEMORY_SCOPED_PTR_H_
#define BASE_MEMORY_SCOPED_PTR_H_
@@ -84,11 +85,13 @@
#include <stddef.h>
#include <stdlib.h>
-#include <algorithm> // For std::swap().
#include <iosfwd>
+#include <memory>
+#include <type_traits>
+#include <utility>
-#include "base/basictypes.h"
#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "base/move.h"
#include "base/template_util.h"
@@ -99,61 +102,6 @@ class RefCountedBase;
class RefCountedThreadSafeBase;
} // namespace subtle
-// Function object which deletes its parameter, which must be a pointer.
-// If C is an array type, invokes 'delete[]' on the parameter; otherwise,
-// invokes 'delete'. The default deleter for scoped_ptr<T>.
-template <class T>
-struct DefaultDeleter {
- DefaultDeleter() {}
- template <typename U> DefaultDeleter(const DefaultDeleter<U>& other) {
- // IMPLEMENTATION NOTE: C++11 20.7.1.1.2p2 only provides this constructor
- // if U* is implicitly convertible to T* and U is not an array type.
- //
- // Correct implementation should use SFINAE to disable this
- // constructor. However, since there are no other 1-argument constructors,
- // using a COMPILE_ASSERT() based on is_convertible<> and requiring
- // complete types is simpler and will cause compile failures for equivalent
- // misuses.
- //
- // Note, the is_convertible<U*, T*> check also ensures that U is not an
- // array. T is guaranteed to be a non-array, so any U* where U is an array
- // cannot convert to T*.
- enum { T_must_be_complete = sizeof(T) };
- enum { U_must_be_complete = sizeof(U) };
- COMPILE_ASSERT((base::is_convertible<U*, T*>::value),
- U_ptr_must_implicitly_convert_to_T_ptr);
- }
- inline void operator()(T* ptr) const {
- enum { type_must_be_complete = sizeof(T) };
- delete ptr;
- }
-};
-
-// Specialization of DefaultDeleter for array types.
-template <class T>
-struct DefaultDeleter<T[]> {
- inline void operator()(T* ptr) const {
- enum { type_must_be_complete = sizeof(T) };
- delete[] ptr;
- }
-
- private:
- // Disable this operator for any U != T because it is undefined to execute
- // an array delete when the static type of the array mismatches the dynamic
- // type.
- //
- // References:
- // C++98 [expr.delete]p3
- // http://cplusplus.github.com/LWG/lwg-defects.html#938
- template <typename U> void operator()(U* array) const;
-};
-
-template <class T, int n>
-struct DefaultDeleter<T[n]> {
- // Never allow someone to declare something like scoped_ptr<int[10]>.
- COMPILE_ASSERT(sizeof(T) == -1, do_not_use_array_with_size_as_type);
-};
-
// Function object which invokes 'free' on its parameter, which must be
// a pointer. Can be used to store malloc-allocated pointers in scoped_ptr:
//
@@ -175,17 +123,6 @@ template <typename T> struct IsNotRefCounted {
};
};
-template <typename T>
-struct ShouldAbortOnSelfReset {
- template <typename U>
- static NoType Test(const typename U::AllowSelfReset*);
-
- template <typename U>
- static YesType Test(...);
-
- static const bool value = sizeof(Test<T>(0)) == sizeof(YesType);
-};
-
// Minimal implementation of the core logic of scoped_ptr, suitable for
// reuse in both scoped_ptr and its specializations.
template <class T, class D>
@@ -216,18 +153,20 @@ class scoped_ptr_impl {
}
~scoped_ptr_impl() {
- if (data_.ptr != nullptr) {
- // Not using get_deleter() saves one function call in non-optimized
- // builds.
- static_cast<D&>(data_)(data_.ptr);
- }
+ // Match libc++, which calls reset() in its destructor.
+ // Use nullptr as the new value for three reasons:
+ // 1. libc++ does it.
+ // 2. Avoids infinitely recursing into destructors if two classes are owned
+ // in a reference cycle (see ScopedPtrTest.ReferenceCycle).
+ // 3. If |this| is accessed in the future, in a use-after-free bug, attempts
+ // to dereference |this|'s pointer should cause either a failure or a
+ // segfault closer to the problem. If |this| wasn't reset to nullptr,
+ // the access would cause the deleted memory to be read or written
+ // leading to other more subtle issues.
+ reset(nullptr);
}
void reset(T* p) {
- // This is a self-reset, which is no longer allowed for default deleters:
- // https://crbug.com/162971
- assert(!ShouldAbortOnSelfReset<D>::value || p == nullptr || p != data_.ptr);
-
// Match C++11's definition of unique_ptr::reset(), which requires changing
// the pointer before invoking the deleter on the old pointer. This prevents
// |this| from being accessed after the deleter is run, which may destroy
@@ -289,25 +228,27 @@ class scoped_ptr_impl {
// dereference it, you get the thread safety guarantees of T.
//
// The size of scoped_ptr is small. On most compilers, when using the
-// DefaultDeleter, sizeof(scoped_ptr<T>) == sizeof(T*). Custom deleters will
-// increase the size proportional to whatever state they need to have. See
+// std::default_delete, sizeof(scoped_ptr<T>) == sizeof(T*). Custom deleters
+// will increase the size proportional to whatever state they need to have. See
// comments inside scoped_ptr_impl<> for details.
//
// Current implementation targets having a strict subset of C++11's
// unique_ptr<> features. Known deficiencies include not supporting move-only
// deleteres, function pointers as deleters, and deleters with reference
// types.
-template <class T, class D = base::DefaultDeleter<T> >
+template <class T, class D = std::default_delete<T>>
class scoped_ptr {
- MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(scoped_ptr)
+ DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND(scoped_ptr)
- COMPILE_ASSERT(base::internal::IsNotRefCounted<T>::value,
- T_is_refcounted_type_and_needs_scoped_refptr);
+ static_assert(!std::is_array<T>::value,
+ "scoped_ptr doesn't support array with size");
+ static_assert(base::internal::IsNotRefCounted<T>::value,
+ "T is a refcounted type and needs a scoped_refptr");
public:
// The element and deleter types.
- typedef T element_type;
- typedef D deleter_type;
+ using element_type = T;
+ using deleter_type = D;
// Constructor. Defaults to initializing with nullptr.
scoped_ptr() : impl_(nullptr) {}
@@ -319,44 +260,87 @@ class scoped_ptr {
scoped_ptr(element_type* p, const D& d) : impl_(p, d) {}
// Constructor. Allows construction from a nullptr.
- scoped_ptr(decltype(nullptr)) : impl_(nullptr) {}
+ scoped_ptr(std::nullptr_t) : impl_(nullptr) {}
+
+ // Move constructor.
+ //
+ // IMPLEMENTATION NOTE: Clang requires a move constructor to be defined (and
+ // not just the conversion constructor) in order to warn on pessimizing moves.
+ // The requirements for the move constructor are specified in C++11
+ // 20.7.1.2.1.15-17, which has some subtleties around reference deleters. As
+ // we don't support reference (or move-only) deleters, the post conditions are
+ // trivially true: we always copy construct the deleter from other's deleter.
+ scoped_ptr(scoped_ptr&& other) : impl_(&other.impl_) {}
- // Constructor. Allows construction from a scoped_ptr rvalue for a
+ // Conversion constructor. Allows construction from a scoped_ptr rvalue for a
// convertible type and deleter.
//
- // IMPLEMENTATION NOTE: C++11 unique_ptr<> keeps this constructor distinct
- // from the normal move constructor. By C++11 20.7.1.2.1.21, this constructor
- // has different post-conditions if D is a reference type. Since this
- // implementation does not support deleters with reference type,
- // we do not need a separate move constructor allowing us to avoid one
- // use of SFINAE. You only need to care about this if you modify the
- // implementation of scoped_ptr.
- template <typename U, typename V>
- scoped_ptr(scoped_ptr<U, V>&& other)
- : impl_(&other.impl_) {
- COMPILE_ASSERT(!base::is_array<U>::value, U_cannot_be_an_array);
+ // IMPLEMENTATION NOTE: C++ 20.7.1.2.1.19 requires this constructor to only
+ // participate in overload resolution if all the following are true:
+ // - U is implicitly convertible to T: this is important for 2 reasons:
+ // 1. So type traits don't incorrectly return true, e.g.
+ // std::is_convertible<scoped_ptr<Base>, scoped_ptr<Derived>>::value
+ // should be false.
+ // 2. To make sure code like this compiles:
+ // void F(scoped_ptr<int>);
+ // void F(scoped_ptr<Base>);
+ // // Ambiguous since both conversion constructors match.
+ // F(scoped_ptr<Derived>());
+ // - U is not an array type: to prevent conversions from scoped_ptr<T[]> to
+ // scoped_ptr<T>.
+ // - D is a reference type and E is the same type, or D is not a reference
+ // type and E is implicitly convertible to D: again, we don't support
+ // reference deleters, so we only worry about the latter requirement.
+ template <typename U,
+ typename E,
+ typename std::enable_if<!std::is_array<U>::value &&
+ std::is_convertible<U*, T*>::value &&
+ std::is_convertible<E, D>::value>::type* =
+ nullptr>
+ scoped_ptr(scoped_ptr<U, E>&& other)
+ : impl_(&other.impl_) {}
+
+ // operator=.
+ //
+ // IMPLEMENTATION NOTE: Unlike the move constructor, Clang does not appear to
+ // require a move assignment operator to trigger the pessimizing move warning:
+ // in this case, the warning triggers when moving a temporary. For consistency
+ // with the move constructor, we define it anyway. C++11 20.7.1.2.3.1-3
+ // defines several requirements around this: like the move constructor, the
+ // requirements are simplified by the fact that we don't support move-only or
+ // reference deleters.
+ scoped_ptr& operator=(scoped_ptr&& rhs) {
+ impl_.TakeState(&rhs.impl_);
+ return *this;
}
// operator=. Allows assignment from a scoped_ptr rvalue for a convertible
// type and deleter.
//
// IMPLEMENTATION NOTE: C++11 unique_ptr<> keeps this operator= distinct from
- // the normal move assignment operator. By C++11 20.7.1.2.3.4, this templated
- // form has different requirements on for move-only Deleters. Since this
- // implementation does not support move-only Deleters, we do not need a
- // separate move assignment operator allowing us to avoid one use of SFINAE.
- // You only need to care about this if you modify the implementation of
- // scoped_ptr.
- template <typename U, typename V>
- scoped_ptr& operator=(scoped_ptr<U, V>&& rhs) {
- COMPILE_ASSERT(!base::is_array<U>::value, U_cannot_be_an_array);
+ // the normal move assignment operator. C++11 20.7.1.2.3.4-7 contains the
+ // requirement for this operator, but like the conversion constructor, the
+ // requirements are greatly simplified by not supporting move-only or
+ // reference deleters.
+ template <typename U,
+ typename E,
+ typename std::enable_if<!std::is_array<U>::value &&
+ std::is_convertible<U*, T*>::value &&
+ // Note that this really should be
+ // std::is_assignable, but <type_traits>
+ // appears to be missing this on some
+ // platforms. This is close enough (though
+ // it's not the same).
+ std::is_convertible<D, E>::value>::type* =
+ nullptr>
+ scoped_ptr& operator=(scoped_ptr<U, E>&& rhs) {
impl_.TakeState(&rhs.impl_);
return *this;
}
// operator=. Allows assignment from a nullptr. Deletes the currently owned
// object, if any.
- scoped_ptr& operator=(decltype(nullptr)) {
+ scoped_ptr& operator=(std::nullptr_t) {
reset();
return *this;
}
@@ -397,12 +381,6 @@ class scoped_ptr {
return impl_.get() ? &scoped_ptr::impl_ : nullptr;
}
- // Comparison operators.
- // These return whether two scoped_ptr refer to the same object, not just to
- // two different but equal objects.
- bool operator==(const element_type* p) const { return impl_.get() == p; }
- bool operator!=(const element_type* p) const { return impl_.get() != p; }
-
// Swap two scoped pointers.
void swap(scoped_ptr& p2) {
impl_.swap(p2.impl_);
@@ -423,23 +401,16 @@ class scoped_ptr {
// Forbidden for API compatibility with std::unique_ptr.
explicit scoped_ptr(int disallow_construction_from_null);
-
- // Forbid comparison of scoped_ptr types. If U != T, it totally
- // doesn't make sense, and if U == T, it still doesn't make sense
- // because you should never have the same object owned by two different
- // scoped_ptrs.
- template <class U> bool operator==(scoped_ptr<U> const& p2) const;
- template <class U> bool operator!=(scoped_ptr<U> const& p2) const;
};
template <class T, class D>
class scoped_ptr<T[], D> {
- MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(scoped_ptr)
+ DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND(scoped_ptr)
public:
// The element and deleter types.
- typedef T element_type;
- typedef D deleter_type;
+ using element_type = T;
+ using deleter_type = D;
// Constructor. Defaults to initializing with nullptr.
scoped_ptr() : impl_(nullptr) {}
@@ -458,7 +429,7 @@ class scoped_ptr<T[], D> {
explicit scoped_ptr(element_type* array) : impl_(array) {}
// Constructor. Allows construction from a nullptr.
- scoped_ptr(decltype(nullptr)) : impl_(nullptr) {}
+ scoped_ptr(std::nullptr_t) : impl_(nullptr) {}
// Constructor. Allows construction from a scoped_ptr rvalue.
scoped_ptr(scoped_ptr&& other) : impl_(&other.impl_) {}
@@ -471,7 +442,7 @@ class scoped_ptr<T[], D> {
// operator=. Allows assignment from a nullptr. Deletes the currently owned
// array, if any.
- scoped_ptr& operator=(decltype(nullptr)) {
+ scoped_ptr& operator=(std::nullptr_t) {
reset();
return *this;
}
@@ -502,12 +473,6 @@ class scoped_ptr<T[], D> {
return impl_.get() ? &scoped_ptr::impl_ : nullptr;
}
- // Comparison operators.
- // These return whether two scoped_ptr refer to the same object, not just to
- // two different but equal objects.
- bool operator==(element_type* array) const { return impl_.get() == array; }
- bool operator!=(element_type* array) const { return impl_.get() != array; }
-
// Swap two scoped pointers.
void swap(scoped_ptr& p2) {
impl_.swap(p2.impl_);
@@ -540,13 +505,6 @@ class scoped_ptr<T[], D> {
// reasons as the constructor above.
template <typename U> void reset(U* array);
void reset(int disallow_reset_from_null);
-
- // Forbid comparison of scoped_ptr types. If U != T, it totally
- // doesn't make sense, and if U == T, it still doesn't make sense
- // because you should never have the same object owned by two different
- // scoped_ptrs.
- template <class U> bool operator==(scoped_ptr<U> const& p2) const;
- template <class U> bool operator!=(scoped_ptr<U> const& p2) const;
};
// Free functions
@@ -555,14 +513,82 @@ void swap(scoped_ptr<T, D>& p1, scoped_ptr<T, D>& p2) {
p1.swap(p2);
}
+template <class T1, class D1, class T2, class D2>
+bool operator==(const scoped_ptr<T1, D1>& p1, const scoped_ptr<T2, D2>& p2) {
+ return p1.get() == p2.get();
+}
+template <class T, class D>
+bool operator==(const scoped_ptr<T, D>& p, std::nullptr_t) {
+ return p.get() == nullptr;
+}
+template <class T, class D>
+bool operator==(std::nullptr_t, const scoped_ptr<T, D>& p) {
+ return p.get() == nullptr;
+}
+
+template <class T1, class D1, class T2, class D2>
+bool operator!=(const scoped_ptr<T1, D1>& p1, const scoped_ptr<T2, D2>& p2) {
+ return !(p1 == p2);
+}
+template <class T, class D>
+bool operator!=(const scoped_ptr<T, D>& p, std::nullptr_t) {
+ return !(p == nullptr);
+}
+template <class T, class D>
+bool operator!=(std::nullptr_t, const scoped_ptr<T, D>& p) {
+ return !(p == nullptr);
+}
+
+template <class T1, class D1, class T2, class D2>
+bool operator<(const scoped_ptr<T1, D1>& p1, const scoped_ptr<T2, D2>& p2) {
+ return p1.get() < p2.get();
+}
+template <class T, class D>
+bool operator<(const scoped_ptr<T, D>& p, std::nullptr_t) {
+ return p.get() < nullptr;
+}
template <class T, class D>
-bool operator==(T* p1, const scoped_ptr<T, D>& p2) {
- return p1 == p2.get();
+bool operator<(std::nullptr_t, const scoped_ptr<T, D>& p) {
+ return nullptr < p.get();
}
+template <class T1, class D1, class T2, class D2>
+bool operator>(const scoped_ptr<T1, D1>& p1, const scoped_ptr<T2, D2>& p2) {
+ return p2 < p1;
+}
+template <class T, class D>
+bool operator>(const scoped_ptr<T, D>& p, std::nullptr_t) {
+ return nullptr < p;
+}
+template <class T, class D>
+bool operator>(std::nullptr_t, const scoped_ptr<T, D>& p) {
+ return p < nullptr;
+}
+
+template <class T1, class D1, class T2, class D2>
+bool operator<=(const scoped_ptr<T1, D1>& p1, const scoped_ptr<T2, D2>& p2) {
+ return !(p1 > p2);
+}
+template <class T, class D>
+bool operator<=(const scoped_ptr<T, D>& p, std::nullptr_t) {
+ return !(p > nullptr);
+}
+template <class T, class D>
+bool operator<=(std::nullptr_t, const scoped_ptr<T, D>& p) {
+ return !(nullptr > p);
+}
+
+template <class T1, class D1, class T2, class D2>
+bool operator>=(const scoped_ptr<T1, D1>& p1, const scoped_ptr<T2, D2>& p2) {
+ return !(p1 < p2);
+}
+template <class T, class D>
+bool operator>=(const scoped_ptr<T, D>& p, std::nullptr_t) {
+ return !(p < nullptr);
+}
template <class T, class D>
-bool operator!=(T* p1, const scoped_ptr<T, D>& p2) {
- return p1 != p2.get();
+bool operator>=(std::nullptr_t, const scoped_ptr<T, D>& p) {
+ return !(nullptr < p);
}
// A function to convert T* into scoped_ptr<T>
diff --git a/chromium/base/memory/scoped_ptr_unittest.cc b/chromium/base/memory/scoped_ptr_unittest.cc
index 71d995c452e..8bea43b972b 100644
--- a/chromium/base/memory/scoped_ptr_unittest.cc
+++ b/chromium/base/memory/scoped_ptr_unittest.cc
@@ -4,11 +4,14 @@
#include "base/memory/scoped_ptr.h"
+#include <stddef.h>
+
#include <sstream>
-#include "base/basictypes.h"
#include "base/bind.h"
#include "base/callback.h"
+#include "base/macros.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
@@ -84,7 +87,7 @@ int OverloadedNewAndDelete::g_new_count = 0;
int OverloadedNewAndDelete::g_delete_count = 0;
scoped_ptr<ConDecLogger> PassThru(scoped_ptr<ConDecLogger> logger) {
- return logger.Pass();
+ return logger;
}
void GrabAndDrop(scoped_ptr<ConDecLogger> logger) {
@@ -102,8 +105,8 @@ TEST(ScopedPtrTest, ScopedPtr) {
int constructed = 0;
// Ensure size of scoped_ptr<> doesn't increase unexpectedly.
- COMPILE_ASSERT(sizeof(int*) >= sizeof(scoped_ptr<int>),
- scoped_ptr_larger_than_raw_ptr);
+ static_assert(sizeof(int*) >= sizeof(scoped_ptr<int>),
+ "scoped_ptr shouldn't be larger than the raw pointer");
{
scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed));
@@ -146,25 +149,25 @@ TEST(ScopedPtrTest, ScopedPtr) {
}
EXPECT_EQ(0, constructed);
- // Test swap(), == and !=
+ // Test swap().
{
scoped_ptr<ConDecLogger> scoper1;
scoped_ptr<ConDecLogger> scoper2;
- EXPECT_TRUE(scoper1 == scoper2.get());
- EXPECT_FALSE(scoper1 != scoper2.get());
+ EXPECT_TRUE(scoper1.get() == scoper2.get());
+ EXPECT_FALSE(scoper1.get() != scoper2.get());
ConDecLogger* logger = new ConDecLogger(&constructed);
scoper1.reset(logger);
EXPECT_EQ(logger, scoper1.get());
EXPECT_FALSE(scoper2.get());
- EXPECT_FALSE(scoper1 == scoper2.get());
- EXPECT_TRUE(scoper1 != scoper2.get());
+ EXPECT_FALSE(scoper1.get() == scoper2.get());
+ EXPECT_TRUE(scoper1.get() != scoper2.get());
scoper2.swap(scoper1);
EXPECT_EQ(logger, scoper2.get());
EXPECT_FALSE(scoper1.get());
- EXPECT_FALSE(scoper1 == scoper2.get());
- EXPECT_TRUE(scoper1 != scoper2.get());
+ EXPECT_FALSE(scoper1.get() == scoper2.get());
+ EXPECT_TRUE(scoper1.get() != scoper2.get());
}
EXPECT_EQ(0, constructed);
}
@@ -178,7 +181,7 @@ TEST(ScopedPtrTest, ScopedPtrDepthSubtyping) {
EXPECT_EQ(1, constructed);
EXPECT_TRUE(scoper.get());
- scoped_ptr<ConDecLoggerParent> scoper_parent(scoper.Pass());
+ scoped_ptr<ConDecLoggerParent> scoper_parent(std::move(scoper));
EXPECT_EQ(1, constructed);
EXPECT_TRUE(scoper_parent.get());
EXPECT_FALSE(scoper.get());
@@ -196,7 +199,7 @@ TEST(ScopedPtrTest, ScopedPtrDepthSubtyping) {
EXPECT_TRUE(scoper.get());
scoped_ptr<ConDecLoggerParent> scoper_parent;
- scoper_parent = scoper.Pass();
+ scoper_parent = std::move(scoper);
EXPECT_EQ(1, constructed);
EXPECT_TRUE(scoper_parent.get());
EXPECT_FALSE(scoper.get());
@@ -209,7 +212,7 @@ TEST(ScopedPtrTest, ScopedPtrDepthSubtyping) {
EXPECT_EQ(1, constructed);
EXPECT_TRUE(scoper.get());
- scoped_ptr<const ConDecLogger> scoper_const(scoper.Pass());
+ scoped_ptr<const ConDecLogger> scoper_const(std::move(scoper));
EXPECT_EQ(1, constructed);
EXPECT_TRUE(scoper_const.get());
EXPECT_FALSE(scoper.get());
@@ -227,7 +230,7 @@ TEST(ScopedPtrTest, ScopedPtrDepthSubtyping) {
EXPECT_TRUE(scoper.get());
scoped_ptr<const ConDecLogger> scoper_const;
- scoper_const = scoper.Pass();
+ scoper_const = std::move(scoper);
EXPECT_EQ(1, constructed);
EXPECT_TRUE(scoper_const.get());
EXPECT_FALSE(scoper.get());
@@ -251,7 +254,7 @@ TEST(ScopedPtrTest, ScopedPtrDepthSubtyping) {
EXPECT_EQ(0, alternate_deletes);
// Test this compiles and correctly overwrites the deleter state.
- scoper = scoper_child.Pass();
+ scoper = std::move(scoper_child);
EXPECT_TRUE(scoper);
EXPECT_FALSE(scoper_child);
EXPECT_EQ(1, deletes);
@@ -267,7 +270,8 @@ TEST(ScopedPtrTest, ScopedPtrDepthSubtyping) {
EXPECT_TRUE(scoper_child);
EXPECT_EQ(1, deletes);
EXPECT_EQ(1, alternate_deletes);
- scoped_ptr<double, CountingDeleter> scoper_construct(scoper_child.Pass());
+ scoped_ptr<double, CountingDeleter> scoper_construct(
+ std::move(scoper_child));
EXPECT_TRUE(scoper_construct);
EXPECT_FALSE(scoper_child);
EXPECT_EQ(1, deletes);
@@ -327,12 +331,12 @@ TEST(ScopedPtrTest, ScopedPtrWithArray) {
}
EXPECT_EQ(0, constructed);
- // Test swap(), ==, !=, and type-safe Boolean.
+ // Test swap() and type-safe Boolean.
{
scoped_ptr<ConDecLogger[]> scoper1;
scoped_ptr<ConDecLogger[]> scoper2;
- EXPECT_TRUE(scoper1 == scoper2.get());
- EXPECT_FALSE(scoper1 != scoper2.get());
+ EXPECT_TRUE(scoper1.get() == scoper2.get());
+ EXPECT_FALSE(scoper1.get() != scoper2.get());
ConDecLogger* loggers = new ConDecLogger[kNumLoggers];
for (int i = 0; i < kNumLoggers; ++i) {
@@ -343,14 +347,14 @@ TEST(ScopedPtrTest, ScopedPtrWithArray) {
EXPECT_EQ(loggers, scoper1.get());
EXPECT_FALSE(scoper2);
EXPECT_FALSE(scoper2.get());
- EXPECT_FALSE(scoper1 == scoper2.get());
- EXPECT_TRUE(scoper1 != scoper2.get());
+ EXPECT_FALSE(scoper1.get() == scoper2.get());
+ EXPECT_TRUE(scoper1.get() != scoper2.get());
scoper2.swap(scoper1);
EXPECT_EQ(loggers, scoper2.get());
EXPECT_FALSE(scoper1.get());
- EXPECT_FALSE(scoper1 == scoper2.get());
- EXPECT_TRUE(scoper1 != scoper2.get());
+ EXPECT_FALSE(scoper1.get() == scoper2.get());
+ EXPECT_TRUE(scoper1.get() != scoper2.get());
}
EXPECT_EQ(0, constructed);
@@ -363,13 +367,13 @@ TEST(ScopedPtrTest, ScopedPtrWithArray) {
}
EXPECT_EQ(kNumLoggers, constructed);
- // Test Pass() with constructor;
- scoped_ptr<ConDecLogger[]> scoper2(scoper.Pass());
+ // Test moving with constructor;
+ scoped_ptr<ConDecLogger[]> scoper2(std::move(scoper));
EXPECT_EQ(kNumLoggers, constructed);
- // Test Pass() with assignment;
+ // Test moving with assignment;
scoped_ptr<ConDecLogger[]> scoper3;
- scoper3 = scoper2.Pass();
+ scoper3 = std::move(scoper2);
EXPECT_EQ(kNumLoggers, constructed);
EXPECT_FALSE(scoper);
EXPECT_FALSE(scoper2);
@@ -378,27 +382,30 @@ TEST(ScopedPtrTest, ScopedPtrWithArray) {
EXPECT_EQ(0, constructed);
}
-TEST(ScopedPtrTest, PassBehavior) {
+TEST(ScopedPtrTest, MoveBehavior) {
int constructed = 0;
{
ConDecLogger* logger = new ConDecLogger(&constructed);
scoped_ptr<ConDecLogger> scoper(logger);
EXPECT_EQ(1, constructed);
- // Test Pass() with constructor;
- scoped_ptr<ConDecLogger> scoper2(scoper.Pass());
+ // Test moving with constructor;
+ scoped_ptr<ConDecLogger> scoper2(std::move(scoper));
EXPECT_EQ(1, constructed);
- // Test Pass() with assignment;
+ // Test moving with assignment;
scoped_ptr<ConDecLogger> scoper3;
- scoper3 = scoper2.Pass();
+ scoper3 = std::move(scoper2);
EXPECT_EQ(1, constructed);
EXPECT_FALSE(scoper.get());
EXPECT_FALSE(scoper2.get());
EXPECT_TRUE(scoper3.get());
}
- // Test uncaught Pass() does not have side effects.
+#if !defined(OS_ANDROID) && !defined(OS_LINUX) && !defined(OS_MACOSX)
+ // Test uncaught Pass() does not have side effects, because Pass()
+ // is implemented by std::move().
+ // TODO(danakj): Remove this test case when we remove Pass().
{
ConDecLogger* logger = new ConDecLogger(&constructed);
scoped_ptr<ConDecLogger> scoper(logger);
@@ -411,6 +418,7 @@ TEST(ScopedPtrTest, PassBehavior) {
EXPECT_TRUE(rvalue);
}
EXPECT_EQ(0, constructed);
+#endif
// Test that passing to function which does nothing does not leak.
{
@@ -419,7 +427,7 @@ TEST(ScopedPtrTest, PassBehavior) {
EXPECT_EQ(1, constructed);
// Should auto-destruct logger by end of scope.
- GrabAndDrop(scoper.Pass());
+ GrabAndDrop(std::move(scoper));
EXPECT_FALSE(scoper.get());
}
EXPECT_EQ(0, constructed);
@@ -434,7 +442,7 @@ TEST(ScopedPtrTest, ReturnTypeBehavior) {
scoped_ptr<ConDecLogger> scoper(logger);
EXPECT_EQ(1, constructed);
- PassThru(scoper.Pass());
+ PassThru(std::move(scoper));
EXPECT_FALSE(scoper.get());
}
EXPECT_EQ(0, constructed);
@@ -446,7 +454,7 @@ TEST(ScopedPtrTest, ReturnTypeBehavior) {
EXPECT_EQ(1, constructed);
// Should auto-destruct logger by end of scope.
- PassThru(scoper.Pass());
+ PassThru(std::move(scoper));
EXPECT_FALSE(scoper.get());
}
EXPECT_EQ(0, constructed);
@@ -537,8 +545,8 @@ TEST(ScopedPtrTest, CustomDeleter) {
// Pass the second deleter through a constructor and an operator=. Then
// reinitialize the empty scopers to ensure that each one is deleting
// properly.
- scoped_ptr<double, CountingDeleter> scoper3(scoper2.Pass());
- scoper = scoper3.Pass();
+ scoped_ptr<double, CountingDeleter> scoper3(std::move(scoper2));
+ scoper = std::move(scoper3);
EXPECT_EQ(1, deletes);
scoper2.reset(&dummy_value2);
@@ -549,33 +557,33 @@ TEST(ScopedPtrTest, CustomDeleter) {
EXPECT_EQ(1, deletes);
EXPECT_EQ(3, alternate_deletes);
- // Test swap(), ==, !=, and type-safe Boolean.
+ // Test swap(), and type-safe Boolean.
{
scoped_ptr<double, CountingDeleter> scoper1(NULL,
CountingDeleter(&deletes));
scoped_ptr<double, CountingDeleter> scoper2(NULL,
CountingDeleter(&deletes));
- EXPECT_TRUE(scoper1 == scoper2.get());
- EXPECT_FALSE(scoper1 != scoper2.get());
+ EXPECT_TRUE(scoper1.get() == scoper2.get());
+ EXPECT_FALSE(scoper1.get() != scoper2.get());
scoper1.reset(&dummy_value);
EXPECT_TRUE(scoper1);
EXPECT_EQ(&dummy_value, scoper1.get());
EXPECT_FALSE(scoper2);
EXPECT_FALSE(scoper2.get());
- EXPECT_FALSE(scoper1 == scoper2.get());
- EXPECT_TRUE(scoper1 != scoper2.get());
+ EXPECT_FALSE(scoper1.get() == scoper2.get());
+ EXPECT_TRUE(scoper1.get() != scoper2.get());
scoper2.swap(scoper1);
EXPECT_EQ(&dummy_value, scoper2.get());
EXPECT_FALSE(scoper1.get());
- EXPECT_FALSE(scoper1 == scoper2.get());
- EXPECT_TRUE(scoper1 != scoper2.get());
+ EXPECT_FALSE(scoper1.get() == scoper2.get());
+ EXPECT_TRUE(scoper1.get() != scoper2.get());
}
}
// Sanity check test for overloaded new and delete operators. Does not do full
-// coverage of reset/release/Pass() operations as that is redundant with the
+// coverage of reset/release/move operations as that is redundant with the
// above.
TEST(ScopedPtrTest, OverloadedNewAndDelete) {
{
@@ -583,7 +591,7 @@ TEST(ScopedPtrTest, OverloadedNewAndDelete) {
scoped_ptr<OverloadedNewAndDelete> scoper(new OverloadedNewAndDelete());
EXPECT_TRUE(scoper.get());
- scoped_ptr<OverloadedNewAndDelete> scoper2(scoper.Pass());
+ scoped_ptr<OverloadedNewAndDelete> scoper2(std::move(scoper));
}
EXPECT_EQ(1, OverloadedNewAndDelete::delete_count());
EXPECT_EQ(1, OverloadedNewAndDelete::new_count());
@@ -632,55 +640,15 @@ TEST(ScopedPtrTest, Conversion) {
scoped_ptr<Sub> sub1(new Sub);
scoped_ptr<Sub> sub2(new Sub);
- // Upcast with Pass() works.
- scoped_ptr<Super> super1 = sub1.Pass();
- super1 = sub2.Pass();
+ // Upcast with move works.
+ scoped_ptr<Super> super1 = std::move(sub1);
+ super1 = std::move(sub2);
// Upcast with an rvalue works.
scoped_ptr<Super> super2 = SubClassReturn();
super2 = SubClassReturn();
}
-// Android death tests don't work properly with assert(). Yay.
-#if !defined(NDEBUG) && defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
-TEST(ScopedPtrTest, SelfResetAbortsWithDefaultDeleter) {
- scoped_ptr<int> x(new int);
- EXPECT_DEATH(x.reset(x.get()), "");
-}
-
-TEST(ScopedPtrTest, SelfResetAbortsWithDefaultArrayDeleter) {
- scoped_ptr<int[]> y(new int[4]);
- EXPECT_DEATH(y.reset(y.get()), "");
-}
-
-TEST(ScopedPtrTest, SelfResetAbortsWithDefaultFreeDeleter) {
- scoped_ptr<int, base::FreeDeleter> z(static_cast<int*>(malloc(sizeof(int))));
- EXPECT_DEATH(z.reset(z.get()), "");
-}
-
-// A custom deleter that doesn't opt out should still crash.
-TEST(ScopedPtrTest, SelfResetAbortsWithCustomDeleter) {
- struct CustomDeleter {
- inline void operator()(int* x) { delete x; }
- };
- scoped_ptr<int, CustomDeleter> x(new int);
- EXPECT_DEATH(x.reset(x.get()), "");
-}
-#endif
-
-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) {
@@ -709,10 +677,166 @@ TEST(ScopedPtrTest, ReferenceCycle) {
a->b.reset(new StructB);
a->b->a.reset(a);
- // Break the cycle by calling reset(). This will cause |a| (and hence, |a.b|)
+ // Break the cycle by calling reset(). This will cause |a| (and hence, |a->b|)
// to be deleted before the call to reset() returns. This tests that the
// implementation of scoped_ptr::reset() doesn't access |this| after it
// deletes the underlying pointer. This behaviour is consistent with the
// definition of unique_ptr::reset in C++11.
a->b.reset();
+
+ // Go again, but this time, break the cycle by invoking |a|'s destructor. This
+ // tests that the implementation of ~scoped_ptr doesn't infinitely recurse
+ // into the destructors of |a| and |a->b|. Note, deleting |a| instead will
+ // cause |a| to be double-free'd because |a->b| owns |a| and deletes it via
+ // its destructor.
+ a = new StructA;
+ a->b.reset(new StructB);
+ a->b->a.reset(a);
+ a->~StructA();
+}
+
+TEST(ScopedPtrTest, Operators) {
+ struct Parent {};
+ struct Child : public Parent {};
+
+ scoped_ptr<Parent> p(new Parent);
+ scoped_ptr<Parent> p2(new Parent);
+ scoped_ptr<Child> c(new Child);
+ scoped_ptr<Parent> pnull;
+
+ // Operator==.
+ EXPECT_TRUE(p == p);
+ EXPECT_FALSE(p == c);
+ EXPECT_FALSE(p == p2);
+ EXPECT_FALSE(p == pnull);
+
+ EXPECT_FALSE(p == nullptr);
+ EXPECT_FALSE(nullptr == p);
+ EXPECT_TRUE(pnull == nullptr);
+ EXPECT_TRUE(nullptr == pnull);
+
+ // Operator!=.
+ EXPECT_FALSE(p != p);
+ EXPECT_TRUE(p != c);
+ EXPECT_TRUE(p != p2);
+ EXPECT_TRUE(p != pnull);
+
+ EXPECT_TRUE(p != nullptr);
+ EXPECT_TRUE(nullptr != p);
+ EXPECT_FALSE(pnull != nullptr);
+ EXPECT_FALSE(nullptr != pnull);
+
+ // Compare two scoped_ptr<T>.
+ EXPECT_EQ(p.get() < p2.get(), p < p2);
+ EXPECT_EQ(p.get() <= p2.get(), p <= p2);
+ EXPECT_EQ(p.get() > p2.get(), p > p2);
+ EXPECT_EQ(p.get() >= p2.get(), p >= p2);
+ EXPECT_EQ(p2.get() < p.get(), p2 < p);
+ EXPECT_EQ(p2.get() <= p.get(), p2 <= p);
+ EXPECT_EQ(p2.get() > p.get(), p2 > p);
+ EXPECT_EQ(p2.get() >= p.get(), p2 >= p);
+
+ // And convertible scoped_ptr<T> and scoped_ptr<U>.
+ EXPECT_EQ(p.get() < c.get(), p < c);
+ EXPECT_EQ(p.get() <= c.get(), p <= c);
+ EXPECT_EQ(p.get() > c.get(), p > c);
+ EXPECT_EQ(p.get() >= c.get(), p >= c);
+ EXPECT_EQ(c.get() < p.get(), c < p);
+ EXPECT_EQ(c.get() <= p.get(), c <= p);
+ EXPECT_EQ(c.get() > p.get(), c > p);
+ EXPECT_EQ(c.get() >= p.get(), c >= p);
+
+ // Compare to nullptr.
+ EXPECT_TRUE(p > nullptr);
+ EXPECT_FALSE(nullptr > p);
+ EXPECT_FALSE(pnull > nullptr);
+ EXPECT_FALSE(nullptr > pnull);
+
+ EXPECT_TRUE(p >= nullptr);
+ EXPECT_FALSE(nullptr >= p);
+ EXPECT_TRUE(pnull >= nullptr);
+ EXPECT_TRUE(nullptr >= pnull);
+
+ EXPECT_FALSE(p < nullptr);
+ EXPECT_TRUE(nullptr < p);
+ EXPECT_FALSE(pnull < nullptr);
+ EXPECT_FALSE(nullptr < pnull);
+
+ EXPECT_FALSE(p <= nullptr);
+ EXPECT_TRUE(nullptr <= p);
+ EXPECT_TRUE(pnull <= nullptr);
+ EXPECT_TRUE(nullptr <= pnull);
+};
+
+TEST(ScopedPtrTest, ArrayOperators) {
+ struct Parent {};
+ struct Child : public Parent {};
+
+ scoped_ptr<Parent[]> p(new Parent[1]);
+ scoped_ptr<Parent[]> p2(new Parent[1]);
+ scoped_ptr<Child[]> c(new Child[1]);
+ scoped_ptr<Parent[]> pnull;
+
+ // Operator==.
+ EXPECT_TRUE(p == p);
+ EXPECT_FALSE(p == c);
+ EXPECT_FALSE(p == p2);
+ EXPECT_FALSE(p == pnull);
+
+ EXPECT_FALSE(p == nullptr);
+ EXPECT_FALSE(nullptr == p);
+ EXPECT_TRUE(pnull == nullptr);
+ EXPECT_TRUE(nullptr == pnull);
+
+ // Operator!=.
+ EXPECT_FALSE(p != p);
+ EXPECT_TRUE(p != c);
+ EXPECT_TRUE(p != p2);
+ EXPECT_TRUE(p != pnull);
+
+ EXPECT_TRUE(p != nullptr);
+ EXPECT_TRUE(nullptr != p);
+ EXPECT_FALSE(pnull != nullptr);
+ EXPECT_FALSE(nullptr != pnull);
+
+ // Compare two scoped_ptr<T>.
+ EXPECT_EQ(p.get() < p2.get(), p < p2);
+ EXPECT_EQ(p.get() <= p2.get(), p <= p2);
+ EXPECT_EQ(p.get() > p2.get(), p > p2);
+ EXPECT_EQ(p.get() >= p2.get(), p >= p2);
+ EXPECT_EQ(p2.get() < p.get(), p2 < p);
+ EXPECT_EQ(p2.get() <= p.get(), p2 <= p);
+ EXPECT_EQ(p2.get() > p.get(), p2 > p);
+ EXPECT_EQ(p2.get() >= p.get(), p2 >= p);
+
+ // And convertible scoped_ptr<T> and scoped_ptr<U>.
+ EXPECT_EQ(p.get() < c.get(), p < c);
+ EXPECT_EQ(p.get() <= c.get(), p <= c);
+ EXPECT_EQ(p.get() > c.get(), p > c);
+ EXPECT_EQ(p.get() >= c.get(), p >= c);
+ EXPECT_EQ(c.get() < p.get(), c < p);
+ EXPECT_EQ(c.get() <= p.get(), c <= p);
+ EXPECT_EQ(c.get() > p.get(), c > p);
+ EXPECT_EQ(c.get() >= p.get(), c >= p);
+
+ // Compare to nullptr.
+ EXPECT_TRUE(p > nullptr);
+ EXPECT_FALSE(nullptr > p);
+ EXPECT_FALSE(pnull > nullptr);
+ EXPECT_FALSE(nullptr > pnull);
+
+ EXPECT_TRUE(p >= nullptr);
+ EXPECT_FALSE(nullptr >= p);
+ EXPECT_TRUE(pnull >= nullptr);
+ EXPECT_TRUE(nullptr >= pnull);
+
+ EXPECT_FALSE(p < nullptr);
+ EXPECT_TRUE(nullptr < p);
+ EXPECT_FALSE(pnull < nullptr);
+ EXPECT_FALSE(nullptr < pnull);
+
+ EXPECT_FALSE(p <= nullptr);
+ EXPECT_TRUE(nullptr <= p);
+ EXPECT_TRUE(pnull <= nullptr);
+ EXPECT_TRUE(nullptr <= pnull);
}
diff --git a/chromium/base/memory/scoped_ptr_unittest.nc b/chromium/base/memory/scoped_ptr_unittest.nc
index b62703c3390..10b45a1897e 100644
--- a/chromium/base/memory/scoped_ptr_unittest.nc
+++ b/chromium/base/memory/scoped_ptr_unittest.nc
@@ -2,8 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/basictypes.h"
+// This is a "No Compile Test" suite.
+// http://dev.chromium.org/developers/testing/no-compile-tests
+
#include "base/memory/scoped_ptr.h"
+
+#include <utility>
+
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
namespace {
@@ -19,31 +25,31 @@ class RefCountedClass : public base::RefCountedThreadSafe<RefCountedClass> {
} // namespace
-#if defined(NCTEST_NO_PASS_DOWNCAST) // [r"fatal error: no matching constructor for initialization of 'base::internal::scoped_ptr_impl<\(anonymous namespace\)::Child, base::DefaultDeleter<\(anonymous namespace\)::Child> >::Data'"]
+#if defined(NCTEST_NO_PASS_DOWNCAST) // [r"fatal error: no viable conversion from returned value of type 'scoped_ptr<\(anonymous namespace\)::Parent>' to function return type 'scoped_ptr<\(anonymous namespace\)::Child>'"]
scoped_ptr<Child> DowncastUsingPassAs(scoped_ptr<Parent> object) {
- return object.Pass();
+ return object;
}
-#elif defined(NCTEST_NO_REF_COUNTED_SCOPED_PTR) // [r"fatal error: static_assert failed \"T_is_refcounted_type_and_needs_scoped_refptr\""]
+#elif defined(NCTEST_NO_REF_COUNTED_SCOPED_PTR) // [r"fatal error: static_assert failed \"T is a refcounted type and needs a scoped_refptr\""]
// scoped_ptr<> should not work for ref-counted objects.
void WontCompile() {
scoped_ptr<RefCountedClass> x;
}
-#elif defined(NCTEST_NO_ARRAY_WITH_SIZE) // [r"fatal error: static_assert failed \"do_not_use_array_with_size_as_type\""]
+#elif defined(NCTEST_NO_ARRAY_WITH_SIZE) // [r"fatal error: static_assert failed \"scoped_ptr doesn't support array with size\""]
void WontCompile() {
scoped_ptr<int[10]> x;
}
-#elif defined(NCTEST_NO_PASS_FROM_ARRAY) // [r"fatal error: static_assert failed \"U_cannot_be_an_array\""]
+#elif defined(NCTEST_NO_PASS_FROM_ARRAY) // [r"fatal error: no viable overloaded '='"]
void WontCompile() {
scoped_ptr<int[]> a;
scoped_ptr<int*> b;
- b = a.Pass();
+ b = std::move(a);
}
#elif defined(NCTEST_NO_PASS_TO_ARRAY) // [r"fatal error: no viable overloaded '='"]
@@ -51,21 +57,21 @@ void WontCompile() {
void WontCompile() {
scoped_ptr<int*> a;
scoped_ptr<int[]> b;
- b = a.Pass();
+ b = std::move(a);
}
-#elif defined(NCTEST_NO_CONSTRUCT_FROM_ARRAY) // [r"fatal error: 'impl_' is a private member of 'scoped_ptr<int \[\], base::DefaultDeleter<int \[\]> >'"]
+#elif defined(NCTEST_NO_CONSTRUCT_FROM_ARRAY) // [r"fatal error: no matching constructor for initialization of 'scoped_ptr<int \*>'"]
void WontCompile() {
scoped_ptr<int[]> a;
- scoped_ptr<int*> b(a.Pass());
+ scoped_ptr<int*> b(std::move(a));
}
#elif defined(NCTEST_NO_CONSTRUCT_TO_ARRAY) // [r"fatal error: no matching constructor for initialization of 'scoped_ptr<int \[\]>'"]
void WontCompile() {
scoped_ptr<int*> a;
- scoped_ptr<int[]> b(a.Pass());
+ scoped_ptr<int[]> b(std::move(a));
}
#elif defined(NCTEST_NO_CONSTRUCT_SCOPED_PTR_ARRAY_FROM_NULL) // [r"is ambiguous"]
@@ -74,7 +80,7 @@ void WontCompile() {
scoped_ptr<int[]> x(NULL);
}
-#elif defined(NCTEST_NO_CONSTRUCT_SCOPED_PTR_ARRAY_FROM_DERIVED) // [r"fatal error: calling a private constructor of class 'scoped_ptr<\(anonymous namespace\)::Parent \[\], base::DefaultDeleter<\(anonymous namespace\)::Parent \[\]> >'"]
+#elif defined(NCTEST_NO_CONSTRUCT_SCOPED_PTR_ARRAY_FROM_DERIVED) // [r"fatal error: calling a private constructor of class 'scoped_ptr<\(anonymous namespace\)::Parent \[\], std::default_delete<\(anonymous namespace\)::Parent \[\]> >'"]
void WontCompile() {
scoped_ptr<Parent[]> x(new Child[1]);
@@ -87,7 +93,7 @@ void WontCompile() {
x.reset(NULL);
}
-#elif defined(NCTEST_NO_RESET_SCOPED_PTR_ARRAY_FROM_DERIVED) // [r"fatal error: 'reset' is a private member of 'scoped_ptr<\(anonymous namespace\)::Parent \[\], base::DefaultDeleter<\(anonymous namespace\)::Parent \[\]> >'"]
+#elif defined(NCTEST_NO_RESET_SCOPED_PTR_ARRAY_FROM_DERIVED) // [r"fatal error: 'reset' is a private member of 'scoped_ptr<\(anonymous namespace\)::Parent \[\], std::default_delete<\(anonymous namespace\)::Parent \[\]> >'"]
void WontCompile() {
scoped_ptr<Parent[]> x;
diff --git a/chromium/base/memory/scoped_vector.h b/chromium/base/memory/scoped_vector.h
index e1e5c722a4f..6730612abc6 100644
--- a/chromium/base/memory/scoped_vector.h
+++ b/chromium/base/memory/scoped_vector.h
@@ -5,9 +5,10 @@
#ifndef BASE_MEMORY_SCOPED_VECTOR_H_
#define BASE_MEMORY_SCOPED_VECTOR_H_
+#include <stddef.h>
+
#include <vector>
-#include "base/basictypes.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/move.h"
@@ -15,9 +16,12 @@
// ScopedVector wraps a vector deleting the elements from its
// destructor.
+//
+// TODO(http://crbug.com/554289): DEPRECATED: Use std::vector instead (now that
+// we have support for moveable types inside containers).
template <class T>
class ScopedVector {
- MOVE_ONLY_TYPE_FOR_CPP_03(ScopedVector, RValue)
+ MOVE_ONLY_TYPE_FOR_CPP_03(ScopedVector)
public:
typedef typename std::vector<T*>::allocator_type allocator_type;
@@ -36,10 +40,10 @@ class ScopedVector {
ScopedVector() {}
~ScopedVector() { clear(); }
- ScopedVector(RValue other) { swap(*other.object); }
+ ScopedVector(ScopedVector&& other) { swap(other); }
- ScopedVector& operator=(RValue rhs) {
- swap(*rhs.object);
+ ScopedVector& operator=(ScopedVector&& rhs) {
+ swap(rhs);
return *this;
}
diff --git a/chromium/base/memory/scoped_vector_unittest.cc b/chromium/base/memory/scoped_vector_unittest.cc
index 4dee9c9004e..8638ecee55e 100644
--- a/chromium/base/memory/scoped_vector_unittest.cc
+++ b/chromium/base/memory/scoped_vector_unittest.cc
@@ -4,8 +4,11 @@
#include "base/memory/scoped_vector.h"
+#include <utility>
+
#include "base/bind.h"
#include "base/callback.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -225,7 +228,7 @@ TEST(ScopedVectorTest, MoveConstruct) {
EXPECT_FALSE(scoped_vector.empty());
EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
- ScopedVector<LifeCycleObject> scoped_vector_copy(scoped_vector.Pass());
+ ScopedVector<LifeCycleObject> scoped_vector_copy(std::move(scoped_vector));
EXPECT_TRUE(scoped_vector.empty());
EXPECT_FALSE(scoped_vector_copy.empty());
EXPECT_TRUE(watcher.IsWatching(scoped_vector_copy.back()));
@@ -245,7 +248,7 @@ TEST(ScopedVectorTest, MoveAssign) {
EXPECT_FALSE(scoped_vector.empty());
EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
- scoped_vector_assign = scoped_vector.Pass();
+ scoped_vector_assign = std::move(scoped_vector);
EXPECT_TRUE(scoped_vector.empty());
EXPECT_FALSE(scoped_vector_assign.empty());
EXPECT_TRUE(watcher.IsWatching(scoped_vector_assign.back()));
@@ -275,7 +278,7 @@ class DeleteCounter {
template <typename T>
ScopedVector<T> PassThru(ScopedVector<T> scoper) {
- return scoper.Pass();
+ return scoper;
}
TEST(ScopedVectorTest, Passed) {
@@ -326,7 +329,7 @@ TEST(ScopedVectorTest, PushBackScopedPtr) {
EXPECT_EQ(0, delete_counter);
{
ScopedVector<DeleteCounter> v;
- v.push_back(elem.Pass());
+ v.push_back(std::move(elem));
EXPECT_EQ(0, delete_counter);
}
EXPECT_EQ(1, delete_counter);
diff --git a/chromium/base/memory/shared_memory.h b/chromium/base/memory/shared_memory.h
index 9de93d519d9..a94b399a6ae 100644
--- a/chromium/base/memory/shared_memory.h
+++ b/chromium/base/memory/shared_memory.h
@@ -5,22 +5,20 @@
#ifndef BASE_MEMORY_SHARED_MEMORY_H_
#define BASE_MEMORY_SHARED_MEMORY_H_
-#include "build/build_config.h"
+#include <stddef.h>
#include <string>
-#if defined(OS_POSIX)
-#include <stdio.h>
-#include <sys/types.h>
-#include <semaphore.h>
-#endif
-
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/memory/shared_memory_handle.h"
#include "base/process/process_handle.h"
+#include "build/build_config.h"
#if defined(OS_POSIX)
+#include <stdio.h>
+#include <sys/types.h>
+#include <semaphore.h>
#include "base/file_descriptor_posix.h"
#include "base/files/file_util.h"
#include "base/files/scoped_file.h"
@@ -31,36 +29,29 @@ namespace base {
class FilePath;
// Options for creating a shared memory object.
-struct SharedMemoryCreateOptions {
- SharedMemoryCreateOptions()
- : size(0),
- executable(false),
- share_read_only(false) {
-#if !defined(OS_MACOSX) || defined(OS_IOS)
- name_deprecated = nullptr;
- open_existing_deprecated = false;
-#endif
- }
+struct BASE_EXPORT SharedMemoryCreateOptions {
+ SharedMemoryCreateOptions();
-#if !defined(OS_MACOSX) || defined(OS_IOS)
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+ // The type of OS primitive that should back the SharedMemory object.
+ SharedMemoryHandle::Type type;
+#else
// DEPRECATED (crbug.com/345734):
// If NULL, the object is anonymous. This pointer is owned by the caller
// and must live through the call to Create().
const std::string* name_deprecated;
-#endif
- // Size of the shared memory object to be created.
- // When opening an existing object, this has no effect.
- size_t size;
-
-#if !defined(OS_MACOSX) || defined(OS_IOS)
// DEPRECATED (crbug.com/345734):
// If true, and the shared memory already exists, Create() will open the
// existing shared memory and ignore the size parameter. If false,
// shared memory must not exist. This flag is meaningless unless
// name_deprecated is non-NULL.
bool open_existing_deprecated;
-#endif
+#endif // defined(OS_MACOSX) && !defined(OS_IOS)
+
+ // Size of the shared memory object to be created.
+ // When opening an existing object, this has no effect.
+ size_t size;
// If true, mappings might need to be made executable later.
bool executable;
@@ -91,12 +82,14 @@ class BASE_EXPORT SharedMemory {
// that |read_only| matches the permissions of the handle.
SharedMemory(const SharedMemoryHandle& handle, bool read_only);
+#if defined(OS_WIN)
// Create a new SharedMemory object from an existing, open
// shared memory file that was created by a remote process and not shared
// to the current process.
SharedMemory(const SharedMemoryHandle& handle,
bool read_only,
ProcessHandle process);
+#endif
// Closes any open files.
~SharedMemory();
@@ -139,6 +132,16 @@ class BASE_EXPORT SharedMemory {
// Returns true on success and false on failure.
bool CreateAndMapAnonymous(size_t size);
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+ // These two methods are analogs of CreateAndMapAnonymous and CreateAnonymous
+ // that force the underlying OS primitive to be a POSIX fd. Do not add new
+ // uses of these methods unless absolutely necessary, since constructing a
+ // fd-backed SharedMemory object frequently takes 100ms+.
+ // http://crbug.com/466437.
+ bool CreateAndMapAnonymousPosix(size_t size);
+ bool CreateAnonymousPosix(size_t size);
+#endif // defined(OS_MACOSX) && !defined(OS_IOS)
+
// Creates an anonymous shared memory segment of size size.
// Returns true on success and false on failure.
bool CreateAnonymous(size_t size) {
@@ -279,6 +282,9 @@ class BASE_EXPORT SharedMemory {
ShareMode);
#if defined(OS_WIN)
+ // If true indicates this came from an external source so needs extra checks
+ // before being mapped.
+ bool external_section_;
std::wstring name_;
HANDLE mapped_file_;
#elif defined(OS_MACOSX) && !defined(OS_IOS)
diff --git a/chromium/base/memory/shared_memory_android.cc b/chromium/base/memory/shared_memory_android.cc
index 5ba1bd6a101..6f1d9cb874c 100644
--- a/chromium/base/memory/shared_memory_android.cc
+++ b/chromium/base/memory/shared_memory_android.cc
@@ -4,6 +4,7 @@
#include "base/memory/shared_memory.h"
+#include <stddef.h>
#include <sys/mman.h>
#include "base/logging.h"
diff --git a/chromium/base/memory/shared_memory_handle.h b/chromium/base/memory/shared_memory_handle.h
index 43950a253ad..f90553e2fe7 100644
--- a/chromium/base/memory/shared_memory_handle.h
+++ b/chromium/base/memory/shared_memory_handle.h
@@ -5,6 +5,8 @@
#ifndef BASE_MEMORY_SHARED_MEMORY_HANDLE_H_
#define BASE_MEMORY_SHARED_MEMORY_HANDLE_H_
+#include <stddef.h>
+
#include "build/build_config.h"
#if defined(OS_WIN)
@@ -75,12 +77,15 @@ class BASE_EXPORT SharedMemoryHandle {
#else
class BASE_EXPORT SharedMemoryHandle {
public:
+ // The values of these enums must not change, as they are used by the
+ // histogram OSX.SharedMemory.Mechanism.
enum Type {
// The SharedMemoryHandle is backed by a POSIX fd.
POSIX,
// The SharedMemoryHandle is backed by the Mach primitive "memory object".
MACH,
};
+ static const int TypeMax = 2;
// The format that should be used to transmit |Type| over the wire.
typedef int TypeWireFormat;
@@ -156,6 +161,9 @@ class BASE_EXPORT SharedMemoryHandle {
// Closes the underlying OS primitive.
void Close() const;
+ void SetOwnershipPassesToIPC(bool ownership_passes);
+ bool OwnershipPassesToIPC() const;
+
private:
// Shared code between copy constructor and operator=.
void CopyRelevantData(const SharedMemoryHandle& handle);
@@ -177,6 +185,12 @@ class BASE_EXPORT SharedMemoryHandle {
// The pid of the process in which |memory_object_| is usable. Only
// relevant if |memory_object_| is not |MACH_PORT_NULL|.
base::ProcessId pid_;
+
+ // Whether passing this object as a parameter to an IPC message passes
+ // ownership of |memory_object_| to the IPC stack. This is meant to mimic
+ // the behavior of the |auto_close| parameter of FileDescriptor.
+ // Defaults to |false|.
+ bool ownership_passes_to_ipc_;
};
};
};
diff --git a/chromium/base/memory/shared_memory_handle_mac.cc b/chromium/base/memory/shared_memory_handle_mac.cc
index 13af82dbd95..e8f772fc7f2 100644
--- a/chromium/base/memory/shared_memory_handle_mac.cc
+++ b/chromium/base/memory/shared_memory_handle_mac.cc
@@ -5,9 +5,11 @@
#include "base/memory/shared_memory_handle.h"
#include <mach/mach_vm.h>
+#include <stddef.h>
#include <sys/mman.h>
#include <unistd.h>
+#include "base/mac/mac_util.h"
#include "base/posix/eintr_wrapper.h"
namespace base {
@@ -44,12 +46,17 @@ SharedMemoryHandle::SharedMemoryHandle(mach_vm_size_t size) {
memory_object_ = named_right;
size_ = size;
pid_ = GetCurrentProcId();
+ ownership_passes_to_ipc_ = false;
}
SharedMemoryHandle::SharedMemoryHandle(mach_port_t memory_object,
mach_vm_size_t size,
base::ProcessId pid)
- : type_(MACH), memory_object_(memory_object), size_(size), pid_(pid) {}
+ : type_(MACH),
+ memory_object_(memory_object),
+ size_(size),
+ pid_(pid),
+ ownership_passes_to_ipc_(false) {}
SharedMemoryHandle::SharedMemoryHandle(const SharedMemoryHandle& handle)
: type_(handle.type_) {
@@ -171,6 +178,9 @@ bool SharedMemoryHandle::MapAt(off_t offset,
return *memory && *memory != reinterpret_cast<void*>(-1);
case SharedMemoryHandle::MACH:
+ // The flag VM_PROT_IS_MASK is only supported on OSX 10.7+.
+ DCHECK(mac::IsOSLionOrLater());
+
DCHECK_EQ(pid_, GetCurrentProcId());
kern_return_t kr = mach_vm_map(
mach_task_self(),
@@ -182,7 +192,7 @@ bool SharedMemoryHandle::MapAt(off_t offset,
offset,
FALSE, // Copy
VM_PROT_READ | (read_only ? 0 : VM_PROT_WRITE), // Current protection
- VM_PROT_READ | VM_PROT_WRITE, // Maximum protection
+ VM_PROT_WRITE | VM_PROT_READ | VM_PROT_IS_MASK, // Maximum protection
VM_INHERIT_NONE);
return kr == KERN_SUCCESS;
}
@@ -205,6 +215,16 @@ void SharedMemoryHandle::Close() const {
}
}
+void SharedMemoryHandle::SetOwnershipPassesToIPC(bool ownership_passes) {
+ DCHECK_EQ(type_, MACH);
+ ownership_passes_to_ipc_ = ownership_passes;
+}
+
+bool SharedMemoryHandle::OwnershipPassesToIPC() const {
+ DCHECK_EQ(type_, MACH);
+ return ownership_passes_to_ipc_;
+}
+
void SharedMemoryHandle::CopyRelevantData(const SharedMemoryHandle& handle) {
switch (type_) {
case POSIX:
@@ -214,6 +234,7 @@ void SharedMemoryHandle::CopyRelevantData(const SharedMemoryHandle& handle) {
memory_object_ = handle.memory_object_;
size_ = handle.size_;
pid_ = handle.pid_;
+ ownership_passes_to_ipc_ = handle.ownership_passes_to_ipc_;
break;
}
}
diff --git a/chromium/base/memory/shared_memory_mac.cc b/chromium/base/memory/shared_memory_mac.cc
index 084b7256fb4..6fc299da14a 100644
--- a/chromium/base/memory/shared_memory_mac.cc
+++ b/chromium/base/memory/shared_memory_mac.cc
@@ -4,8 +4,10 @@
#include "base/memory/shared_memory.h"
+#include <errno.h>
#include <fcntl.h>
#include <mach/mach_vm.h>
+#include <stddef.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -13,12 +15,17 @@
#include "base/files/file_util.h"
#include "base/files/scoped_file.h"
#include "base/logging.h"
+#include "base/mac/mac_util.h"
+#include "base/mac/scoped_mach_vm.h"
+#include "base/metrics/field_trial.h"
+#include "base/metrics/histogram_macros.h"
#include "base/posix/eintr_wrapper.h"
#include "base/posix/safe_strerror.h"
#include "base/process/process_metrics.h"
#include "base/profiler/scoped_tracker.h"
#include "base/scoped_generic.h"
#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
#if defined(OS_MACOSX)
#include "base/mac/foundation_util.h"
@@ -28,6 +35,81 @@ namespace base {
namespace {
+const char kTrialName[] = "MacMemoryMechanism";
+const char kTrialMach[] = "Mach";
+const char kTrialPosix[] = "Posix";
+
+SharedMemoryHandle::Type GetABTestMechanism() {
+ static bool found_group = false;
+ static SharedMemoryHandle::Type group = SharedMemoryHandle::MACH;
+
+ if (found_group)
+ return group;
+
+ const std::string group_name =
+ base::FieldTrialList::FindFullName(kTrialName);
+ if (group_name == kTrialMach) {
+ group = SharedMemoryHandle::MACH;
+ found_group = true;
+ } else if (group_name == kTrialPosix) {
+ group = SharedMemoryHandle::POSIX;
+ found_group = true;
+ } else {
+ group = SharedMemoryHandle::MACH;
+ }
+
+ return group;
+}
+
+// Emits a histogram entry indicating which type of SharedMemory was created.
+void EmitMechanism(SharedMemoryHandle::Type type) {
+ UMA_HISTOGRAM_ENUMERATION("OSX.SharedMemory.Mechanism", type,
+ SharedMemoryHandle::TypeMax);
+}
+
+// Returns whether the operation succeeded.
+// |new_handle| is an output variable, populated on success. The caller takes
+// ownership of the underlying memory object.
+// |handle| is the handle to copy.
+// If |handle| is already mapped, |mapped_addr| is its mapped location.
+// Otherwise, |mapped_addr| should be |nullptr|.
+bool MakeMachSharedMemoryHandleReadOnly(SharedMemoryHandle* new_handle,
+ SharedMemoryHandle handle,
+ void* mapped_addr) {
+ if (!handle.IsValid())
+ return false;
+
+ size_t size;
+ CHECK(handle.GetSize(&size));
+
+ // Map if necessary.
+ void* temp_addr = mapped_addr;
+ base::mac::ScopedMachVM scoper;
+ if (!temp_addr) {
+ // Intentionally lower current prot and max prot to |VM_PROT_READ|.
+ kern_return_t kr = mach_vm_map(
+ mach_task_self(), reinterpret_cast<mach_vm_address_t*>(&temp_addr),
+ size, 0, VM_FLAGS_ANYWHERE, handle.GetMemoryObject(), 0, FALSE,
+ VM_PROT_READ, VM_PROT_READ, VM_INHERIT_NONE);
+ if (kr != KERN_SUCCESS)
+ return false;
+ scoper.reset(reinterpret_cast<vm_address_t>(temp_addr),
+ mach_vm_round_page(size));
+ }
+
+ // Make new memory object.
+ mach_port_t named_right;
+ kern_return_t kr = mach_make_memory_entry_64(
+ mach_task_self(), reinterpret_cast<memory_object_size_t*>(&size),
+ reinterpret_cast<memory_object_offset_t>(temp_addr), VM_PROT_READ,
+ &named_right, MACH_PORT_NULL);
+ if (kr != KERN_SUCCESS)
+ return false;
+
+ *new_handle = SharedMemoryHandle(named_right, size, base::GetCurrentProcId());
+ return true;
+}
+
struct ScopedPathUnlinkerTraits {
static FilePath* InvalidValue() { return nullptr; }
@@ -94,6 +176,22 @@ bool CreateAnonymousSharedMemory(const SharedMemoryCreateOptions& options,
} // namespace
+SharedMemoryCreateOptions::SharedMemoryCreateOptions()
+ : type(SharedMemoryHandle::MACH),
+ size(0),
+ executable(false),
+ share_read_only(false) {
+ if (mac::IsOSLionOrLater()) {
+ // A/B test the mechanism. Once the experiment is over, this will always be
+ // set to SharedMemoryHandle::MACH.
+ // http://crbug.com/547261
+ type = GetABTestMechanism();
+ } else {
+ // Mach shared memory isn't supported on OSX 10.6 or older.
+ type = SharedMemoryHandle::POSIX;
+ }
+}
+
SharedMemory::SharedMemory()
: mapped_memory_mechanism_(SharedMemoryHandle::POSIX),
readonly_mapped_file_(-1),
@@ -111,20 +209,6 @@ SharedMemory::SharedMemory(const SharedMemoryHandle& handle, bool read_only)
read_only_(read_only),
requested_size_(0) {}
-SharedMemory::SharedMemory(const SharedMemoryHandle& handle,
- bool read_only,
- ProcessHandle process)
- : mapped_memory_mechanism_(SharedMemoryHandle::POSIX),
- readonly_mapped_file_(-1),
- mapped_size_(0),
- memory_(NULL),
- read_only_(read_only),
- requested_size_(0) {
- // We don't handle this case yet (note the ignored parameter); let's die if
- // someone comes calling.
- NOTREACHED();
-}
-
SharedMemory::~SharedMemory() {
Unmap();
Close();
@@ -166,6 +250,17 @@ bool SharedMemory::CreateAndMapAnonymous(size_t size) {
return CreateAnonymous(size) && Map(size);
}
+bool SharedMemory::CreateAndMapAnonymousPosix(size_t size) {
+ return CreateAnonymousPosix(size) && Map(size);
+}
+
+bool SharedMemory::CreateAnonymousPosix(size_t size) {
+ SharedMemoryCreateOptions options;
+ options.type = SharedMemoryHandle::POSIX;
+ options.size = size;
+ return Create(options);
+}
+
// static
bool SharedMemory::GetSizeFromSharedMemoryHandle(
const SharedMemoryHandle& handle,
@@ -187,9 +282,17 @@ bool SharedMemory::Create(const SharedMemoryCreateOptions& options) {
if (options.size > static_cast<size_t>(std::numeric_limits<int>::max()))
return false;
- // This function theoretically can block on the disk, but realistically
- // the temporary files we create will just go into the buffer cache
- // and be deleted before they ever make it out to disk.
+ EmitMechanism(options.type);
+
+ if (options.type == SharedMemoryHandle::MACH) {
+ shm_ = SharedMemoryHandle(options.size);
+ requested_size_ = options.size;
+ return shm_.IsValid();
+ }
+
+ // This function theoretically can block on the disk. Both profiling of real
+ // users and local instrumentation shows that this is a real problem.
+ // https://code.google.com/p/chromium/issues/detail?id=466437
base::ThreadRestrictions::ScopedAllowIO allow_io;
ScopedFILE fp;
@@ -216,7 +319,7 @@ bool SharedMemory::Create(const SharedMemoryCreateOptions& options) {
}
requested_size_ = options.size;
- return PrepareMapFile(fp.Pass(), readonly_fd.Pass());
+ return PrepareMapFile(std::move(fp), std::move(readonly_fd));
}
bool SharedMemory::MapAt(off_t offset, size_t bytes) {
@@ -247,15 +350,17 @@ bool SharedMemory::Unmap() {
switch (mapped_memory_mechanism_) {
case SharedMemoryHandle::POSIX:
munmap(memory_, mapped_size_);
- memory_ = NULL;
- mapped_size_ = 0;
- return true;
+ break;
case SharedMemoryHandle::MACH:
mach_vm_deallocate(mach_task_self(),
reinterpret_cast<mach_vm_address_t>(memory_),
mapped_size_);
- return true;
+ break;
}
+
+ memory_ = NULL;
+ mapped_size_ = 0;
+ return true;
}
SharedMemoryHandle SharedMemory::handle() const {
@@ -322,7 +427,31 @@ bool SharedMemory::ShareToProcessCommon(ProcessHandle process,
SharedMemoryHandle* new_handle,
bool close_self,
ShareMode share_mode) {
- DCHECK_NE(shm_.GetType(), SharedMemoryHandle::MACH);
+ if (shm_.GetType() == SharedMemoryHandle::MACH) {
+ DCHECK(shm_.IsValid());
+
+ bool success = false;
+ switch (share_mode) {
+ case SHARE_CURRENT_MODE:
+ *new_handle = shm_.Duplicate();
+ success = true;
+ break;
+ case SHARE_READONLY:
+ success = MakeMachSharedMemoryHandleReadOnly(new_handle, shm_, memory_);
+ break;
+ }
+
+ if (success)
+ new_handle->SetOwnershipPassesToIPC(true);
+
+ if (close_self) {
+ Unmap();
+ Close();
+ }
+
+ return success;
+ }
+
int handle_to_dup = -1;
switch (share_mode) {
case SHARE_CURRENT_MODE:
@@ -338,6 +467,10 @@ bool SharedMemory::ShareToProcessCommon(ProcessHandle process,
const int new_fd = HANDLE_EINTR(dup(handle_to_dup));
if (new_fd < 0) {
+ if (close_self) {
+ Unmap();
+ Close();
+ }
DPLOG(ERROR) << "dup() failed.";
return false;
}
diff --git a/chromium/base/memory/shared_memory_mac_unittest.cc b/chromium/base/memory/shared_memory_mac_unittest.cc
index 5e03670f963..bcb1f2b9669 100644
--- a/chromium/base/memory/shared_memory_mac_unittest.cc
+++ b/chromium/base/memory/shared_memory_mac_unittest.cc
@@ -5,10 +5,14 @@
#include <mach/mach.h>
#include <mach/mach_vm.h>
#include <servers/bootstrap.h>
+#include <stddef.h>
+#include <stdint.h>
#include "base/command_line.h"
+#include "base/mac/mac_util.h"
#include "base/mac/mach_logging.h"
#include "base/mac/scoped_mach_port.h"
+#include "base/macros.h"
#include "base/memory/shared_memory.h"
#include "base/process/process_handle.h"
#include "base/rand_util.h"
@@ -22,6 +26,46 @@ namespace base {
namespace {
+// Gets the current and maximum protection levels of the memory region.
+// Returns whether the operation was successful.
+// |current| and |max| are output variables only populated on success.
+bool GetProtections(void* address, size_t size, int* current, int* max) {
+ vm_region_info_t region_info;
+ mach_vm_address_t mem_address = reinterpret_cast<mach_vm_address_t>(address);
+ mach_vm_size_t mem_size = size;
+ vm_region_basic_info_64 basic_info;
+
+ region_info = reinterpret_cast<vm_region_recurse_info_t>(&basic_info);
+ vm_region_flavor_t flavor = VM_REGION_BASIC_INFO_64;
+ memory_object_name_t memory_object;
+ mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64;
+
+ kern_return_t kr =
+ mach_vm_region(mach_task_self(), &mem_address, &mem_size, flavor,
+ region_info, &count, &memory_object);
+ if (kr != KERN_SUCCESS) {
+ MACH_LOG(ERROR, kr) << "Failed to get region info.";
+ return false;
+ }
+
+ *current = basic_info.protection;
+ *max = basic_info.max_protection;
+ return true;
+}
+
+// Creates a new SharedMemory with the given |size|, filled with 'a'.
+scoped_ptr<SharedMemory> CreateSharedMemory(int size) {
+ SharedMemoryHandle shm(size);
+ if (!shm.IsValid()) {
+ LOG(ERROR) << "Failed to make SharedMemoryHandle";
+ return nullptr;
+ }
+ scoped_ptr<SharedMemory> shared_memory(new SharedMemory(shm, false));
+ shared_memory->Map(size);
+ memset(shared_memory->memory(), 'a', size);
+ return shared_memory;
+}
+
static const std::string g_service_switch_name = "service_name";
// Structs used to pass a mach port from client to server.
@@ -97,6 +141,7 @@ void SendMachPort(mach_port_t receiving_port,
send_hdr->msgh_remote_port = receiving_port;
send_hdr->msgh_local_port = MACH_PORT_NULL;
send_hdr->msgh_reserved = 0;
+ send_hdr->msgh_id = 0;
send_msg.body.msgh_descriptor_count = 1;
send_msg.data.name = port_to_send;
send_msg.data.disposition = disposition;
@@ -125,7 +170,7 @@ mach_port_t CommonChildProcessSetUp() {
mach_port_t client_port = MakeReceivingPort();
// Send the port that this process is listening on to the server.
- SendMachPort(server_port, client_port, MACH_MSG_TYPE_MAKE_SEND);
+ SendMachPort(server_port.get(), client_port, MACH_MSG_TYPE_MAKE_SEND);
return client_port;
}
@@ -160,7 +205,7 @@ class SharedMemoryMacMultiProcessTest : public MultiProcessTest {
service_name_ = CreateRandomServiceName();
server_port_.reset(BecomeMachServer(service_name_.c_str()));
child_process_ = SpawnChild(name);
- client_port_.reset(ReceiveMachPort(server_port_));
+ client_port_.reset(ReceiveMachPort(server_port_.get()));
}
static const int s_memory_size = 99999;
@@ -183,16 +228,17 @@ class SharedMemoryMacMultiProcessTest : public MultiProcessTest {
// Tests that content written to shared memory in the server process can be read
// by the child process.
TEST_F(SharedMemoryMacMultiProcessTest, MachBasedSharedMemory) {
+ // Mach-based SharedMemory isn't support on OSX 10.6.
+ if (mac::IsOSSnowLeopard())
+ return;
+
SetUpChild("MachBasedSharedMemoryClient");
- SharedMemoryHandle shm(s_memory_size);
- ASSERT_TRUE(shm.IsValid());
- SharedMemory shared_memory(shm, false);
- shared_memory.Map(s_memory_size);
- memset(shared_memory.memory(), 'a', s_memory_size);
+ scoped_ptr<SharedMemory> shared_memory(CreateSharedMemory(s_memory_size));
// Send the underlying memory object to the client process.
- SendMachPort(client_port_, shm.GetMemoryObject(), MACH_MSG_TYPE_COPY_SEND);
+ SendMachPort(client_port_.get(), shared_memory->handle().GetMemoryObject(),
+ MACH_MSG_TYPE_COPY_SEND);
int rv = -1;
ASSERT_TRUE(child_process_.WaitForExitWithTimeout(
TestTimeouts::action_timeout(), &rv));
@@ -202,7 +248,7 @@ TEST_F(SharedMemoryMacMultiProcessTest, MachBasedSharedMemory) {
MULTIPROCESS_TEST_MAIN(MachBasedSharedMemoryClient) {
mac::ScopedMachReceiveRight client_port(CommonChildProcessSetUp());
// The next mach port should be for a memory object.
- mach_port_t memory_object = ReceiveMachPort(client_port);
+ mach_port_t memory_object = ReceiveMachPort(client_port.get());
SharedMemoryHandle shm(memory_object,
SharedMemoryMacMultiProcessTest::s_memory_size,
GetCurrentProcId());
@@ -217,6 +263,10 @@ MULTIPROCESS_TEST_MAIN(MachBasedSharedMemoryClient) {
// Tests that mapping shared memory with an offset works correctly.
TEST_F(SharedMemoryMacMultiProcessTest, MachBasedSharedMemoryWithOffset) {
+ // Mach-based SharedMemory isn't support on OSX 10.6.
+ if (mac::IsOSSnowLeopard())
+ return;
+
SetUpChild("MachBasedSharedMemoryWithOffsetClient");
SharedMemoryHandle shm(s_memory_size);
@@ -231,7 +281,8 @@ TEST_F(SharedMemoryMacMultiProcessTest, MachBasedSharedMemoryWithOffset) {
memset(start + 2 * page_size, 'c', page_size);
// Send the underlying memory object to the client process.
- SendMachPort(client_port_, shm.GetMemoryObject(), MACH_MSG_TYPE_COPY_SEND);
+ SendMachPort(
+ client_port_.get(), shm.GetMemoryObject(), MACH_MSG_TYPE_COPY_SEND);
int rv = -1;
ASSERT_TRUE(child_process_.WaitForExitWithTimeout(
TestTimeouts::action_timeout(), &rv));
@@ -241,7 +292,7 @@ TEST_F(SharedMemoryMacMultiProcessTest, MachBasedSharedMemoryWithOffset) {
MULTIPROCESS_TEST_MAIN(MachBasedSharedMemoryWithOffsetClient) {
mac::ScopedMachReceiveRight client_port(CommonChildProcessSetUp());
// The next mach port should be for a memory object.
- mach_port_t memory_object = ReceiveMachPort(client_port);
+ mach_port_t memory_object = ReceiveMachPort(client_port.get());
SharedMemoryHandle shm(memory_object,
SharedMemoryMacMultiProcessTest::s_memory_size,
GetCurrentProcId());
@@ -261,6 +312,10 @@ MULTIPROCESS_TEST_MAIN(MachBasedSharedMemoryWithOffsetClient) {
// Tests that duplication and closing has the right effect on Mach reference
// counts.
TEST_F(SharedMemoryMacMultiProcessTest, MachDuplicateAndClose) {
+ // Mach-based SharedMemory isn't support on OSX 10.6.
+ if (mac::IsOSSnowLeopard())
+ return;
+
mach_msg_type_number_t active_name_count = GetActiveNameCount();
// Making a new SharedMemoryHandle increments the name count.
@@ -284,10 +339,29 @@ TEST_F(SharedMemoryMacMultiProcessTest, MachDuplicateAndClose) {
EXPECT_EQ(active_name_count, GetActiveNameCount());
}
+// Tests that Mach shared memory can be mapped and unmapped.
+TEST_F(SharedMemoryMacMultiProcessTest, MachUnmapMap) {
+ // Mach-based SharedMemory isn't support on OSX 10.6.
+ if (mac::IsOSSnowLeopard())
+ return;
+
+ mach_msg_type_number_t active_name_count = GetActiveNameCount();
+
+ scoped_ptr<SharedMemory> shared_memory = CreateSharedMemory(s_memory_size);
+ ASSERT_TRUE(shared_memory->Unmap());
+ ASSERT_TRUE(shared_memory->Map(s_memory_size));
+ shared_memory.reset();
+ EXPECT_EQ(active_name_count, GetActiveNameCount());
+}
+
// Tests that passing a SharedMemoryHandle to a SharedMemory object also passes
// ownership, and that destroying the SharedMemory closes the SharedMemoryHandle
// as well.
TEST_F(SharedMemoryMacMultiProcessTest, MachSharedMemoryTakesOwnership) {
+ // Mach-based SharedMemory isn't support on OSX 10.6.
+ if (mac::IsOSSnowLeopard())
+ return;
+
mach_msg_type_number_t active_name_count = GetActiveNameCount();
// Making a new SharedMemoryHandle increments the name count.
@@ -307,17 +381,109 @@ TEST_F(SharedMemoryMacMultiProcessTest, MachSharedMemoryTakesOwnership) {
// Tests that the read-only flag works.
TEST_F(SharedMemoryMacMultiProcessTest, MachReadOnly) {
- SharedMemoryHandle shm(s_memory_size);
- ASSERT_TRUE(shm.IsValid());
- SharedMemory shared_memory(shm, false);
- shared_memory.Map(s_memory_size);
- memset(shared_memory.memory(), 'a', s_memory_size);
+ // Mach-based SharedMemory isn't support on OSX 10.6.
+ if (mac::IsOSSnowLeopard())
+ return;
+
+ scoped_ptr<SharedMemory> shared_memory(CreateSharedMemory(s_memory_size));
+
+ SharedMemoryHandle shm2 = shared_memory->handle().Duplicate();
+ ASSERT_TRUE(shm2.IsValid());
+ SharedMemory shared_memory2(shm2, true);
+ shared_memory2.Map(s_memory_size);
+ ASSERT_DEATH(memset(shared_memory2.memory(), 'b', s_memory_size), "");
+}
+
+// Tests that the method ShareToProcess() works.
+TEST_F(SharedMemoryMacMultiProcessTest, MachShareToProcess) {
+ // Mach-based SharedMemory isn't support on OSX 10.6.
+ if (mac::IsOSSnowLeopard())
+ return;
+
+ mach_msg_type_number_t active_name_count = GetActiveNameCount();
+
+ {
+ scoped_ptr<SharedMemory> shared_memory(CreateSharedMemory(s_memory_size));
+
+ SharedMemoryHandle shm2;
+ ASSERT_TRUE(shared_memory->ShareToProcess(GetCurrentProcId(), &shm2));
+ ASSERT_TRUE(shm2.IsValid());
+ SharedMemory shared_memory2(shm2, true);
+ shared_memory2.Map(s_memory_size);
+
+ ASSERT_EQ(0, memcmp(shared_memory->memory(), shared_memory2.memory(),
+ s_memory_size));
+ }
- SharedMemoryHandle shm2 = shm.Duplicate();
+ EXPECT_EQ(active_name_count, GetActiveNameCount());
+}
+
+// Tests that the method ShareReadOnlyToProcess() creates a memory object that
+// is read only.
+TEST_F(SharedMemoryMacMultiProcessTest, MachShareToProcessReadonly) {
+ // Mach-based SharedMemory isn't support on OSX 10.6.
+ if (mac::IsOSSnowLeopard())
+ return;
+
+ scoped_ptr<SharedMemory> shared_memory(CreateSharedMemory(s_memory_size));
+
+ // Check the protection levels.
+ int current_prot, max_prot;
+ ASSERT_TRUE(GetProtections(shared_memory->memory(),
+ shared_memory->mapped_size(), &current_prot,
+ &max_prot));
+ ASSERT_EQ(VM_PROT_READ | VM_PROT_WRITE, current_prot);
+ ASSERT_EQ(VM_PROT_READ | VM_PROT_WRITE, max_prot);
+
+ // Make a new memory object.
+ SharedMemoryHandle shm2;
+ ASSERT_TRUE(shared_memory->ShareReadOnlyToProcess(GetCurrentProcId(), &shm2));
ASSERT_TRUE(shm2.IsValid());
- SharedMemory shared_memory2(shm, true);
+
+ // Mapping with |readonly| set to |false| should fail.
+ SharedMemory shared_memory2(shm2, false);
shared_memory2.Map(s_memory_size);
+ ASSERT_EQ(nullptr, shared_memory2.memory());
+
+ // Now trying mapping with |readonly| set to |true|.
+ SharedMemory shared_memory3(shm2.Duplicate(), true);
+ shared_memory3.Map(s_memory_size);
+ ASSERT_NE(nullptr, shared_memory3.memory());
+
+ // Check the protection levels.
+ ASSERT_TRUE(GetProtections(shared_memory3.memory(),
+ shared_memory3.mapped_size(), &current_prot,
+ &max_prot));
+ ASSERT_EQ(VM_PROT_READ, current_prot);
+ ASSERT_EQ(VM_PROT_READ, max_prot);
+
+ // The memory should still be readonly, since the underlying memory object
+ // is readonly.
ASSERT_DEATH(memset(shared_memory2.memory(), 'b', s_memory_size), "");
}
+// Tests that the method ShareReadOnlyToProcess() doesn't leak.
+TEST_F(SharedMemoryMacMultiProcessTest, MachShareToProcessReadonlyLeak) {
+ // Mach-based SharedMemory isn't support on OSX 10.6.
+ if (mac::IsOSSnowLeopard())
+ return;
+
+ mach_msg_type_number_t active_name_count = GetActiveNameCount();
+
+ {
+ scoped_ptr<SharedMemory> shared_memory(CreateSharedMemory(s_memory_size));
+
+ SharedMemoryHandle shm2;
+ ASSERT_TRUE(
+ shared_memory->ShareReadOnlyToProcess(GetCurrentProcId(), &shm2));
+ ASSERT_TRUE(shm2.IsValid());
+
+ // Intentionally map with |readonly| set to |false|.
+ SharedMemory shared_memory2(shm2, false);
+ shared_memory2.Map(s_memory_size);
+ }
+
+ EXPECT_EQ(active_name_count, GetActiveNameCount());
+}
+
} // namespace base
diff --git a/chromium/base/memory/shared_memory_nacl.cc b/chromium/base/memory/shared_memory_nacl.cc
index 41416a1d7f8..a329cd19837 100644
--- a/chromium/base/memory/shared_memory_nacl.cc
+++ b/chromium/base/memory/shared_memory_nacl.cc
@@ -6,6 +6,7 @@
#include <errno.h>
#include <fcntl.h>
+#include <stddef.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -16,6 +17,13 @@
namespace base {
+SharedMemoryCreateOptions::SharedMemoryCreateOptions()
+ : name_deprecated(nullptr),
+ open_existing_deprecated(false),
+ size(0),
+ executable(false),
+ share_read_only(false) {}
+
SharedMemory::SharedMemory()
: mapped_file_(-1),
mapped_size_(0),
@@ -32,17 +40,6 @@ SharedMemory::SharedMemory(const SharedMemoryHandle& handle, bool read_only)
requested_size_(0) {
}
-SharedMemory::SharedMemory(const SharedMemoryHandle& handle,
- bool read_only,
- ProcessHandle process)
- : mapped_file_(handle.fd),
- mapped_size_(0),
- memory_(NULL),
- read_only_(read_only),
- requested_size_(0) {
- NOTREACHED();
-}
-
SharedMemory::~SharedMemory() {
Unmap();
Close();
diff --git a/chromium/base/memory/shared_memory_posix.cc b/chromium/base/memory/shared_memory_posix.cc
index 96344c6c877..d55c2df28bd 100644
--- a/chromium/base/memory/shared_memory_posix.cc
+++ b/chromium/base/memory/shared_memory_posix.cc
@@ -4,7 +4,9 @@
#include "base/memory/shared_memory.h"
+#include <errno.h>
#include <fcntl.h>
+#include <stddef.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -18,6 +20,7 @@
#include "base/profiler/scoped_tracker.h"
#include "base/scoped_generic.h"
#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
#if defined(OS_ANDROID)
#include "base/os_compat_android.h"
@@ -97,6 +100,13 @@ bool CreateAnonymousSharedMemory(const SharedMemoryCreateOptions& options,
#endif // !defined(OS_ANDROID)
}
+SharedMemoryCreateOptions::SharedMemoryCreateOptions()
+ : name_deprecated(nullptr),
+ open_existing_deprecated(false),
+ size(0),
+ executable(false),
+ share_read_only(false) {}
+
SharedMemory::SharedMemory()
: mapped_file_(-1),
readonly_mapped_file_(-1),
@@ -115,20 +125,6 @@ SharedMemory::SharedMemory(const SharedMemoryHandle& handle, bool read_only)
requested_size_(0) {
}
-SharedMemory::SharedMemory(const SharedMemoryHandle& handle,
- bool read_only,
- ProcessHandle process)
- : mapped_file_(handle.fd),
- readonly_mapped_file_(-1),
- mapped_size_(0),
- memory_(NULL),
- read_only_(read_only),
- requested_size_(0) {
- // We don't handle this case yet (note the ignored parameter); let's die if
- // someone comes calling.
- NOTREACHED();
-}
-
SharedMemory::~SharedMemory() {
Unmap();
Close();
@@ -303,7 +299,7 @@ bool SharedMemory::Create(const SharedMemoryCreateOptions& options) {
return false;
}
- return PrepareMapFile(fp.Pass(), readonly_fd.Pass());
+ return PrepareMapFile(std::move(fp), std::move(readonly_fd));
}
// Our current implementation of shmem is with mmap()ing of files.
@@ -335,7 +331,7 @@ bool SharedMemory::Open(const std::string& name, bool read_only) {
DPLOG(ERROR) << "open(\"" << path.value() << "\", O_RDONLY) failed";
return false;
}
- return PrepareMapFile(fp.Pass(), readonly_fd.Pass());
+ return PrepareMapFile(std::move(fp), std::move(readonly_fd));
}
#endif // !defined(OS_ANDROID)
@@ -485,6 +481,10 @@ bool SharedMemory::ShareToProcessCommon(ProcessHandle process,
const int new_fd = HANDLE_EINTR(dup(handle_to_dup));
if (new_fd < 0) {
+ if (close_self) {
+ Unmap();
+ Close();
+ }
DPLOG(ERROR) << "dup() failed.";
return false;
}
diff --git a/chromium/base/memory/shared_memory_unittest.cc b/chromium/base/memory/shared_memory_unittest.cc
index 86fb3ac7547..226c5a79281 100644
--- a/chromium/base/memory/shared_memory_unittest.cc
+++ b/chromium/base/memory/shared_memory_unittest.cc
@@ -2,10 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
+#include <stdint.h>
+
#include "base/atomicops.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/shared_memory.h"
+#include "base/memory/shared_memory_handle.h"
#include "base/process/kill.h"
#include "base/rand_util.h"
#include "base/strings/string_number_conversions.h"
@@ -13,6 +17,7 @@
#include "base/test/multiprocess_test.h"
#include "base/threading/platform_thread.h"
#include "base/time/time.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/multiprocess_func_list.h"
@@ -39,7 +44,7 @@ namespace {
// Verify that each thread's value in the shared memory is always correct.
class MultipleThreadMain : public PlatformThread::Delegate {
public:
- explicit MultipleThreadMain(int16 id) : id_(id) {}
+ explicit MultipleThreadMain(int16_t id) : id_(id) {}
~MultipleThreadMain() override {}
static void CleanUp() {
@@ -49,7 +54,7 @@ class MultipleThreadMain : public PlatformThread::Delegate {
// PlatformThread::Delegate interface.
void ThreadMain() override {
- const uint32 kDataSize = 1024;
+ const uint32_t kDataSize = 1024;
SharedMemory memory;
bool rv = memory.CreateNamedDeprecated(s_test_name_, true, kDataSize);
EXPECT_TRUE(rv);
@@ -70,14 +75,14 @@ class MultipleThreadMain : public PlatformThread::Delegate {
}
private:
- int16 id_;
+ int16_t id_;
- static const char* const s_test_name_;
+ static const char s_test_name_[];
DISALLOW_COPY_AND_ASSIGN(MultipleThreadMain);
};
-const char* const MultipleThreadMain::s_test_name_ =
+const char MultipleThreadMain::s_test_name_[] =
"SharedMemoryOpenThreadTest";
#endif // !defined(OS_MACOSX)
@@ -87,7 +92,7 @@ const char* const MultipleThreadMain::s_test_name_ =
// CreateNamedDeprecated(openExisting=true)
#if !defined(OS_ANDROID) && !defined(OS_MACOSX)
TEST(SharedMemoryTest, OpenClose) {
- const uint32 kDataSize = 1024;
+ const uint32_t kDataSize = 1024;
std::string test_name = "SharedMemoryOpenCloseTest";
// Open two handles to a memory segment, confirm that they are mapped
@@ -135,8 +140,8 @@ TEST(SharedMemoryTest, OpenClose) {
}
TEST(SharedMemoryTest, OpenExclusive) {
- const uint32 kDataSize = 1024;
- const uint32 kDataSize2 = 2048;
+ const uint32_t kDataSize = 1024;
+ const uint32_t kDataSize2 = 2048;
std::ostringstream test_name_stream;
test_name_stream << "SharedMemoryOpenExclusiveTest."
<< Time::Now().ToDoubleT();
@@ -248,7 +253,7 @@ TEST(SharedMemoryTest, MultipleThreads) {
thread_delegates.reset(new MultipleThreadMain*[numthreads]);
// Spawn the threads.
- for (int16 index = 0; index < numthreads; index++) {
+ for (int16_t index = 0; index < numthreads; index++) {
PlatformThreadHandle pth;
thread_delegates[index] = new MultipleThreadMain(index);
EXPECT_TRUE(PlatformThread::Create(0, thread_delegates[index], &pth));
@@ -272,7 +277,7 @@ TEST(SharedMemoryTest, AnonymousPrivate) {
int i, j;
int count = 4;
bool rv;
- const uint32 kDataSize = 8192;
+ const uint32_t kDataSize = 8192;
scoped_ptr<SharedMemory[]> memories(new SharedMemory[count]);
scoped_ptr<int*[]> pointers(new int*[count]);
@@ -316,6 +321,10 @@ TEST(SharedMemoryTest, ShareReadOnly) {
SharedMemoryCreateOptions options;
options.size = contents.size();
options.share_read_only = true;
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+ // The Mach functionality is tested in shared_memory_mac_unittest.cc.
+ options.type = SharedMemoryHandle::POSIX;
+#endif
ASSERT_TRUE(writable_shmem.Create(options));
ASSERT_TRUE(writable_shmem.Map(options.size));
memcpy(writable_shmem.memory(), contents.data(), contents.size());
@@ -420,13 +429,13 @@ TEST(SharedMemoryTest, ShareToSelf) {
}
TEST(SharedMemoryTest, MapAt) {
- ASSERT_TRUE(SysInfo::VMAllocationGranularity() >= sizeof(uint32));
+ ASSERT_TRUE(SysInfo::VMAllocationGranularity() >= sizeof(uint32_t));
const size_t kCount = SysInfo::VMAllocationGranularity();
- const size_t kDataSize = kCount * sizeof(uint32);
+ const size_t kDataSize = kCount * sizeof(uint32_t);
SharedMemory memory;
ASSERT_TRUE(memory.CreateAndMapAnonymous(kDataSize));
- uint32* ptr = static_cast<uint32*>(memory.memory());
+ uint32_t* ptr = static_cast<uint32_t*>(memory.memory());
ASSERT_NE(ptr, static_cast<void*>(NULL));
for (size_t i = 0; i < kCount; ++i) {
@@ -437,8 +446,8 @@ TEST(SharedMemoryTest, MapAt) {
off_t offset = SysInfo::VMAllocationGranularity();
ASSERT_TRUE(memory.MapAt(offset, kDataSize - offset));
- offset /= sizeof(uint32);
- ptr = static_cast<uint32*>(memory.memory());
+ offset /= sizeof(uint32_t);
+ ptr = static_cast<uint32_t*>(memory.memory());
ASSERT_NE(ptr, static_cast<void*>(NULL));
for (size_t i = offset; i < kCount; ++i) {
EXPECT_EQ(ptr[i - offset], i);
@@ -446,7 +455,7 @@ TEST(SharedMemoryTest, MapAt) {
}
TEST(SharedMemoryTest, MapTwice) {
- const uint32 kDataSize = 1024;
+ const uint32_t kDataSize = 1024;
SharedMemory memory;
bool rv = memory.CreateAndMapAnonymous(kDataSize);
EXPECT_TRUE(rv);
@@ -463,12 +472,16 @@ TEST(SharedMemoryTest, MapTwice) {
#if !defined(OS_IOS)
// Create a shared memory object, mmap it, and mprotect it to PROT_EXEC.
TEST(SharedMemoryTest, AnonymousExecutable) {
- const uint32 kTestSize = 1 << 16;
+ const uint32_t kTestSize = 1 << 16;
SharedMemory shared_memory;
SharedMemoryCreateOptions options;
options.size = kTestSize;
options.executable = true;
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+ // The Mach functionality is tested in shared_memory_mac_unittest.cc.
+ options.type = SharedMemoryHandle::POSIX;
+#endif
EXPECT_TRUE(shared_memory.Create(options));
EXPECT_TRUE(shared_memory.Map(shared_memory.requested_size()));
@@ -497,11 +510,15 @@ class ScopedUmaskSetter {
// Create a shared memory object, check its permissions.
TEST(SharedMemoryTest, FilePermissionsAnonymous) {
- const uint32 kTestSize = 1 << 8;
+ const uint32_t kTestSize = 1 << 8;
SharedMemory shared_memory;
SharedMemoryCreateOptions options;
options.size = kTestSize;
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+ // The Mach functionality is tested in shared_memory_mac_unittest.cc.
+ options.type = SharedMemoryHandle::POSIX;
+#endif
// Set a file mode creation mask that gives all permissions.
ScopedUmaskSetter permissive_mask(S_IWGRP | S_IWOTH);
@@ -524,6 +541,10 @@ TEST(SharedMemoryTest, FilePermissionsNamed) {
SharedMemory shared_memory;
SharedMemoryCreateOptions options;
options.size = kTestSize;
+#if defined(OS_MACOSX) && !defined(OS_IOS)
+ // The Mach functionality is tested in shared_memory_mac_unittest.cc.
+ options.type = SharedMemoryHandle::POSIX;
+#endif
// Set a file mode creation mask that gives all permissions.
ScopedUmaskSetter permissive_mask(S_IWGRP | S_IWOTH);
@@ -555,6 +576,55 @@ TEST(SharedMemoryTest, MapMinimumAlignment) {
shared_memory.Close();
}
+#if defined(OS_WIN)
+TEST(SharedMemoryTest, UnsafeImageSection) {
+ const char kTestSectionName[] = "UnsafeImageSection";
+ wchar_t path[MAX_PATH];
+ EXPECT_GT(::GetModuleFileName(nullptr, path, arraysize(path)), 0U);
+
+ // Map the current executable image to save us creating a new PE file on disk.
+ base::win::ScopedHandle file_handle(
+ ::CreateFile(path, GENERIC_READ, 0, nullptr, OPEN_EXISTING, 0, nullptr));
+ EXPECT_TRUE(file_handle.IsValid());
+ base::win::ScopedHandle section_handle(
+ ::CreateFileMappingA(file_handle.Get(), nullptr,
+ PAGE_READONLY | SEC_IMAGE, 0, 0, kTestSectionName));
+ EXPECT_TRUE(section_handle.IsValid());
+
+ // Check direct opening by name, from handle and duplicated from handle.
+ SharedMemory shared_memory_open;
+ EXPECT_TRUE(shared_memory_open.Open(kTestSectionName, true));
+ EXPECT_FALSE(shared_memory_open.Map(1));
+ EXPECT_EQ(nullptr, shared_memory_open.memory());
+
+ SharedMemory shared_memory_handle_dup(
+ SharedMemoryHandle(section_handle.Get(), ::GetCurrentProcessId()), true,
+ GetCurrentProcess());
+ EXPECT_FALSE(shared_memory_handle_dup.Map(1));
+ EXPECT_EQ(nullptr, shared_memory_handle_dup.memory());
+
+ SharedMemory shared_memory_handle_local(
+ SharedMemoryHandle(section_handle.Take(), ::GetCurrentProcessId()), true);
+ EXPECT_FALSE(shared_memory_handle_local.Map(1));
+ EXPECT_EQ(nullptr, shared_memory_handle_local.memory());
+
+ // Check that a handle without SECTION_QUERY also can't be mapped as it can't
+ // be checked.
+ SharedMemory shared_memory_handle_dummy;
+ SharedMemoryCreateOptions options;
+ options.size = 0x1000;
+ EXPECT_TRUE(shared_memory_handle_dummy.Create(options));
+ HANDLE handle_no_query;
+ EXPECT_TRUE(::DuplicateHandle(
+ ::GetCurrentProcess(), shared_memory_handle_dummy.handle().GetHandle(),
+ ::GetCurrentProcess(), &handle_no_query, FILE_MAP_READ, FALSE, 0));
+ SharedMemory shared_memory_handle_no_query(
+ SharedMemoryHandle(handle_no_query, ::GetCurrentProcessId()), true);
+ EXPECT_FALSE(shared_memory_handle_no_query.Map(1));
+ EXPECT_EQ(nullptr, shared_memory_handle_no_query.memory());
+}
+#endif // defined(OS_WIN)
+
// iOS does not allow multiple processes.
// Android ashmem does not support named shared memory.
// Mac SharedMemory does not support named shared memory. crbug.com/345734
@@ -587,12 +657,12 @@ class SharedMemoryProcessTest : public MultiProcessTest {
return errors;
}
- static const char* const s_test_name_;
- static const uint32 s_data_size_;
+ static const char s_test_name_[];
+ static const uint32_t s_data_size_;
};
-const char* const SharedMemoryProcessTest::s_test_name_ = "MPMem";
-const uint32 SharedMemoryProcessTest::s_data_size_ = 1024;
+const char SharedMemoryProcessTest::s_test_name_[] = "MPMem";
+const uint32_t SharedMemoryProcessTest::s_data_size_ = 1024;
TEST_F(SharedMemoryProcessTest, SharedMemoryAcrossProcesses) {
const int kNumTasks = 5;
diff --git a/chromium/base/memory/shared_memory_win.cc b/chromium/base/memory/shared_memory_win.cc
index 3eef9a94d33..b022a3e9751 100644
--- a/chromium/base/memory/shared_memory_win.cc
+++ b/chromium/base/memory/shared_memory_win.cc
@@ -5,6 +5,8 @@
#include "base/memory/shared_memory.h"
#include <aclapi.h>
+#include <stddef.h>
+#include <stdint.h>
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
@@ -14,6 +16,23 @@
namespace {
+typedef enum _SECTION_INFORMATION_CLASS {
+ SectionBasicInformation,
+} SECTION_INFORMATION_CLASS;
+
+typedef struct _SECTION_BASIC_INFORMATION {
+ PVOID BaseAddress;
+ ULONG Attributes;
+ LARGE_INTEGER Size;
+} SECTION_BASIC_INFORMATION, *PSECTION_BASIC_INFORMATION;
+
+typedef ULONG(__stdcall* NtQuerySectionType)(
+ HANDLE SectionHandle,
+ SECTION_INFORMATION_CLASS SectionInformationClass,
+ PVOID SectionInformation,
+ ULONG SectionInformationLength,
+ PULONG ResultLength);
+
// Returns the length of the memory section starting at the supplied address.
size_t GetMemorySectionSize(void* address) {
MEMORY_BASIC_INFORMATION memory_info;
@@ -23,29 +42,57 @@ size_t GetMemorySectionSize(void* address) {
static_cast<char*>(memory_info.AllocationBase));
}
+// Checks if the section object is safe to map. At the moment this just means
+// it's not an image section.
+bool IsSectionSafeToMap(HANDLE handle) {
+ static NtQuerySectionType nt_query_section_func;
+ if (!nt_query_section_func) {
+ nt_query_section_func = reinterpret_cast<NtQuerySectionType>(
+ ::GetProcAddress(::GetModuleHandle(L"ntdll.dll"), "NtQuerySection"));
+ DCHECK(nt_query_section_func);
+ }
+
+ // The handle must have SECTION_QUERY access for this to succeed.
+ SECTION_BASIC_INFORMATION basic_information = {};
+ ULONG status =
+ nt_query_section_func(handle, SectionBasicInformation, &basic_information,
+ sizeof(basic_information), nullptr);
+ if (status)
+ return false;
+ return (basic_information.Attributes & SEC_IMAGE) != SEC_IMAGE;
+}
+
} // namespace.
namespace base {
+SharedMemoryCreateOptions::SharedMemoryCreateOptions()
+ : name_deprecated(nullptr),
+ open_existing_deprecated(false),
+ size(0),
+ executable(false),
+ share_read_only(false) {}
+
SharedMemory::SharedMemory()
- : mapped_file_(NULL),
+ : external_section_(false),
+ mapped_file_(NULL),
mapped_size_(0),
memory_(NULL),
read_only_(false),
- requested_size_(0) {
-}
+ requested_size_(0) {}
SharedMemory::SharedMemory(const std::wstring& name)
- : name_(name),
+ : external_section_(false),
+ name_(name),
mapped_file_(NULL),
mapped_size_(0),
memory_(NULL),
read_only_(false),
- requested_size_(0) {
-}
+ requested_size_(0) {}
SharedMemory::SharedMemory(const SharedMemoryHandle& handle, bool read_only)
- : mapped_file_(handle.GetHandle()),
+ : external_section_(true),
+ mapped_file_(handle.GetHandle()),
mapped_size_(0),
memory_(NULL),
read_only_(read_only),
@@ -56,14 +103,16 @@ SharedMemory::SharedMemory(const SharedMemoryHandle& handle, bool read_only)
SharedMemory::SharedMemory(const SharedMemoryHandle& handle,
bool read_only,
ProcessHandle process)
- : mapped_file_(NULL),
+ : external_section_(true),
+ mapped_file_(NULL),
mapped_size_(0),
memory_(NULL),
read_only_(read_only),
requested_size_(0) {
- ::DuplicateHandle(
- process, handle.GetHandle(), GetCurrentProcess(), &mapped_file_,
- read_only_ ? FILE_MAP_READ : FILE_MAP_READ | FILE_MAP_WRITE, FALSE, 0);
+ DWORD access = FILE_MAP_READ | SECTION_QUERY;
+ ::DuplicateHandle(process, handle.GetHandle(), GetCurrentProcess(),
+ &mapped_file_,
+ read_only_ ? access : access | FILE_MAP_WRITE, FALSE, 0);
}
SharedMemory::~SharedMemory() {
@@ -146,7 +195,7 @@ bool SharedMemory::Create(const SharedMemoryCreateOptions& options) {
// So, we generate a random name when we need to enforce read-only.
uint64_t rand_values[4];
RandBytes(&rand_values, sizeof(rand_values));
- name_ = StringPrintf(L"CrSharedMem_%016x%016x%016x%016x",
+ name_ = StringPrintf(L"CrSharedMem_%016llx%016llx%016llx%016llx",
rand_values[0], rand_values[1],
rand_values[2], rand_values[3]);
}
@@ -163,6 +212,7 @@ bool SharedMemory::Create(const SharedMemoryCreateOptions& options) {
// If the file already existed, set requested_size_ to 0 to show that
// we don't know the size.
requested_size_ = 0;
+ external_section_ = true;
if (!options.open_existing_deprecated) {
Close();
return false;
@@ -179,17 +229,20 @@ bool SharedMemory::Delete(const std::string& name) {
bool SharedMemory::Open(const std::string& name, bool read_only) {
DCHECK(!mapped_file_);
-
+ DWORD access = FILE_MAP_READ | SECTION_QUERY;
+ if (!read_only)
+ access |= FILE_MAP_WRITE;
name_ = ASCIIToUTF16(name);
read_only_ = read_only;
- mapped_file_ = OpenFileMapping(
- read_only_ ? FILE_MAP_READ : FILE_MAP_READ | FILE_MAP_WRITE,
- false, name_.empty() ? NULL : name_.c_str());
- if (mapped_file_ != NULL) {
- // Note: size_ is not set in this case.
- return true;
- }
- return false;
+ mapped_file_ =
+ OpenFileMapping(access, false, name_.empty() ? nullptr : name_.c_str());
+ if (!mapped_file_)
+ return false;
+ // If a name specified assume it's an external section.
+ if (!name_.empty())
+ external_section_ = true;
+ // Note: size_ is not set in this case.
+ return true;
}
bool SharedMemory::MapAt(off_t offset, size_t bytes) {
@@ -202,12 +255,12 @@ bool SharedMemory::MapAt(off_t offset, size_t bytes) {
if (memory_)
return false;
- memory_ = MapViewOfFile(mapped_file_,
- read_only_ ? FILE_MAP_READ : FILE_MAP_READ |
- FILE_MAP_WRITE,
- static_cast<uint64>(offset) >> 32,
- static_cast<DWORD>(offset),
- bytes);
+ if (external_section_ && !IsSectionSafeToMap(mapped_file_))
+ return false;
+
+ memory_ = MapViewOfFile(
+ mapped_file_, read_only_ ? FILE_MAP_READ : FILE_MAP_READ | FILE_MAP_WRITE,
+ static_cast<uint64_t>(offset) >> 32, static_cast<DWORD>(offset), bytes);
if (memory_ != NULL) {
DCHECK_EQ(0U, reinterpret_cast<uintptr_t>(memory_) &
(SharedMemory::MAP_MINIMUM_ALIGNMENT - 1));
@@ -231,7 +284,7 @@ bool SharedMemory::ShareToProcessCommon(ProcessHandle process,
bool close_self,
ShareMode share_mode) {
*new_handle = SharedMemoryHandle();
- DWORD access = FILE_MAP_READ;
+ DWORD access = FILE_MAP_READ | SECTION_QUERY;
DWORD options = 0;
HANDLE mapped_file = mapped_file_;
HANDLE result;
diff --git a/chromium/base/memory/singleton.h b/chromium/base/memory/singleton.h
index 73196990022..79e4441a8ed 100644
--- a/chromium/base/memory/singleton.h
+++ b/chromium/base/memory/singleton.h
@@ -22,6 +22,7 @@
#include "base/at_exit.h"
#include "base/atomicops.h"
#include "base/base_export.h"
+#include "base/macros.h"
#include "base/memory/aligned_memory.h"
#include "base/threading/thread_restrictions.h"
diff --git a/chromium/base/memory/singleton_unittest.cc b/chromium/base/memory/singleton_unittest.cc
index e8788babdfd..a15145c8747 100644
--- a/chromium/base/memory/singleton_unittest.cc
+++ b/chromium/base/memory/singleton_unittest.cc
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stdint.h>
+
#include "base/at_exit.h"
#include "base/memory/singleton.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -9,7 +11,8 @@
namespace base {
namespace {
-COMPILE_ASSERT(DefaultSingletonTraits<int>::kRegisterAtExit == true, a);
+static_assert(DefaultSingletonTraits<int>::kRegisterAtExit == true,
+ "object must be deleted on process exit");
typedef void (*CallbackFunc)();
@@ -271,8 +274,8 @@ TEST_F(SingletonTest, Alignment) {
// Create some static singletons with increasing sizes and alignment
// requirements. By ordering this way, the linker will need to do some work to
// ensure proper alignment of the static data.
- AlignedTestSingleton<int32>* align4 =
- AlignedTestSingleton<int32>::GetInstance();
+ AlignedTestSingleton<int32_t>* align4 =
+ AlignedTestSingleton<int32_t>::GetInstance();
AlignedTestSingleton<AlignedMemory<32, 32> >* align32 =
AlignedTestSingleton<AlignedMemory<32, 32> >::GetInstance();
AlignedTestSingleton<AlignedMemory<128, 128> >* align128 =
diff --git a/chromium/base/memory/weak_ptr.h b/chromium/base/memory/weak_ptr.h
index 1230ead14bf..33d1e473624 100644
--- a/chromium/base/memory/weak_ptr.h
+++ b/chromium/base/memory/weak_ptr.h
@@ -59,15 +59,20 @@
// off to other task runners, e.g. to use to post tasks back to object on the
// bound sequence.
//
-// Invalidating the factory's WeakPtrs un-binds it from the sequence, allowing
-// it to be passed for a different sequence to use or delete it.
+// If all WeakPtr objects are destroyed or invalidated then the factory is
+// unbound from the SequencedTaskRunner/Thread. The WeakPtrFactory may then be
+// destroyed, or new WeakPtr objects may be used, from a different sequence.
+//
+// Thus, at least one WeakPtr object must exist and have been dereferenced on
+// the correct thread to enforce that other WeakPtr objects will enforce they
+// are used on the desired thread.
#ifndef BASE_MEMORY_WEAK_PTR_H_
#define BASE_MEMORY_WEAK_PTR_H_
-#include "base/basictypes.h"
#include "base/base_export.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/sequence_checker.h"
#include "base/template_util.h"
@@ -156,8 +161,8 @@ class SupportsWeakPtrBase {
static WeakPtr<Derived> StaticAsWeakPtr(Derived* t) {
typedef
is_convertible<Derived, internal::SupportsWeakPtrBase&> convertible;
- COMPILE_ASSERT(convertible::value,
- AsWeakPtr_argument_inherits_from_SupportsWeakPtr);
+ static_assert(convertible::value,
+ "AsWeakPtr argument must inherit from SupportsWeakPtr");
return AsWeakPtrImpl<Derived>(t, *t);
}
diff --git a/chromium/base/memory/weak_ptr_unittest.nc b/chromium/base/memory/weak_ptr_unittest.nc
index 2ab428d2abe..bad1c97ef9b 100644
--- a/chromium/base/memory/weak_ptr_unittest.nc
+++ b/chromium/base/memory/weak_ptr_unittest.nc
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+// This is a "No Compile Test" suite.
+// http://dev.chromium.org/developers/testing/no-compile-tests
+
#include "base/memory/weak_ptr.h"
namespace base {
@@ -112,14 +115,14 @@ void WontCompile() {
WeakPtr<Unrelated> ptr = AsWeakPtr<Unrelated>(&f);
}
-#elif defined(NCTEST_COMPLETELY_UNRELATED_HELPER) // [r"fatal error: static_assert failed \"AsWeakPtr_argument_inherits_from_SupportsWeakPtr\""]
+#elif defined(NCTEST_COMPLETELY_UNRELATED_HELPER) // [r"fatal error: static_assert failed \"AsWeakPtr argument must inherit from SupportsWeakPtr\""]
void WontCompile() {
Unrelated f;
WeakPtr<Unrelated> ptr = AsWeakPtr(&f);
}
-#elif defined(NCTEST_DERIVED_COMPLETELY_UNRELATED_HELPER) // [r"fatal error: static_assert failed \"AsWeakPtr_argument_inherits_from_SupportsWeakPtr\""]
+#elif defined(NCTEST_DERIVED_COMPLETELY_UNRELATED_HELPER) // [r"fatal error: static_assert failed \"AsWeakPtr argument must inherit from SupportsWeakPtr\""]
void WontCompile() {
DerivedUnrelated f;
diff --git a/chromium/base/message_loop/incoming_task_queue.cc b/chromium/base/message_loop/incoming_task_queue.cc
index eab14e9b707..d02bbc72952 100644
--- a/chromium/base/message_loop/incoming_task_queue.cc
+++ b/chromium/base/message_loop/incoming_task_queue.cc
@@ -11,6 +11,7 @@
#include "base/metrics/histogram.h"
#include "base/synchronization/waitable_event.h"
#include "base/time/time.h"
+#include "build/build_config.h"
namespace base {
namespace internal {
diff --git a/chromium/base/message_loop/incoming_task_queue.h b/chromium/base/message_loop/incoming_task_queue.h
index 7dd1e823129..e450aa164fa 100644
--- a/chromium/base/message_loop/incoming_task_queue.h
+++ b/chromium/base/message_loop/incoming_task_queue.h
@@ -6,6 +6,7 @@
#define BASE_MESSAGE_LOOP_INCOMING_TASK_QUEUE_H_
#include "base/base_export.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/pending_task.h"
#include "base/synchronization/lock.h"
diff --git a/chromium/base/message_loop/message_loop.cc b/chromium/base/message_loop/message_loop.cc
index a44f46863e4..e84765a0f7a 100644
--- a/chromium/base/message_loop/message_loop.cc
+++ b/chromium/base/message_loop/message_loop.cc
@@ -5,6 +5,7 @@
#include "base/message_loop/message_loop.h"
#include <algorithm>
+#include <utility>
#include "base/bind.h"
#include "base/compiler_specific.h"
@@ -21,6 +22,7 @@
#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
#include "base/tracked_objects.h"
+#include "build/build_config.h"
#if defined(OS_MACOSX)
#include "base/message_loop/message_pump_mac.h"
@@ -131,9 +133,11 @@ MessageLoop::MessageLoop(scoped_ptr<MessagePump> pump)
}
MessageLoop::~MessageLoop() {
- // current() could be NULL if this message loop is destructed before it is
- // bound to a thread.
- DCHECK(current() == this || !current());
+ // If |pump_| is non-null, this message loop has been bound and should be the
+ // current one on this thread. Otherwise, this loop is being destructed before
+ // it was bound to a thread, so a different message loop (or no loop at all)
+ // may be current.
+ DCHECK((pump_ && current() == this) || (!pump_ && current() != this));
// iOS just attaches to the loop, it doesn't Run it.
// TODO(stuartmorgan): Consider wiring up a Detach().
@@ -175,7 +179,8 @@ MessageLoop::~MessageLoop() {
task_runner_ = NULL;
// OK, now make it so that no one can find us.
- lazy_tls_ptr.Pointer()->Set(NULL);
+ if (current() == this)
+ lazy_tls_ptr.Pointer()->Set(nullptr);
}
// static
@@ -417,7 +422,7 @@ void MessageLoop::SetTaskRunner(
DCHECK_EQ(this, current());
DCHECK(task_runner->BelongsToCurrentThread());
DCHECK(!unbound_task_runner_);
- task_runner_ = task_runner.Pass();
+ task_runner_ = std::move(task_runner);
SetThreadTaskRunnerHandle();
}
diff --git a/chromium/base/message_loop/message_loop.h b/chromium/base/message_loop/message_loop.h
index 63a29f15e95..8ef8d6a21ff 100644
--- a/chromium/base/message_loop/message_loop.h
+++ b/chromium/base/message_loop/message_loop.h
@@ -9,10 +9,11 @@
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/callback_forward.h"
#include "base/debug/task_annotator.h"
+#include "base/gtest_prod_util.h"
#include "base/location.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/incoming_task_queue.h"
@@ -25,6 +26,7 @@
#include "base/synchronization/lock.h"
#include "base/time/time.h"
#include "base/tracking_info.h"
+#include "build/build_config.h"
// TODO(sky): these includes should not be necessary. Nuke them.
#if defined(OS_WIN)
@@ -242,9 +244,6 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate {
// Return as soon as all items that can be run are taken care of.
void RunUntilIdle();
- // TODO(jbates) remove this. crbug.com/131220. See QuitWhenIdle().
- void Quit() { QuitWhenIdle(); }
-
// Deprecated: use RunLoop instead.
//
// Signals the Run method to return when it becomes idle. It will continue to
@@ -268,9 +267,6 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate {
// to be processed before returning from Run.
void QuitNow();
- // TODO(jbates) remove this. crbug.com/131220. See QuitWhenIdleClosure().
- static Closure QuitClosure() { return QuitWhenIdleClosure(); }
-
// Deprecated: use RunLoop instead.
// Construct a Closure that will call QuitWhenIdle(). Useful to schedule an
// arbitrary MessageLoop to QuitWhenIdle.
@@ -408,6 +404,7 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate {
friend class internal::IncomingTaskQueue;
friend class ScheduleWorkTest;
friend class Thread;
+ FRIEND_TEST_ALL_PREFIXES(MessageLoopTest, DeleteUnboundLoop);
using MessagePumpFactoryCallback = Callback<scoped_ptr<MessagePump>()>;
@@ -607,8 +604,8 @@ class BASE_EXPORT MessageLoopForUI : public MessageLoop {
// Do not add any member variables to MessageLoopForUI! This is important b/c
// MessageLoopForUI is often allocated via MessageLoop(TYPE_UI). Any extra
// data that you need should be stored on the MessageLoop's pump_ instance.
-COMPILE_ASSERT(sizeof(MessageLoop) == sizeof(MessageLoopForUI),
- MessageLoopForUI_should_not_have_extra_member_variables);
+static_assert(sizeof(MessageLoop) == sizeof(MessageLoopForUI),
+ "MessageLoopForUI should not have extra member variables");
#endif // !defined(OS_NACL)
@@ -688,8 +685,8 @@ class BASE_EXPORT MessageLoopForIO : public MessageLoop {
// Do not add any member variables to MessageLoopForIO! This is important b/c
// MessageLoopForIO is often allocated via MessageLoop(TYPE_IO). Any extra
// data that you need should be stored on the MessageLoop's pump_ instance.
-COMPILE_ASSERT(sizeof(MessageLoop) == sizeof(MessageLoopForIO),
- MessageLoopForIO_should_not_have_extra_member_variables);
+static_assert(sizeof(MessageLoop) == sizeof(MessageLoopForIO),
+ "MessageLoopForIO should not have extra member variables");
} // namespace base
diff --git a/chromium/base/message_loop/message_loop_task_runner.h b/chromium/base/message_loop/message_loop_task_runner.h
index dc2947df26c..5e70b128b20 100644
--- a/chromium/base/message_loop/message_loop_task_runner.h
+++ b/chromium/base/message_loop/message_loop_task_runner.h
@@ -6,6 +6,7 @@
#define BASE_MESSAGE_LOOP_MESSAGE_LOOP_TASK_RUNNER_H_
#include "base/base_export.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/pending_task.h"
#include "base/single_thread_task_runner.h"
diff --git a/chromium/base/message_loop/message_loop_test.cc b/chromium/base/message_loop/message_loop_test.cc
index eca6c8f2452..ac50d648481 100644
--- a/chromium/base/message_loop/message_loop_test.cc
+++ b/chromium/base/message_loop/message_loop_test.cc
@@ -4,7 +4,12 @@
#include "base/message_loop/message_loop_test.h"
+#include <stddef.h>
+
+#include <utility>
+
#include "base/bind.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/run_loop.h"
#include "base/synchronization/waitable_event.h"
@@ -87,7 +92,7 @@ void RecordRunTimeFunc(Time* run_time, int* quit_counter) {
void RunTest_PostTask(MessagePumpFactory factory) {
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
// Add tests to message loop
scoped_refptr<Foo> foo(new Foo());
std::string a("a"), b("b"), c("c"), d("d");
@@ -104,8 +109,9 @@ void RunTest_PostTask(MessagePumpFactory factory) {
MessageLoop::current()->PostTask(FROM_HERE, Bind(
&Foo::Test2Mixed, foo.get(), a, &d));
// After all tests, post a message that will shut down the message loop
- MessageLoop::current()->PostTask(FROM_HERE, Bind(
- &MessageLoop::Quit, Unretained(MessageLoop::current())));
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ Bind(&MessageLoop::QuitWhenIdle, Unretained(MessageLoop::current())));
// Now kick things off
MessageLoop::current()->Run();
@@ -116,7 +122,7 @@ void RunTest_PostTask(MessagePumpFactory factory) {
void RunTest_PostDelayedTask_Basic(MessagePumpFactory factory) {
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
// Test that PostDelayedTask results in a delayed task.
@@ -139,7 +145,7 @@ void RunTest_PostDelayedTask_Basic(MessagePumpFactory factory) {
void RunTest_PostDelayedTask_InDelayOrder(MessagePumpFactory factory) {
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
// Test that two tasks with different delays run in the right order.
int num_tasks = 2;
@@ -164,7 +170,7 @@ void RunTest_PostDelayedTask_InDelayOrder(MessagePumpFactory factory) {
void RunTest_PostDelayedTask_InPostOrder(MessagePumpFactory factory) {
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
// Test that two tasks with the same delay run in the order in which they
// were posted.
@@ -194,7 +200,7 @@ void RunTest_PostDelayedTask_InPostOrder(MessagePumpFactory factory) {
void RunTest_PostDelayedTask_InPostOrder_2(MessagePumpFactory factory) {
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
// Test that a delayed task still runs after a normal tasks even if the
// normal tasks take a long time to run.
@@ -221,7 +227,7 @@ void RunTest_PostDelayedTask_InPostOrder_2(MessagePumpFactory factory) {
void RunTest_PostDelayedTask_InPostOrder_3(MessagePumpFactory factory) {
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
// Test that a delayed task still runs after a pile of normal tasks. The key
// difference between this test and the previous one is that here we return
@@ -249,7 +255,7 @@ void RunTest_PostDelayedTask_InPostOrder_3(MessagePumpFactory factory) {
void RunTest_PostDelayedTask_SharedTimer(MessagePumpFactory factory) {
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
// Test that the interval of the timer, used to run the next delayed task, is
// set to a value corresponding to when the next delayed task should run.
@@ -316,7 +322,7 @@ void RunTest_EnsureDeletion(MessagePumpFactory factory) {
bool b_was_deleted = false;
{
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
loop.PostTask(
FROM_HERE, Bind(&RecordDeletionProbe::Run,
new RecordDeletionProbe(NULL, &a_was_deleted)));
@@ -336,7 +342,7 @@ void RunTest_EnsureDeletion_Chain(MessagePumpFactory factory) {
bool c_was_deleted = false;
{
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
// The scoped_refptr for each of the below is held either by the chained
// RecordDeletionProbe, or the bound RecordDeletionProbe::Run() callback.
RecordDeletionProbe* a = new RecordDeletionProbe(NULL, &a_was_deleted);
@@ -363,7 +369,7 @@ void NestingFunc(int* depth) {
void RunTest_Nesting(MessagePumpFactory factory) {
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
int depth = 100;
MessageLoop::current()->PostTask(FROM_HERE,
@@ -471,7 +477,7 @@ void QuitFunc(TaskList* order, int cookie) {
}
void RunTest_RecursiveDenial1(MessagePumpFactory factory) {
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
EXPECT_TRUE(MessageLoop::current()->NestableTasksAllowed());
TaskList order;
@@ -518,7 +524,7 @@ void OrderedFunc(TaskList* order, int cookie) {
void RunTest_RecursiveDenial3(MessagePumpFactory factory) {
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
EXPECT_TRUE(MessageLoop::current()->NestableTasksAllowed());
TaskList order;
@@ -559,7 +565,7 @@ void RunTest_RecursiveDenial3(MessagePumpFactory factory) {
void RunTest_RecursiveSupport1(MessagePumpFactory factory) {
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
TaskList order;
MessageLoop::current()->PostTask(
@@ -592,7 +598,7 @@ void RunTest_RecursiveSupport1(MessagePumpFactory factory) {
// Tests that non nestable tasks run in FIFO if there are no nested loops.
void RunTest_NonNestableWithNoNesting(MessagePumpFactory factory) {
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
TaskList order;
@@ -634,7 +640,7 @@ void SleepFunc(TaskList* order, int cookie, TimeDelta delay) {
void RunTest_NonNestableInNestedLoop(MessagePumpFactory factory,
bool use_delayed) {
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
TaskList order;
@@ -702,7 +708,7 @@ void FuncThatQuitsNow() {
// Tests RunLoopQuit only quits the corresponding MessageLoop::Run.
void RunTest_QuitNow(MessagePumpFactory factory) {
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
TaskList order;
@@ -737,7 +743,7 @@ void RunTest_QuitNow(MessagePumpFactory factory) {
// Tests RunLoopQuit only quits the corresponding MessageLoop::Run.
void RunTest_RunLoopQuitTop(MessagePumpFactory factory) {
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
TaskList order;
@@ -767,7 +773,7 @@ void RunTest_RunLoopQuitTop(MessagePumpFactory factory) {
// Tests RunLoopQuit only quits the corresponding MessageLoop::Run.
void RunTest_RunLoopQuitNested(MessagePumpFactory factory) {
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
TaskList order;
@@ -797,7 +803,7 @@ void RunTest_RunLoopQuitNested(MessagePumpFactory factory) {
// Tests RunLoopQuit only quits the corresponding MessageLoop::Run.
void RunTest_RunLoopQuitBogus(MessagePumpFactory factory) {
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
TaskList order;
@@ -830,7 +836,7 @@ void RunTest_RunLoopQuitBogus(MessagePumpFactory factory) {
// Tests RunLoopQuit only quits the corresponding MessageLoop::Run.
void RunTest_RunLoopQuitDeep(MessagePumpFactory factory) {
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
TaskList order;
@@ -899,7 +905,7 @@ void RunTest_RunLoopQuitDeep(MessagePumpFactory factory) {
// Tests RunLoopQuit works before RunWithID.
void RunTest_RunLoopQuitOrderBefore(MessagePumpFactory factory) {
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
TaskList order;
@@ -920,7 +926,7 @@ void RunTest_RunLoopQuitOrderBefore(MessagePumpFactory factory) {
// Tests RunLoopQuit works during RunWithID.
void RunTest_RunLoopQuitOrderDuring(MessagePumpFactory factory) {
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
TaskList order;
@@ -947,7 +953,7 @@ void RunTest_RunLoopQuitOrderDuring(MessagePumpFactory factory) {
// Tests RunLoopQuit works after RunWithID.
void RunTest_RunLoopQuitOrderAfter(MessagePumpFactory factory) {
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
TaskList order;
@@ -1005,7 +1011,7 @@ void PostNTasksThenQuit(int posts_remaining) {
void RunTest_RecursivePosts(MessagePumpFactory factory) {
const int kNumTimes = 1 << 17;
scoped_ptr<MessagePump> pump(factory());
- MessageLoop loop(pump.Pass());
+ MessageLoop loop(std::move(pump));
loop.PostTask(FROM_HERE, Bind(&PostNTasksThenQuit, kNumTimes));
loop.Run();
}
diff --git a/chromium/base/message_loop/message_loop_unittest.cc b/chromium/base/message_loop/message_loop_unittest.cc
index 89f9a40a5ef..1a3a9257007 100644
--- a/chromium/base/message_loop/message_loop_unittest.cc
+++ b/chromium/base/message_loop/message_loop_unittest.cc
@@ -2,12 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
+#include <stdint.h>
+
#include <vector>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/compiler_specific.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
#include "base/message_loop/message_loop_test.h"
@@ -19,6 +23,7 @@
#include "base/thread_task_runner_handle.h"
#include "base/threading/platform_thread.h"
#include "base/threading/thread.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#if defined(OS_WIN)
@@ -336,7 +341,7 @@ void RunTest_RecursiveDenial2(MessageLoop::Type message_loop_type) {
WaitForSingleObject(event.Get(), INFINITE);
MessageLoop::current()->Run();
- ASSERT_EQ(order.Size(), 17);
+ ASSERT_EQ(17u, order.Size());
EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true));
EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false));
EXPECT_EQ(order.Get(2), TaskItem(MESSAGEBOX, 2, true));
@@ -380,7 +385,7 @@ void RunTest_RecursiveSupport2(MessageLoop::Type message_loop_type) {
WaitForSingleObject(event.Get(), INFINITE);
MessageLoop::current()->Run();
- ASSERT_EQ(order.Size(), 18);
+ ASSERT_EQ(18u, order.Size());
EXPECT_EQ(order.Get(0), TaskItem(RECURSIVE, 1, true));
EXPECT_EQ(order.Get(1), TaskItem(RECURSIVE, 1, false));
EXPECT_EQ(order.Get(2), TaskItem(MESSAGEBOX, 2, true));
@@ -522,7 +527,7 @@ void TestIOHandler::Init() {
DWORD read;
EXPECT_FALSE(ReadFile(file_.Get(), buffer_, size(), &read, context()));
- EXPECT_EQ(ERROR_IO_PENDING, GetLastError());
+ EXPECT_EQ(static_cast<DWORD>(ERROR_IO_PENDING), GetLastError());
if (wait_)
WaitForIO();
}
@@ -615,8 +620,9 @@ void RunTest_WaitForIO() {
DWORD written;
EXPECT_TRUE(WriteFile(server1.Get(), buffer, sizeof(buffer), &written, NULL));
PlatformThread::Sleep(2 * delay);
- EXPECT_EQ(WAIT_TIMEOUT, WaitForSingleObject(callback1_called.Get(), 0)) <<
- "handler1 has not been called";
+ EXPECT_EQ(static_cast<DWORD>(WAIT_TIMEOUT),
+ WaitForSingleObject(callback1_called.Get(), 0))
+ << "handler1 has not been called";
EXPECT_TRUE(WriteFile(server2.Get(), buffer, sizeof(buffer), &written, NULL));
@@ -907,8 +913,9 @@ TEST(MessageLoopTest, ThreadMainTaskRunner) {
&Foo::Test1ConstRef, foo.get(), a));
// Post quit task;
- MessageLoop::current()->PostTask(FROM_HERE, Bind(
- &MessageLoop::Quit, Unretained(MessageLoop::current())));
+ MessageLoop::current()->PostTask(
+ FROM_HERE,
+ Bind(&MessageLoop::QuitWhenIdle, Unretained(MessageLoop::current())));
// Now kick things off
MessageLoop::current()->Run();
@@ -983,7 +990,7 @@ LRESULT CALLBACK TestWndProcThunk(HWND hwnd, UINT message,
break;
}
EXPECT_TRUE(did_run);
- MessageLoop::current()->Quit();
+ MessageLoop::current()->QuitWhenIdle();
break;
}
return 0;
@@ -1034,4 +1041,15 @@ TEST(MessageLoopTest, OriginalRunnerWorks) {
EXPECT_EQ(1, foo->test_count());
}
+TEST(MessageLoopTest, DeleteUnboundLoop) {
+ // It should be possible to delete an unbound message loop on a thread which
+ // already has another active loop. This happens when thread creation fails.
+ MessageLoop loop;
+ scoped_ptr<MessageLoop> unbound_loop(MessageLoop::CreateUnbound(
+ MessageLoop::TYPE_DEFAULT, MessageLoop::MessagePumpFactoryCallback()));
+ unbound_loop.reset();
+ EXPECT_EQ(&loop, MessageLoop::current());
+ EXPECT_EQ(loop.task_runner(), ThreadTaskRunnerHandle::Get());
+}
+
} // namespace base
diff --git a/chromium/base/message_loop/message_pump.h b/chromium/base/message_loop/message_pump.h
index a2edb458a96..c53be804109 100644
--- a/chromium/base/message_loop/message_pump.h
+++ b/chromium/base/message_loop/message_pump.h
@@ -6,7 +6,6 @@
#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_H_
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/message_loop/timer_slack.h"
#include "base/threading/non_thread_safe.h"
diff --git a/chromium/base/message_loop/message_pump_android.h b/chromium/base/message_loop/message_pump_android.h
index d48050d21d1..795bd5e79ee 100644
--- a/chromium/base/message_loop/message_pump_android.h
+++ b/chromium/base/message_loop/message_pump_android.h
@@ -10,6 +10,7 @@
#include "base/android/scoped_java_ref.h"
#include "base/base_export.h"
#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "base/message_loop/message_pump.h"
namespace base {
diff --git a/chromium/base/message_loop/message_pump_default.cc b/chromium/base/message_loop/message_pump_default.cc
index 27c19e0227b..ed15395d56f 100644
--- a/chromium/base/message_loop/message_pump_default.cc
+++ b/chromium/base/message_loop/message_pump_default.cc
@@ -6,6 +6,7 @@
#include "base/logging.h"
#include "base/threading/thread_restrictions.h"
+#include "build/build_config.h"
#if defined(OS_MACOSX)
#include "base/mac/scoped_nsautorelease_pool.h"
diff --git a/chromium/base/message_loop/message_pump_default.h b/chromium/base/message_loop/message_pump_default.h
index 8aeaa62fcd2..4cd7cd17d56 100644
--- a/chromium/base/message_loop/message_pump_default.h
+++ b/chromium/base/message_loop/message_pump_default.h
@@ -6,6 +6,7 @@
#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_DEFAULT_H_
#include "base/base_export.h"
+#include "base/macros.h"
#include "base/message_loop/message_pump.h"
#include "base/synchronization/waitable_event.h"
#include "base/time/time.h"
diff --git a/chromium/base/message_loop/message_pump_glib.h b/chromium/base/message_loop/message_pump_glib.h
index 9f4457141d7..b94eeaf4304 100644
--- a/chromium/base/message_loop/message_pump_glib.h
+++ b/chromium/base/message_loop/message_pump_glib.h
@@ -6,6 +6,7 @@
#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_GLIB_H_
#include "base/base_export.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_pump.h"
#include "base/observer_list.h"
diff --git a/chromium/base/message_loop/message_pump_glib_unittest.cc b/chromium/base/message_loop/message_pump_glib_unittest.cc
index 7ddd4f08a04..cd12eba9f59 100644
--- a/chromium/base/message_loop/message_pump_glib_unittest.cc
+++ b/chromium/base/message_loop/message_pump_glib_unittest.cc
@@ -13,6 +13,7 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
diff --git a/chromium/base/message_loop/message_pump_io_ios.cc b/chromium/base/message_loop/message_pump_io_ios.cc
index cd5ffed4b99..9e6efeca193 100644
--- a/chromium/base/message_loop/message_pump_io_ios.cc
+++ b/chromium/base/message_loop/message_pump_io_ios.cc
@@ -22,7 +22,7 @@ bool MessagePumpIOSForIO::FileDescriptorWatcher::StopWatchingFileDescriptor() {
if (fdref_ == NULL)
return true;
- CFFileDescriptorDisableCallBacks(fdref_, callback_types_);
+ CFFileDescriptorDisableCallBacks(fdref_.get(), callback_types_);
if (pump_)
pump_->RemoveRunLoopSource(fd_source_);
fd_source_.reset();
@@ -39,7 +39,7 @@ void MessagePumpIOSForIO::FileDescriptorWatcher::Init(
CFRunLoopSourceRef fd_source,
bool is_persistent) {
DCHECK(fdref);
- DCHECK(!fdref_);
+ DCHECK(!fdref_.is_valid());
is_persistent_ = is_persistent;
fdref_.reset(fdref);
@@ -97,7 +97,7 @@ bool MessagePumpIOSForIO::WatchFileDescriptor(
callback_types |= kCFFileDescriptorWriteCallBack;
}
- CFFileDescriptorRef fdref = controller->fdref_;
+ CFFileDescriptorRef fdref = controller->fdref_.get();
if (fdref == NULL) {
base::ScopedCFTypeRef<CFFileDescriptorRef> scoped_fdref(
CFFileDescriptorCreate(
@@ -174,7 +174,7 @@ void MessagePumpIOSForIO::HandleFdIOEvent(CFFileDescriptorRef fdref,
void* context) {
FileDescriptorWatcher* controller =
static_cast<FileDescriptorWatcher*>(context);
- DCHECK_EQ(fdref, controller->fdref_);
+ DCHECK_EQ(fdref, controller->fdref_.get());
// Ensure that |fdref| will remain live for the duration of this function
// call even if |controller| is deleted or |StopWatchingFileDescriptor()| is
@@ -194,14 +194,14 @@ void MessagePumpIOSForIO::HandleFdIOEvent(CFFileDescriptorRef fdref,
// guarantees that |controller| has not been deleted.
if (callback_types & kCFFileDescriptorReadCallBack &&
CFFileDescriptorIsValid(fdref)) {
- DCHECK_EQ(fdref, controller->fdref_);
+ DCHECK_EQ(fdref, controller->fdref_.get());
controller->OnFileCanReadWithoutBlocking(fd, pump);
}
// Re-enable callbacks after the read/write if the file descriptor is still
// valid and the controller is persistent.
if (CFFileDescriptorIsValid(fdref) && controller->is_persistent_) {
- DCHECK_EQ(fdref, controller->fdref_);
+ DCHECK_EQ(fdref, controller->fdref_.get());
CFFileDescriptorEnableCallBacks(fdref, callback_types);
}
}
diff --git a/chromium/base/message_loop/message_pump_io_ios.h b/chromium/base/message_loop/message_pump_io_ios.h
index 317a59c5d9a..e1cbae6f92f 100644
--- a/chromium/base/message_loop/message_pump_io_ios.h
+++ b/chromium/base/message_loop/message_pump_io_ios.h
@@ -8,6 +8,7 @@
#include "base/base_export.h"
#include "base/mac/scoped_cffiledescriptorref.h"
#include "base/mac/scoped_cftyperef.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_pump_mac.h"
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 ba96f83bbf0..e51de70c0e0 100644
--- a/chromium/base/message_loop/message_pump_io_ios_unittest.cc
+++ b/chromium/base/message_loop/message_pump_io_ios_unittest.cc
@@ -6,6 +6,7 @@
#include <unistd.h>
+#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "base/posix/eintr_wrapper.h"
#include "base/threading/thread.h"
@@ -43,7 +44,7 @@ class MessagePumpIOSForIOTest : public testing::Test {
}
void HandleFdIOEvent(MessageLoopForIO::FileDescriptorWatcher* watcher) {
- MessagePumpIOSForIO::HandleFdIOEvent(watcher->fdref_,
+ MessagePumpIOSForIO::HandleFdIOEvent(watcher->fdref_.get(),
kCFFileDescriptorReadCallBack | kCFFileDescriptorWriteCallBack,
watcher);
}
diff --git a/chromium/base/message_loop/message_pump_libevent.cc b/chromium/base/message_loop/message_pump_libevent.cc
index 74602a7b320..c0a02b2b492 100644
--- a/chromium/base/message_loop/message_pump_libevent.cc
+++ b/chromium/base/message_loop/message_pump_libevent.cc
@@ -5,18 +5,19 @@
#include "base/message_loop/message_pump_libevent.h"
#include <errno.h>
-#include <fcntl.h>
#include <unistd.h>
#include "base/auto_reset.h"
#include "base/compiler_specific.h"
+#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/observer_list.h"
#include "base/posix/eintr_wrapper.h"
+#include "base/third_party/libevent/event.h"
#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
-#include "third_party/libevent/event.h"
+#include "build/build_config.h"
#if defined(OS_MACOSX)
#include "base/mac/scoped_nsautorelease_pool.h"
@@ -42,15 +43,6 @@
namespace base {
-// Return 0 on success
-// Too small a function to bother putting in a library?
-static int SetNonBlocking(int fd) {
- int flags = fcntl(fd, F_GETFL, 0);
- if (flags == -1)
- flags = 0;
- return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
-}
-
MessagePumpLibevent::FileDescriptorWatcher::FileDescriptorWatcher()
: event_(NULL),
pump_(NULL),
@@ -322,11 +314,11 @@ bool MessagePumpLibevent::Init() {
DLOG(ERROR) << "pipe() failed, errno: " << errno;
return false;
}
- if (SetNonBlocking(fds[0])) {
+ if (!SetNonBlocking(fds[0])) {
DLOG(ERROR) << "SetNonBlocking for pipe fd[0] failed, errno: " << errno;
return false;
}
- if (SetNonBlocking(fds[1])) {
+ if (!SetNonBlocking(fds[1])) {
DLOG(ERROR) << "SetNonBlocking for pipe fd[1] failed, errno: " << errno;
return false;
}
diff --git a/chromium/base/message_loop/message_pump_libevent.h b/chromium/base/message_loop/message_pump_libevent.h
index 8b815aea588..4d2f4f70372 100644
--- a/chromium/base/message_loop/message_pump_libevent.h
+++ b/chromium/base/message_loop/message_pump_libevent.h
@@ -5,8 +5,8 @@
#ifndef BASE_MESSAGE_LOOP_MESSAGE_PUMP_LIBEVENT_H_
#define BASE_MESSAGE_LOOP_MESSAGE_PUMP_LIBEVENT_H_
-#include "base/basictypes.h"
#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "base/message_loop/message_pump.h"
#include "base/observer_list.h"
#include "base/threading/thread_checker.h"
diff --git a/chromium/base/message_loop/message_pump_libevent_unittest.cc b/chromium/base/message_loop/message_pump_libevent_unittest.cc
index e911905abd7..eb30d535db6 100644
--- a/chromium/base/message_loop/message_pump_libevent_unittest.cc
+++ b/chromium/base/message_loop/message_pump_libevent_unittest.cc
@@ -15,9 +15,10 @@
#include "base/run_loop.h"
#include "base/synchronization/waitable_event.h"
#include "base/synchronization/waitable_event_watcher.h"
+#include "base/third_party/libevent/event.h"
#include "base/threading/thread.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/libevent/event.h"
namespace base {
diff --git a/chromium/base/message_loop/message_pump_mac.h b/chromium/base/message_loop/message_pump_mac.h
index c46f2612666..14b8377b908 100644
--- a/chromium/base/message_loop/message_pump_mac.h
+++ b/chromium/base/message_loop/message_pump_mac.h
@@ -32,12 +32,13 @@
#include "base/message_loop/message_pump.h"
-#include "base/basictypes.h"
#include <CoreFoundation/CoreFoundation.h>
+#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/timer_slack.h"
+#include "build/build_config.h"
#if defined(__OBJC__)
#if defined(OS_IOS)
diff --git a/chromium/base/message_loop/message_pump_mac.mm b/chromium/base/message_loop/message_pump_mac.mm
index 53e3363da57..b50ea687881 100644
--- a/chromium/base/message_loop/message_pump_mac.mm
+++ b/chromium/base/message_loop/message_pump_mac.mm
@@ -12,9 +12,11 @@
#include "base/logging.h"
#include "base/mac/call_with_eh_frame.h"
#include "base/mac/scoped_cftyperef.h"
+#include "base/macros.h"
#include "base/message_loop/timer_slack.h"
#include "base/run_loop.h"
#include "base/time/time.h"
+#include "build/build_config.h"
#if !defined(OS_IOS)
#import <AppKit/AppKit.h>
diff --git a/chromium/base/message_loop/message_pump_perftest.cc b/chromium/base/message_loop/message_pump_perftest.cc
index 9f76064ce38..789fc1f391b 100644
--- a/chromium/base/message_loop/message_pump_perftest.cc
+++ b/chromium/base/message_loop/message_pump_perftest.cc
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
+#include <stdint.h>
+
#include "base/bind.h"
#include "base/format_macros.h"
#include "base/memory/scoped_vector.h"
@@ -25,6 +28,11 @@ class ScheduleWorkTest : public testing::Test {
public:
ScheduleWorkTest() : counter_(0) {}
+ void SetUp() override {
+ if (base::ThreadTicks::IsSupported())
+ base::ThreadTicks::WaitUntilInitialized();
+ }
+
void Increment(uint64_t amount) { counter_ += amount; }
void Schedule(int index) {
@@ -79,14 +87,15 @@ class ScheduleWorkTest : public testing::Test {
target_->WaitUntilThreadStarted();
}
- ScopedVector<Thread> scheduling_threads;
+ std::vector<scoped_ptr<Thread>> scheduling_threads;
scheduling_times_.reset(new base::TimeDelta[num_scheduling_threads]);
scheduling_thread_times_.reset(new base::TimeDelta[num_scheduling_threads]);
min_batch_times_.reset(new base::TimeDelta[num_scheduling_threads]);
max_batch_times_.reset(new base::TimeDelta[num_scheduling_threads]);
for (int i = 0; i < num_scheduling_threads; ++i) {
- scheduling_threads.push_back(new Thread("posting thread"));
+ scheduling_threads.push_back(
+ make_scoped_ptr(new Thread("posting thread")));
scheduling_threads[i]->Start();
}
diff --git a/chromium/base/message_loop/message_pump_win.cc b/chromium/base/message_loop/message_pump_win.cc
index 14e432015e0..e7246fee16a 100644
--- a/chromium/base/message_loop/message_pump_win.cc
+++ b/chromium/base/message_loop/message_pump_win.cc
@@ -4,8 +4,10 @@
#include "base/message_loop/message_pump_win.h"
-#include <limits>
#include <math.h>
+#include <stdint.h>
+
+#include <limits>
#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram.h"
diff --git a/chromium/base/message_loop/message_pump_win.h b/chromium/base/message_loop/message_pump_win.h
index 9f1838d6e4f..257ccc92b19 100644
--- a/chromium/base/message_loop/message_pump_win.h
+++ b/chromium/base/message_loop/message_pump_win.h
@@ -10,7 +10,6 @@
#include <list>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/message_loop/message_pump.h"
#include "base/message_loop/message_pump_dispatcher.h"
#include "base/observer_list.h"
diff --git a/chromium/base/metrics/BUILD.gn b/chromium/base/metrics/BUILD.gn
deleted file mode 100644
index 159dfd49b29..00000000000
--- a/chromium/base/metrics/BUILD.gn
+++ /dev/null
@@ -1,45 +0,0 @@
-# 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",
- ]
-
- configs += [ "//base:base_implementation" ]
-
- deps = [
- "//base/debug",
- "//base/json",
- "//base/memory",
- ]
-
- visibility = [ "//base/*" ]
-}
diff --git a/chromium/base/metrics/bucket_ranges.cc b/chromium/base/metrics/bucket_ranges.cc
index 949c813e463..084cdd3293a 100644
--- a/chromium/base/metrics/bucket_ranges.cc
+++ b/chromium/base/metrics/bucket_ranges.cc
@@ -11,62 +11,70 @@
namespace base {
// Static table of checksums for all possible 8 bit bytes.
-const uint32 kCrcTable[256] = { 0x0, 0x77073096L, 0xee0e612cL,
-0x990951baL, 0x76dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0xedb8832L,
-0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x9b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
-0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 0x1adad47dL,
-0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL,
-0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L,
-0x4c69105eL, 0xd56041e4L, 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL,
-0xa50ab56bL, 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
-0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, 0xc8d75180L,
-0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL, 0x2802b89eL,
-0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL,
-0xb6662d3dL, 0x76dc4190L, 0x1db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L,
-0x6b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0xf00f934L, 0x9609a88eL,
-0xe10e9818L, 0x7f6a0dbbL, 0x86d3d2dL, 0x91646c97L, 0xe6635c01L, 0x6b6b51f4L,
-0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L,
-0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL,
-0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L,
-0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
-0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL,
-0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L,
-0x206f85b3L, 0xb966d409L, 0xce61e49fL, 0x5edef90eL, 0x29d9c998L, 0xb0d09822L,
-0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L,
-0x9abfb3b6L, 0x3b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x4db2615L,
-0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0xd6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL,
-0x9309ff9dL, 0xa00ae27L, 0x7d079eb1L, 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L,
-0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L,
-0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L,
-0x60b08ed5L, 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
-0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L,
-0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L, 0xcb61b38cL,
-0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L,
-0x5505262fL, 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L,
-0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
-0x26d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x5005713L, 0x95bf4a82L,
-0xe2b87a14L, 0x7bb12baeL, 0xcb61b38L, 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L,
-0xbdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL,
-0xf6b9265bL, 0x6fb077e1L, 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL,
-0x11010b5cL, 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
-0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 0x4969474dL,
-0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L,
-0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L,
-0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL,
-0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
-0x2d02ef8dL,
+const uint32_t kCrcTable[256] = {
+ 0x0, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x76dc419L,
+ 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0xedb8832L, 0x79dcb8a4L,
+ 0xe0d5e91eL, 0x97d2d988L, 0x9b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+ 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+ 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+ 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+ 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+ 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+ 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+ 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+ 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+ 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+ 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+ 0x1db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x6b6b51fL,
+ 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0xf00f934L, 0x9609a88eL,
+ 0xe10e9818L, 0x7f6a0dbbL, 0x86d3d2dL, 0x91646c97L, 0xe6635c01L,
+ 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+ 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+ 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+ 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+ 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+ 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+ 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+ 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+ 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+ 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+ 0x3b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x4db2615L,
+ 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0xd6d6a3eL, 0x7a6a5aa8L,
+ 0xe40ecf0bL, 0x9309ff9dL, 0xa00ae27L, 0x7d079eb1L, 0xf00f9344L,
+ 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+ 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+ 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+ 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+ 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+ 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+ 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+ 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+ 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+ 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+ 0x26d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x5005713L,
+ 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0xcb61b38L, 0x92d28e9bL,
+ 0xe5d5be0dL, 0x7cdcefb7L, 0xbdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+ 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+ 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+ 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+ 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+ 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+ 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+ 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+ 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+ 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+ 0x2d02ef8dL,
};
// We generate the CRC-32 using the low order bits to select whether to XOR in
// the reversed polynomial 0xedb88320L. This is nice and simple, and allows us
-// to keep the quotient in a uint32. Since we're not concerned about the nature
-// of corruptions (i.e., we don't care about bit sequencing, since we are
-// handling memory changes, which are more grotesque) so we don't bother to
-// get the CRC correct for big-endian vs little-ending calculations. All we
-// need is a nice hash, that tends to depend on all the bits of the sample, with
-// very little chance of changes in one place impacting changes in another
-// place.
-static uint32 Crc32(uint32 sum, HistogramBase::Sample value) {
+// to keep the quotient in a uint32_t. Since we're not concerned about the
+// nature of corruptions (i.e., we don't care about bit sequencing, since we are
+// handling memory changes, which are more grotesque) so we don't bother to get
+// the CRC correct for big-endian vs little-ending calculations. All we need is
+// a nice hash, that tends to depend on all the bits of the sample, with very
+// little chance of changes in one place impacting changes in another place.
+static uint32_t Crc32(uint32_t sum, HistogramBase::Sample value) {
// TODO(jar): Switch to false and watch stats.
const bool kUseRealCrc = true;
@@ -84,12 +92,12 @@ static uint32 Crc32(uint32 sum, HistogramBase::Sample value) {
// and we don't care about edge cases since we have an even number of bytes.
union {
HistogramBase::Sample range;
- uint16 ints[sizeof(HistogramBase::Sample) / 2];
+ uint16_t ints[sizeof(HistogramBase::Sample) / 2];
} converter;
DCHECK_EQ(sizeof(HistogramBase::Sample), sizeof(converter));
converter.range = value;
sum += converter.ints[0];
- sum = (sum << 16) ^ sum ^ (static_cast<uint32>(converter.ints[1]) << 11);
+ sum = (sum << 16) ^ sum ^ (static_cast<uint32_t>(converter.ints[1]) << 11);
sum += sum >> 11;
}
return sum;
@@ -107,9 +115,9 @@ void BucketRanges::set_range(size_t i, HistogramBase::Sample value) {
ranges_[i] = value;
}
-uint32 BucketRanges::CalculateChecksum() const {
+uint32_t BucketRanges::CalculateChecksum() const {
// Seed checksum.
- uint32 checksum = static_cast<uint32>(ranges_.size());
+ uint32_t checksum = static_cast<uint32_t>(ranges_.size());
for (size_t index = 0; index < ranges_.size(); ++index)
checksum = Crc32(checksum, ranges_[index]);
diff --git a/chromium/base/metrics/bucket_ranges.h b/chromium/base/metrics/bucket_ranges.h
index 6ea5849370c..c356195ba78 100644
--- a/chromium/base/metrics/bucket_ranges.h
+++ b/chromium/base/metrics/bucket_ranges.h
@@ -17,10 +17,15 @@
#ifndef BASE_METRICS_BUCKET_RANGES_H_
#define BASE_METRICS_BUCKET_RANGES_H_
+#include <stddef.h>
+#include <stdint.h>
+
#include <vector>
+#include <limits.h>
+
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/metrics/histogram_base.h"
namespace base {
@@ -35,8 +40,8 @@ class BASE_EXPORT BucketRanges {
size_t size() const { return ranges_.size(); }
HistogramBase::Sample range(size_t i) const { return ranges_[i]; }
void set_range(size_t i, HistogramBase::Sample value);
- uint32 checksum() const { return checksum_; }
- void set_checksum(uint32 checksum) { checksum_ = checksum; }
+ uint32_t checksum() const { return checksum_; }
+ void set_checksum(uint32_t checksum) { checksum_ = checksum; }
// A bucket is defined by a consecutive pair of entries in |ranges|, so there
// is one fewer bucket than there are ranges. For example, if |ranges| is
@@ -46,7 +51,7 @@ class BASE_EXPORT BucketRanges {
// Checksum methods to verify whether the ranges are corrupted (e.g. bad
// memory access).
- uint32 CalculateChecksum() const;
+ uint32_t CalculateChecksum() const;
bool HasValidChecksum() const;
void ResetChecksum();
@@ -62,16 +67,16 @@ class BASE_EXPORT BucketRanges {
// Checksum for the conntents of ranges_. Used to detect random over-writes
// of our data, and to quickly see if some other BucketRanges instance is
// possibly Equal() to this instance.
- // TODO(kaiwang): Consider change this to uint64. Because we see a lot of
+ // TODO(kaiwang): Consider change this to uint64_t. Because we see a lot of
// noise on UMA dashboard.
- uint32 checksum_;
+ uint32_t checksum_;
DISALLOW_COPY_AND_ASSIGN(BucketRanges);
};
//////////////////////////////////////////////////////////////////////////////
// Expose only for test.
-BASE_EXPORT_PRIVATE extern const uint32 kCrcTable[256];
+BASE_EXPORT extern const uint32_t kCrcTable[256];
} // namespace base
diff --git a/chromium/base/metrics/bucket_ranges_unittest.cc b/chromium/base/metrics/bucket_ranges_unittest.cc
index fc0699c7337..481054c5d28 100644
--- a/chromium/base/metrics/bucket_ranges_unittest.cc
+++ b/chromium/base/metrics/bucket_ranges_unittest.cc
@@ -4,6 +4,8 @@
#include "base/metrics/bucket_ranges.h"
+#include <stdint.h>
+
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
@@ -76,9 +78,9 @@ TEST(BucketRangesTest, Checksum) {
// http://www.w3.org/TR/PNG/#D-CRCAppendix.
TEST(BucketRangesTest, Crc32TableTest) {
for (int i = 0; i < 256; ++i) {
- uint32 checksum = i;
+ uint32_t checksum = i;
for (int j = 0; j < 8; ++j) {
- const uint32 kReversedPolynomial = 0xedb88320L;
+ const uint32_t kReversedPolynomial = 0xedb88320L;
if (checksum & 1)
checksum = kReversedPolynomial ^ (checksum >> 1);
else
diff --git a/chromium/base/metrics/field_trial.cc b/chromium/base/metrics/field_trial.cc
index 2ad7517a4bd..b417b056d24 100644
--- a/chromium/base/metrics/field_trial.cc
+++ b/chromium/base/metrics/field_trial.cc
@@ -9,7 +9,6 @@
#include "base/build_time.h"
#include "base/logging.h"
#include "base/rand_util.h"
-#include "base/sha1.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
@@ -18,6 +17,15 @@ namespace base {
namespace {
+// Define a separator character to use when creating a persistent form of an
+// instance. This is intended for use as a command line argument, passed to a
+// second process to mimic our state (i.e., provide the same group name).
+const char kPersistentStringSeparator = '/'; // Currently a slash.
+
+// Define a marker character to be used as a prefix to a trial name on the
+// command line which forces its activation.
+const char kActivationMarker = '*';
+
// Created a time value based on |year|, |month| and |day_of_month| parameters.
Time CreateTimeFromParams(int year, int month, int day_of_month) {
DCHECK_GT(year, 1970);
@@ -58,6 +66,45 @@ FieldTrial::Probability GetGroupBoundaryValue(
return std::min(result, divisor - 1);
}
+// Parses the --force-fieldtrials string |trials_string| into |entries|.
+// Returns true if the string was parsed correctly. On failure, the |entries|
+// array may end up being partially filled.
+bool ParseFieldTrialsString(const std::string& trials_string,
+ std::vector<FieldTrial::State>* entries) {
+ const StringPiece trials_string_piece(trials_string);
+
+ size_t next_item = 0;
+ while (next_item < trials_string.length()) {
+ size_t name_end = trials_string.find(kPersistentStringSeparator, next_item);
+ if (name_end == trials_string.npos || next_item == name_end)
+ return false;
+ size_t group_name_end =
+ trials_string.find(kPersistentStringSeparator, name_end + 1);
+ if (name_end + 1 == group_name_end)
+ return false;
+ if (group_name_end == trials_string.npos)
+ group_name_end = trials_string.length();
+
+ FieldTrial::State entry;
+ // Verify if the trial should be activated or not.
+ if (trials_string[next_item] == kActivationMarker) {
+ // Name cannot be only the indicator.
+ if (name_end - next_item == 1)
+ return false;
+ next_item++;
+ entry.activated = true;
+ }
+ entry.trial_name =
+ trials_string_piece.substr(next_item, name_end - next_item);
+ entry.group_name =
+ trials_string_piece.substr(name_end + 1, group_name_end - name_end - 1);
+ next_item = group_name_end + 1;
+
+ entries->push_back(entry);
+ }
+ return true;
+}
+
} // namespace
// statics
@@ -65,8 +112,6 @@ const int FieldTrial::kNotFinalized = -1;
const int FieldTrial::kDefaultGroupNumber = 0;
bool FieldTrial::enable_benchmarking_ = false;
-const char FieldTrialList::kPersistentStringSeparator('/');
-const char FieldTrialList::kActivationMarker('*');
int FieldTrialList::kNoExpirationYear = 0;
//------------------------------------------------------------------------------
@@ -75,6 +120,10 @@ int FieldTrialList::kNoExpirationYear = 0;
FieldTrial::EntropyProvider::~EntropyProvider() {
}
+FieldTrial::State::State() : activated(false) {}
+
+FieldTrial::State::~State() {}
+
void FieldTrial::Disable() {
DCHECK(!group_reported_);
enable_field_trial_ = false;
@@ -227,16 +276,12 @@ bool FieldTrial::GetActiveGroup(ActiveGroup* active_group) const {
return true;
}
-bool FieldTrial::GetState(FieldTrialState* field_trial_state) const {
+bool FieldTrial::GetState(State* field_trial_state) {
if (!enable_field_trial_)
return false;
+ FinalizeGroupChoice();
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->group_name = group_name_;
field_trial_state->activated = group_reported_;
return true;
}
@@ -303,7 +348,7 @@ FieldTrial* FieldTrialList::FactoryGetFieldTrialWithRandomizationSeed(
const int month,
const int day_of_month,
FieldTrial::RandomizationType randomization_type,
- uint32 randomization_seed,
+ uint32_t randomization_seed,
int* default_group_number) {
if (default_group_number)
*default_group_number = FieldTrial::kDefaultGroupNumber;
@@ -325,12 +370,11 @@ FieldTrial* FieldTrialList::FactoryGetFieldTrialWithRandomizationSeed(
// group number, so that it does not conflict with the |AppendGroup()|
// result for the chosen group.
const int kNonConflictingGroupNumber = -2;
- COMPILE_ASSERT(
+ static_assert(
kNonConflictingGroupNumber != FieldTrial::kDefaultGroupNumber,
- conflicting_default_group_number);
- COMPILE_ASSERT(
- kNonConflictingGroupNumber != FieldTrial::kNotFinalized,
- conflicting_default_group_number);
+ "The 'non-conflicting' group number conflicts");
+ static_assert(kNonConflictingGroupNumber != FieldTrial::kNotFinalized,
+ "The 'non-conflicting' group number conflicts");
*default_group_number = kNonConflictingGroupNumber;
}
}
@@ -418,7 +462,7 @@ void FieldTrialList::AllStatesToString(std::string* output) {
AutoLock auto_lock(global_->lock_);
for (const auto& registered : global_->registered_) {
- FieldTrial::FieldTrialState trial;
+ FieldTrial::State trial;
if (!registered.second->GetState(&trial))
continue;
DCHECK_EQ(std::string::npos,
@@ -427,9 +471,9 @@ void FieldTrialList::AllStatesToString(std::string* output) {
trial.group_name.find(kPersistentStringSeparator));
if (trial.activated)
output->append(1, kActivationMarker);
- output->append(trial.trial_name);
+ trial.trial_name.AppendToString(output);
output->append(1, kPersistentStringSeparator);
- output->append(trial.group_name);
+ trial.group_name.AppendToString(output);
output->append(1, kPersistentStringSeparator);
}
}
@@ -451,6 +495,24 @@ void FieldTrialList::GetActiveFieldTrialGroups(
}
// static
+void FieldTrialList::GetActiveFieldTrialGroupsFromString(
+ const std::string& trials_string,
+ FieldTrial::ActiveGroups* active_groups) {
+ std::vector<FieldTrial::State> entries;
+ if (!ParseFieldTrialsString(trials_string, &entries))
+ return;
+
+ for (const auto& entry : entries) {
+ if (entry.activated) {
+ FieldTrial::ActiveGroup group;
+ group.trial_name = entry.trial_name.as_string();
+ group.group_name = entry.group_name.as_string();
+ active_groups->push_back(group);
+ }
+ }
+}
+
+// static
bool FieldTrialList::CreateTrialsFromString(
const std::string& trials_string,
FieldTrialActivationMode mode,
@@ -459,40 +521,21 @@ bool FieldTrialList::CreateTrialsFromString(
if (trials_string.empty() || !global_)
return true;
- size_t next_item = 0;
- while (next_item < trials_string.length()) {
- size_t name_end = trials_string.find(kPersistentStringSeparator, next_item);
- if (name_end == trials_string.npos || next_item == name_end)
- return false;
- size_t group_name_end = trials_string.find(kPersistentStringSeparator,
- name_end + 1);
- if (name_end + 1 == group_name_end)
- return false;
- if (group_name_end == trials_string.npos)
- group_name_end = trials_string.length();
+ std::vector<FieldTrial::State> entries;
+ if (!ParseFieldTrialsString(trials_string, &entries))
+ return false;
- // Verify if the trial should be activated or not.
- std::string name;
- bool force_activation = false;
- if (trials_string[next_item] == kActivationMarker) {
- // Name cannot be only the indicator.
- if (name_end - next_item == 1)
- return false;
- next_item++;
- force_activation = true;
- }
- name.append(trials_string, next_item, name_end - next_item);
- std::string group_name(trials_string, name_end + 1,
- group_name_end - name_end - 1);
- next_item = group_name_end + 1;
+ for (const auto& entry : entries) {
+ const std::string trial_name = entry.trial_name.as_string();
+ const std::string group_name = entry.group_name.as_string();
- if (ignored_trial_names.find(name) != ignored_trial_names.end())
+ if (ContainsKey(ignored_trial_names, trial_name))
continue;
- FieldTrial* trial = CreateFieldTrial(name, group_name);
+ FieldTrial* trial = CreateFieldTrial(trial_name, group_name);
if (!trial)
return false;
- if (mode == ACTIVATE_TRIALS || force_activation) {
+ if (mode == ACTIVATE_TRIALS || entry.activated) {
// Call |group()| to mark the trial as "used" and notify observers, if
// any. This is useful to ensure that field trials created in child
// processes are properly reported in crash reports.
diff --git a/chromium/base/metrics/field_trial.h b/chromium/base/metrics/field_trial.h
index 899d89a5742..7bfc1deef12 100644
--- a/chromium/base/metrics/field_trial.h
+++ b/chromium/base/metrics/field_trial.h
@@ -54,6 +54,9 @@
#ifndef BASE_METRICS_FIELD_TRIAL_H_
#define BASE_METRICS_FIELD_TRIAL_H_
+#include <stddef.h>
+#include <stdint.h>
+
#include <map>
#include <set>
#include <string>
@@ -61,8 +64,10 @@
#include "base/base_export.h"
#include "base/gtest_prod_util.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/observer_list_threadsafe.h"
+#include "base/strings/string_piece.h"
#include "base/synchronization/lock.h"
#include "base/time/time.h"
@@ -97,7 +102,7 @@ class BASE_EXPORT FieldTrial : public RefCounted<FieldTrial> {
// providers that support it. A given instance should always return the same
// value given the same input |trial_name| and |randomization_seed| values.
virtual double GetEntropyForTrial(const std::string& trial_name,
- uint32 randomization_seed) const = 0;
+ uint32_t randomization_seed) const = 0;
};
// A pair representing a Field Trial and its selected group.
@@ -108,10 +113,13 @@ class BASE_EXPORT FieldTrial : public RefCounted<FieldTrial> {
// A triplet representing a FieldTrial, its selected group and whether it's
// active.
- struct FieldTrialState {
- std::string trial_name;
- std::string group_name;
+ struct BASE_EXPORT State {
+ StringPiece trial_name;
+ StringPiece group_name;
bool activated;
+
+ State();
+ ~State();
};
typedef std::vector<ActiveGroup> ActiveGroups;
@@ -250,7 +258,7 @@ class BASE_EXPORT FieldTrial : public RefCounted<FieldTrial> {
// 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;
+ bool GetState(State* field_trial_state);
// Returns the group_name. A winner need not have been chosen.
std::string group_name_internal() const { return group_name_; }
@@ -320,15 +328,6 @@ class BASE_EXPORT FieldTrialList {
ACTIVATE_TRIALS,
};
- // Define a separator character to use when creating a persistent form of an
- // instance. This is intended for use as a command line argument, passed to a
- // second process to mimic our state (i.e., provide the same group name).
- static const char kPersistentStringSeparator; // Currently a slash.
-
- // Define a marker character to be used as a prefix to a trial name on the
- // command line which forces its activation.
- static const char kActivationMarker; // Currently an asterisk.
-
// Year that is guaranteed to not be expired when instantiating a field trial
// via |FactoryGetFieldTrial()|. Set to two years from the build date.
static int kNoExpirationYear;
@@ -398,7 +397,7 @@ class BASE_EXPORT FieldTrialList {
const int month,
const int day_of_month,
FieldTrial::RandomizationType randomization_type,
- uint32 randomization_seed,
+ uint32_t randomization_seed,
int* default_group_number);
// The Find() method can be used to test to see if a named trial was already
@@ -448,6 +447,11 @@ class BASE_EXPORT FieldTrialList {
static void GetActiveFieldTrialGroups(
FieldTrial::ActiveGroups* active_groups);
+ // Returns the field trials that are marked active in |trials_string|.
+ static void GetActiveFieldTrialGroupsFromString(
+ const std::string& trials_string,
+ FieldTrial::ActiveGroups* active_groups);
+
// Use a state string (re: StatesToString()) to augment the current list of
// field trials to include the supplied trials, and using a 100% probability
// for each trial, force them to have the same group string. This is commonly
@@ -457,9 +461,9 @@ class BASE_EXPORT FieldTrialList {
// trials are all marked as "used" for the purposes of active trial reporting
// if |mode| is ACTIVATE_TRIALS, otherwise each trial will be marked as "used"
// if it is prefixed with |kActivationMarker|. Trial names in
- // |ignored_trial_names| are ignored when parsing |prior_trials|.
+ // |ignored_trial_names| are ignored when parsing |trials_string|.
static bool CreateTrialsFromString(
- const std::string& prior_trials,
+ const std::string& trials_string,
FieldTrialActivationMode mode,
const std::set<std::string>& ignored_trial_names);
diff --git a/chromium/base/metrics/field_trial_unittest.cc b/chromium/base/metrics/field_trial_unittest.cc
index 6cecc00fd8a..555d7fa60c1 100644
--- a/chromium/base/metrics/field_trial_unittest.cc
+++ b/chromium/base/metrics/field_trial_unittest.cc
@@ -4,7 +4,10 @@
#include "base/metrics/field_trial.h"
+#include <stddef.h>
+
#include "base/build_time.h"
+#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "base/rand_util.h"
#include "base/run_loop.h"
@@ -313,8 +316,19 @@ TEST_F(FieldTrialTest, ActiveGroups) {
}
}
+TEST_F(FieldTrialTest, GetActiveFieldTrialGroupsFromString) {
+ FieldTrial::ActiveGroups active_groups;
+ FieldTrialList::GetActiveFieldTrialGroupsFromString("*A/X/B/Y/*C/Z",
+ &active_groups);
+ ASSERT_EQ(2U, active_groups.size());
+ EXPECT_EQ("A", active_groups[0].trial_name);
+ EXPECT_EQ("X", active_groups[0].group_name);
+ EXPECT_EQ("C", active_groups[1].trial_name);
+ EXPECT_EQ("Z", active_groups[1].group_name);
+}
+
TEST_F(FieldTrialTest, AllGroups) {
- FieldTrial::FieldTrialState field_trial_state;
+ FieldTrial::State field_trial_state;
std::string one_winner("One Winner");
scoped_refptr<FieldTrial> trial =
CreateFieldTrial(one_winner, 10, "Default", NULL);
@@ -446,30 +460,34 @@ TEST_F(FieldTrialTest, SaveAll) {
std::string save_string;
scoped_refptr<FieldTrial> trial =
- CreateFieldTrial("Some name", 10, "Default some name", NULL);
+ CreateFieldTrial("Some name", 10, "Default some name", nullptr);
EXPECT_EQ("", trial->group_name_internal());
FieldTrialList::AllStatesToString(&save_string);
EXPECT_EQ("Some name/Default some name/", save_string);
+ // Getting all states should have finalized the trial.
+ EXPECT_EQ("Default some name", trial->group_name_internal());
save_string.clear();
// Create a winning group.
+ trial = CreateFieldTrial("trial2", 10, "Default some name", nullptr);
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);
+ EXPECT_EQ("Some name/Default some name/*trial2/Winner/", save_string);
save_string.clear();
// Create a second trial and winning group.
scoped_refptr<FieldTrial> trial2 =
- CreateFieldTrial("xxx", 10, "Default xxx", NULL);
+ CreateFieldTrial("xxx", 10, "Default xxx", nullptr);
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);
+ EXPECT_EQ("Some name/Default some name/*trial2/Winner/*xxx/yyyy/",
+ save_string);
save_string.clear();
// Create a third trial with only the default group.
@@ -477,7 +495,8 @@ TEST_F(FieldTrialTest, SaveAll) {
CreateFieldTrial("zzz", 10, "default", NULL);
FieldTrialList::AllStatesToString(&save_string);
- EXPECT_EQ("*Some name/Winner/*xxx/yyyy/zzz/default/", save_string);
+ EXPECT_EQ("Some name/Default some name/*trial2/Winner/*xxx/yyyy/zzz/default/",
+ save_string);
}
TEST_F(FieldTrialTest, Restore) {
diff --git a/chromium/base/metrics/histogram.cc b/chromium/base/metrics/histogram.cc
index b37bc4c4685..62c2bc808da 100644
--- a/chromium/base/metrics/histogram.cc
+++ b/chromium/base/metrics/histogram.cc
@@ -9,6 +9,7 @@
#include "base/metrics/histogram.h"
+#include <limits.h>
#include <math.h>
#include <algorithm>
@@ -18,6 +19,7 @@
#include "base/debug/alias.h"
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
+#include "base/metrics/metrics_hashes.h"
#include "base/metrics/sample_vector.h"
#include "base/metrics/statistics_recorder.h"
#include "base/pickle.h"
@@ -36,7 +38,7 @@ bool ReadHistogramArguments(PickleIterator* iter,
int* declared_min,
int* declared_max,
size_t* bucket_count,
- uint32* range_checksum) {
+ uint32_t* range_checksum) {
if (!iter->ReadString(histogram_name) ||
!iter->ReadInt(flags) ||
!iter->ReadInt(declared_min) ||
@@ -67,7 +69,7 @@ bool ReadHistogramArguments(PickleIterator* iter,
}
bool ValidateRangeChecksum(const HistogramBase& histogram,
- uint32 range_checksum) {
+ uint32_t range_checksum) {
const Histogram& casted_histogram =
static_cast<const Histogram&>(histogram);
@@ -86,7 +88,7 @@ HistogramBase* Histogram::FactoryGet(const std::string& name,
Sample minimum,
Sample maximum,
size_t bucket_count,
- int32 flags) {
+ int32_t flags) {
bool valid_arguments =
InspectConstructionArguments(name, &minimum, &maximum, &bucket_count);
DCHECK(valid_arguments);
@@ -125,7 +127,7 @@ HistogramBase* Histogram::FactoryTimeGet(const std::string& name,
TimeDelta minimum,
TimeDelta maximum,
size_t bucket_count,
- int32 flags) {
+ int32_t flags) {
return FactoryGet(name, static_cast<Sample>(minimum.InMilliseconds()),
static_cast<Sample>(maximum.InMilliseconds()), bucket_count,
flags);
@@ -135,7 +137,7 @@ HistogramBase* Histogram::FactoryGet(const char* name,
Sample minimum,
Sample maximum,
size_t bucket_count,
- int32 flags) {
+ int32_t flags) {
return FactoryGet(std::string(name), minimum, maximum, bucket_count, flags);
}
@@ -143,7 +145,7 @@ HistogramBase* Histogram::FactoryTimeGet(const char* name,
TimeDelta minimum,
TimeDelta maximum,
size_t bucket_count,
- int32 flags) {
+ int32_t flags) {
return FactoryTimeGet(std::string(name), minimum, maximum, bucket_count,
flags);
}
@@ -203,7 +205,7 @@ int Histogram::FindCorruption(const HistogramSamples& samples) const {
if (!bucket_ranges()->HasValidChecksum())
inconsistencies |= RANGE_CHECKSUM_ERROR;
- int64 delta64 = samples.redundant_count() - samples.TotalCount();
+ int64_t delta64 = samples.redundant_count() - samples.TotalCount();
if (delta64 != 0) {
int delta = static_cast<int>(delta64);
if (delta != delta64)
@@ -259,6 +261,10 @@ bool Histogram::InspectConstructionArguments(const std::string& name,
return true;
}
+uint64_t Histogram::name_hash() const {
+ return samples_->id();
+}
+
HistogramType Histogram::GetHistogramType() const {
return HISTOGRAM;
}
@@ -293,7 +299,7 @@ void Histogram::AddCount(int value, int count) {
}
scoped_ptr<HistogramSamples> Histogram::SnapshotSamples() const {
- return SnapshotSampleVector().Pass();
+ return SnapshotSampleVector();
}
void Histogram::AddSamples(const HistogramSamples& samples) {
@@ -335,7 +341,7 @@ Histogram::Histogram(const std::string& name,
declared_min_(minimum),
declared_max_(maximum) {
if (ranges)
- samples_.reset(new SampleVector(ranges));
+ samples_.reset(new SampleVector(HashMetricName(name), ranges));
}
Histogram::~Histogram() {
@@ -373,7 +379,7 @@ HistogramBase* Histogram::DeserializeInfoImpl(PickleIterator* iter) {
int declared_min;
int declared_max;
size_t bucket_count;
- uint32 range_checksum;
+ uint32_t range_checksum;
if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
&declared_max, &bucket_count, &range_checksum)) {
@@ -392,9 +398,10 @@ HistogramBase* Histogram::DeserializeInfoImpl(PickleIterator* iter) {
}
scoped_ptr<SampleVector> Histogram::SnapshotSampleVector() const {
- scoped_ptr<SampleVector> samples(new SampleVector(bucket_ranges()));
+ scoped_ptr<SampleVector> samples(
+ new SampleVector(samples_->id(), bucket_ranges()));
samples->Add(*samples_);
- return samples.Pass();
+ return samples;
}
void Histogram::WriteAsciiImpl(bool graph_it,
@@ -432,8 +439,8 @@ void Histogram::WriteAsciiImpl(bool graph_it,
}
}
- int64 remaining = sample_count;
- int64 past = 0;
+ int64_t remaining = sample_count;
+ int64_t past = 0;
// Output the actual histogram graph.
for (size_t i = 0; i < bucket_count(); ++i) {
Count current = snapshot->GetCountAtIndex(i);
@@ -492,9 +499,9 @@ void Histogram::WriteAsciiHeader(const SampleVector& samples,
StringAppendF(output, " (flags = 0x%x)", flags() & ~kHexRangePrintingFlag);
}
-void Histogram::WriteAsciiBucketContext(const int64 past,
+void Histogram::WriteAsciiBucketContext(const int64_t past,
const Count current,
- const int64 remaining,
+ const int64_t remaining,
const size_t i,
std::string* output) const {
double scaled_sum = (past + current + remaining) / 100.0;
@@ -513,7 +520,7 @@ void Histogram::GetParameters(DictionaryValue* params) const {
}
void Histogram::GetCountAndBucketData(Count* count,
- int64* sum,
+ int64_t* sum,
ListValue* buckets) const {
scoped_ptr<SampleVector> snapshot = SnapshotSampleVector();
*count = snapshot->TotalCount();
@@ -544,7 +551,7 @@ HistogramBase* LinearHistogram::FactoryGet(const std::string& name,
Sample minimum,
Sample maximum,
size_t bucket_count,
- int32 flags) {
+ int32_t flags) {
return FactoryGetWithRangeDescription(
name, minimum, maximum, bucket_count, flags, NULL);
}
@@ -553,7 +560,7 @@ HistogramBase* LinearHistogram::FactoryTimeGet(const std::string& name,
TimeDelta minimum,
TimeDelta maximum,
size_t bucket_count,
- int32 flags) {
+ int32_t flags) {
return FactoryGet(name, static_cast<Sample>(minimum.InMilliseconds()),
static_cast<Sample>(maximum.InMilliseconds()), bucket_count,
flags);
@@ -563,7 +570,7 @@ HistogramBase* LinearHistogram::FactoryGet(const char* name,
Sample minimum,
Sample maximum,
size_t bucket_count,
- int32 flags) {
+ int32_t flags) {
return FactoryGet(std::string(name), minimum, maximum, bucket_count, flags);
}
@@ -571,18 +578,18 @@ HistogramBase* LinearHistogram::FactoryTimeGet(const char* name,
TimeDelta minimum,
TimeDelta maximum,
size_t bucket_count,
- int32 flags) {
+ int32_t flags) {
return FactoryTimeGet(std::string(name), minimum, maximum, bucket_count,
flags);
}
HistogramBase* LinearHistogram::FactoryGetWithRangeDescription(
- const std::string& name,
- Sample minimum,
- Sample maximum,
- size_t bucket_count,
- int32 flags,
- const DescriptionPair descriptions[]) {
+ const std::string& name,
+ Sample minimum,
+ Sample maximum,
+ size_t bucket_count,
+ int32_t flags,
+ const DescriptionPair descriptions[]) {
bool valid_arguments = Histogram::InspectConstructionArguments(
name, &minimum, &maximum, &bucket_count);
DCHECK(valid_arguments);
@@ -679,7 +686,7 @@ HistogramBase* LinearHistogram::DeserializeInfoImpl(PickleIterator* iter) {
int declared_min;
int declared_max;
size_t bucket_count;
- uint32 range_checksum;
+ uint32_t range_checksum;
if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
&declared_max, &bucket_count, &range_checksum)) {
@@ -700,7 +707,7 @@ HistogramBase* LinearHistogram::DeserializeInfoImpl(PickleIterator* iter) {
//------------------------------------------------------------------------------
HistogramBase* BooleanHistogram::FactoryGet(const std::string& name,
- int32 flags) {
+ int32_t flags) {
HistogramBase* histogram = StatisticsRecorder::FindHistogram(name);
if (!histogram) {
// To avoid racy destruction at shutdown, the following will be leaked.
@@ -721,7 +728,7 @@ HistogramBase* BooleanHistogram::FactoryGet(const std::string& name,
return histogram;
}
-HistogramBase* BooleanHistogram::FactoryGet(const char* name, int32 flags) {
+HistogramBase* BooleanHistogram::FactoryGet(const char* name, int32_t flags) {
return FactoryGet(std::string(name), flags);
}
@@ -739,7 +746,7 @@ HistogramBase* BooleanHistogram::DeserializeInfoImpl(PickleIterator* iter) {
int declared_min;
int declared_max;
size_t bucket_count;
- uint32 range_checksum;
+ uint32_t range_checksum;
if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
&declared_max, &bucket_count, &range_checksum)) {
@@ -762,7 +769,7 @@ HistogramBase* BooleanHistogram::DeserializeInfoImpl(PickleIterator* iter) {
HistogramBase* CustomHistogram::FactoryGet(
const std::string& name,
const std::vector<Sample>& custom_ranges,
- int32 flags) {
+ int32_t flags) {
CHECK(ValidateCustomRanges(custom_ranges));
HistogramBase* histogram = StatisticsRecorder::FindHistogram(name);
@@ -788,7 +795,7 @@ HistogramBase* CustomHistogram::FactoryGet(
HistogramBase* CustomHistogram::FactoryGet(
const char* name,
const std::vector<Sample>& custom_ranges,
- int32 flags) {
+ int32_t flags) {
return FactoryGet(std::string(name), custom_ranges, flags);
}
@@ -842,7 +849,7 @@ HistogramBase* CustomHistogram::DeserializeInfoImpl(PickleIterator* iter) {
int declared_min;
int declared_max;
size_t bucket_count;
- uint32 range_checksum;
+ uint32_t range_checksum;
if (!ReadHistogramArguments(iter, &histogram_name, &flags, &declared_min,
&declared_max, &bucket_count, &range_checksum)) {
diff --git a/chromium/base/metrics/histogram.h b/chromium/base/metrics/histogram.h
index 1f6e2a1ceeb..28bb29b6e3d 100644
--- a/chromium/base/metrics/histogram.h
+++ b/chromium/base/metrics/histogram.h
@@ -66,15 +66,18 @@
#ifndef BASE_METRICS_HISTOGRAM_H_
#define BASE_METRICS_HISTOGRAM_H_
+#include <stddef.h>
+#include <stdint.h>
+
#include <map>
#include <string>
#include <vector>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/gtest_prod_util.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/metrics/bucket_ranges.h"
#include "base/metrics/histogram_base.h"
@@ -114,12 +117,12 @@ class BASE_EXPORT Histogram : public HistogramBase {
Sample minimum,
Sample maximum,
size_t bucket_count,
- int32 flags);
+ int32_t flags);
static HistogramBase* FactoryTimeGet(const std::string& name,
base::TimeDelta minimum,
base::TimeDelta maximum,
size_t bucket_count,
- int32 flags);
+ int32_t flags);
// Overloads of the above two functions that take a const char* |name| param,
// to avoid code bloat from the std::string constructor being inlined into
@@ -128,12 +131,12 @@ class BASE_EXPORT Histogram : public HistogramBase {
Sample minimum,
Sample maximum,
size_t bucket_count,
- int32 flags);
+ int32_t flags);
static HistogramBase* FactoryTimeGet(const char* name,
base::TimeDelta minimum,
base::TimeDelta maximum,
size_t bucket_count,
- int32 flags);
+ int32_t flags);
static void InitializeBucketRanges(Sample minimum,
Sample maximum,
@@ -176,6 +179,7 @@ class BASE_EXPORT Histogram : public HistogramBase {
size_t* bucket_count);
// HistogramBase implementation:
+ uint64_t name_hash() const override;
HistogramType GetHistogramType() const override;
bool HasConstructionArguments(Sample expected_minimum,
Sample expected_maximum,
@@ -224,7 +228,7 @@ class BASE_EXPORT Histogram : public HistogramBase {
friend class StatisticsRecorder; // To allow it to delete duplicates.
friend class StatisticsRecorderTest;
- friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
+ friend BASE_EXPORT HistogramBase* DeserializeHistogramInfo(
base::PickleIterator* iter);
static HistogramBase* DeserializeInfoImpl(base::PickleIterator* iter);
@@ -248,15 +252,17 @@ class BASE_EXPORT Histogram : public HistogramBase {
// Write information about previous, current, and next buckets.
// Information such as cumulative percentage, etc.
- void WriteAsciiBucketContext(const int64 past, const Count current,
- const int64 remaining, const size_t i,
+ void WriteAsciiBucketContext(const int64_t past,
+ const Count current,
+ const int64_t remaining,
+ const size_t i,
std::string* output) const;
// WriteJSON calls these.
void GetParameters(DictionaryValue* params) const override;
void GetCountAndBucketData(Count* count,
- int64* sum,
+ int64_t* sum,
ListValue* buckets) const override;
// Does not own this object. Should get from StatisticsRecorder.
@@ -286,12 +292,12 @@ class BASE_EXPORT LinearHistogram : public Histogram {
Sample minimum,
Sample maximum,
size_t bucket_count,
- int32 flags);
+ int32_t flags);
static HistogramBase* FactoryTimeGet(const std::string& name,
TimeDelta minimum,
TimeDelta maximum,
size_t bucket_count,
- int32 flags);
+ int32_t flags);
// Overloads of the above two functions that take a const char* |name| param,
// to avoid code bloat from the std::string constructor being inlined into
@@ -300,12 +306,12 @@ class BASE_EXPORT LinearHistogram : public Histogram {
Sample minimum,
Sample maximum,
size_t bucket_count,
- int32 flags);
+ int32_t flags);
static HistogramBase* FactoryTimeGet(const char* name,
TimeDelta minimum,
TimeDelta maximum,
size_t bucket_count,
- int32 flags);
+ int32_t flags);
struct DescriptionPair {
Sample sample;
@@ -322,7 +328,7 @@ class BASE_EXPORT LinearHistogram : public Histogram {
Sample minimum,
Sample maximum,
size_t bucket_count,
- int32 flags,
+ int32_t flags,
const DescriptionPair descriptions[]);
static void InitializeBucketRanges(Sample minimum,
@@ -349,7 +355,7 @@ class BASE_EXPORT LinearHistogram : public Histogram {
bool PrintEmptyBucket(size_t index) const override;
private:
- friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
+ friend BASE_EXPORT HistogramBase* DeserializeHistogramInfo(
base::PickleIterator* iter);
static HistogramBase* DeserializeInfoImpl(base::PickleIterator* iter);
@@ -367,19 +373,19 @@ class BASE_EXPORT LinearHistogram : public Histogram {
// BooleanHistogram is a histogram for booleans.
class BASE_EXPORT BooleanHistogram : public LinearHistogram {
public:
- static HistogramBase* FactoryGet(const std::string& name, int32 flags);
+ static HistogramBase* FactoryGet(const std::string& name, int32_t flags);
// Overload of the above function that takes a const char* |name| param,
// to avoid code bloat from the std::string constructor being inlined into
// call sites.
- static HistogramBase* FactoryGet(const char* name, int32 flags);
+ static HistogramBase* FactoryGet(const char* name, int32_t flags);
HistogramType GetHistogramType() const override;
private:
BooleanHistogram(const std::string& name, const BucketRanges* ranges);
- friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
+ friend BASE_EXPORT HistogramBase* DeserializeHistogramInfo(
base::PickleIterator* iter);
static HistogramBase* DeserializeInfoImpl(base::PickleIterator* iter);
@@ -397,14 +403,14 @@ class BASE_EXPORT CustomHistogram : public Histogram {
// client should not depend on this.
static HistogramBase* FactoryGet(const std::string& name,
const std::vector<Sample>& custom_ranges,
- int32 flags);
+ int32_t flags);
// Overload of the above function that takes a const char* |name| param,
// to avoid code bloat from the std::string constructor being inlined into
// call sites.
static HistogramBase* FactoryGet(const char* name,
const std::vector<Sample>& custom_ranges,
- int32 flags);
+ int32_t flags);
// Overridden from Histogram:
HistogramType GetHistogramType() const override;
@@ -427,7 +433,7 @@ class BASE_EXPORT CustomHistogram : public Histogram {
double GetBucketSize(Count current, size_t i) const override;
private:
- friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
+ friend BASE_EXPORT HistogramBase* DeserializeHistogramInfo(
base::PickleIterator* iter);
static HistogramBase* DeserializeInfoImpl(base::PickleIterator* iter);
diff --git a/chromium/base/metrics/histogram_base.cc b/chromium/base/metrics/histogram_base.cc
index 6b3f69c2c04..412f1438d2f 100644
--- a/chromium/base/metrics/histogram_base.cc
+++ b/chromium/base/metrics/histogram_base.cc
@@ -4,7 +4,9 @@
#include "base/metrics/histogram_base.h"
-#include <climits>
+#include <limits.h>
+
+#include <utility>
#include "base/json/json_string_value_serializer.h"
#include "base/logging.h"
@@ -71,12 +73,14 @@ void HistogramBase::CheckName(const StringPiece& name) const {
DCHECK_EQ(histogram_name(), name);
}
-void HistogramBase::SetFlags(int32 flags) {
- flags_ |= flags;
+void HistogramBase::SetFlags(int32_t flags) {
+ HistogramBase::Count old_flags = subtle::NoBarrier_Load(&flags_);
+ subtle::NoBarrier_Store(&flags_, old_flags | flags);
}
-void HistogramBase::ClearFlags(int32 flags) {
- flags_ &= ~flags;
+void HistogramBase::ClearFlags(int32_t flags) {
+ HistogramBase::Count old_flags = subtle::NoBarrier_Load(&flags_);
+ subtle::NoBarrier_Store(&flags_, old_flags & ~flags);
}
void HistogramBase::AddTime(const TimeDelta& time) {
@@ -100,7 +104,7 @@ int HistogramBase::FindCorruption(const HistogramSamples& samples) const {
void HistogramBase::WriteJSON(std::string* output) const {
Count count;
- int64 sum;
+ int64_t sum;
scoped_ptr<ListValue> buckets(new ListValue());
GetCountAndBucketData(&count, &sum, buckets.get());
scoped_ptr<DictionaryValue> parameters(new DictionaryValue());
@@ -112,14 +116,14 @@ 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.Pass());
- root.Set("buckets", buckets.Pass());
+ root.Set("params", std::move(parameters));
+ root.Set("buckets", std::move(buckets));
root.SetInteger("pid", GetCurrentProcId());
serializer.Serialize(root);
}
void HistogramBase::FindAndRunCallback(HistogramBase::Sample sample) const {
- if ((flags_ & kCallbackExists) == 0)
+ if ((flags() & kCallbackExists) == 0)
return;
StatisticsRecorder::OnSampleCallback cb =
diff --git a/chromium/base/metrics/histogram_base.h b/chromium/base/metrics/histogram_base.h
index 304e3e03b6b..4fa07c64efb 100644
--- a/chromium/base/metrics/histogram_base.h
+++ b/chromium/base/metrics/histogram_base.h
@@ -5,6 +5,8 @@
#ifndef BASE_METRICS_HISTOGRAM_BASE_H_
#define BASE_METRICS_HISTOGRAM_BASE_H_
+#include <limits.h>
+#include <stddef.h>
#include <stdint.h>
#include <string>
@@ -12,7 +14,7 @@
#include "base/atomicops.h"
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/string_piece.h"
#include "base/time/time.h"
@@ -43,8 +45,7 @@ std::string HistogramTypeToString(HistogramType type);
// Create or find existing histogram that matches the pickled info.
// Returns NULL if the pickled data has problems.
-BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
- base::PickleIterator* iter);
+BASE_EXPORT HistogramBase* DeserializeHistogramInfo(base::PickleIterator* iter);
////////////////////////////////////////////////////////////////////////////////
@@ -105,8 +106,11 @@ class BASE_EXPORT HistogramBase {
// in more compact machine code being generated by the macros.
void CheckName(const StringPiece& name) const;
+ // Get a unique ID for this histogram's samples.
+ virtual uint64_t name_hash() const = 0;
+
// Operations with Flags enum.
- int32_t flags() const { return flags_; }
+ int32_t flags() const { return subtle::NoBarrier_Load(&flags_); }
void SetFlags(int32_t flags);
void ClearFlags(int32_t flags);
@@ -167,7 +171,7 @@ class BASE_EXPORT HistogramBase {
// counts to |buckets|, the total sample count to |count| and the total sum
// to |sum|.
virtual void GetCountAndBucketData(Count* count,
- int64* sum,
+ int64_t* sum,
ListValue* buckets) const = 0;
//// Produce actual graph (set of blank vs non blank char's) for a bucket.
@@ -190,7 +194,7 @@ class BASE_EXPORT HistogramBase {
private:
const std::string histogram_name_;
- int32_t flags_;
+ AtomicCount flags_;
DISALLOW_COPY_AND_ASSIGN(HistogramBase);
};
diff --git a/chromium/base/metrics/histogram_delta_serialization.cc b/chromium/base/metrics/histogram_delta_serialization.cc
index e4aad13ac22..f2b825b6d31 100644
--- a/chromium/base/metrics/histogram_delta_serialization.cc
+++ b/chromium/base/metrics/histogram_delta_serialization.cc
@@ -61,6 +61,8 @@ HistogramDeltaSerialization::~HistogramDeltaSerialization() {
void HistogramDeltaSerialization::PrepareAndSerializeDeltas(
std::vector<std::string>* serialized_deltas) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
serialized_deltas_ = serialized_deltas;
// Note: Before serializing, we set the kIPCSerializationSourceFlag for all
// the histograms, so that the receiving process can distinguish them from the
@@ -84,6 +86,7 @@ void HistogramDeltaSerialization::DeserializeAndAddSamples(
void HistogramDeltaSerialization::RecordDelta(
const HistogramBase& histogram,
const HistogramSamples& snapshot) {
+ DCHECK(thread_checker_.CalledOnValidThread());
DCHECK_NE(0, snapshot.TotalCount());
Pickle pickle;
@@ -95,16 +98,22 @@ void HistogramDeltaSerialization::RecordDelta(
void HistogramDeltaSerialization::InconsistencyDetected(
HistogramBase::Inconsistency problem) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
inconsistencies_histogram_->Add(problem);
}
void HistogramDeltaSerialization::UniqueInconsistencyDetected(
HistogramBase::Inconsistency problem) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
inconsistencies_unique_histogram_->Add(problem);
}
void HistogramDeltaSerialization::InconsistencyDetectedInLoggedCount(
int amount) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
inconsistent_snapshot_histogram_->Add(std::abs(amount));
}
diff --git a/chromium/base/metrics/histogram_delta_serialization.h b/chromium/base/metrics/histogram_delta_serialization.h
index a379914c0db..0a3983f8eab 100644
--- a/chromium/base/metrics/histogram_delta_serialization.h
+++ b/chromium/base/metrics/histogram_delta_serialization.h
@@ -9,10 +9,11 @@
#include <vector>
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/metrics/histogram_flattener.h"
#include "base/metrics/histogram_snapshot_manager.h"
+#include "base/threading/thread_checker.h"
namespace base {
@@ -45,6 +46,8 @@ class BASE_EXPORT HistogramDeltaSerialization : public HistogramFlattener {
HistogramBase::Inconsistency problem) override;
void InconsistencyDetectedInLoggedCount(int amount) override;
+ ThreadChecker thread_checker_;
+
// Calculates deltas in histogram counters.
HistogramSnapshotManager histogram_snapshot_manager_;
diff --git a/chromium/base/metrics/histogram_flattener.h b/chromium/base/metrics/histogram_flattener.h
index ca05a4f421f..b5fe9766566 100644
--- a/chromium/base/metrics/histogram_flattener.h
+++ b/chromium/base/metrics/histogram_flattener.h
@@ -8,7 +8,7 @@
#include <map>
#include <string>
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/metrics/histogram.h"
namespace base {
diff --git a/chromium/base/metrics/histogram_macros.h b/chromium/base/metrics/histogram_macros.h
index 882c58ac44b..0492f0c9132 100644
--- a/chromium/base/metrics/histogram_macros.h
+++ b/chromium/base/metrics/histogram_macros.h
@@ -6,7 +6,6 @@
#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"
diff --git a/chromium/base/metrics/histogram_samples.cc b/chromium/base/metrics/histogram_samples.cc
index f5e03b979e1..4cd8e556b81 100644
--- a/chromium/base/metrics/histogram_samples.cc
+++ b/chromium/base/metrics/histogram_samples.cc
@@ -59,30 +59,58 @@ void SampleCountPickleIterator::Get(HistogramBase::Sample* min,
} // namespace
-HistogramSamples::HistogramSamples() : sum_(0), redundant_count_(0) {}
+// Don't try to delegate behavior to the constructor below that accepts a
+// Matadata pointer by passing &local_meta_. Such cannot be reliably passed
+// because it has not yet been constructed -- no member variables have; the
+// class itself is in the middle of being constructed. Using it to
+// initialize meta_ is okay because the object now exists and local_meta_
+// is before meta_ in the construction order.
+HistogramSamples::HistogramSamples(uint64_t id)
+ : meta_(&local_meta_) {
+ meta_->id = id;
+}
+
+HistogramSamples::HistogramSamples(uint64_t id, Metadata* meta)
+ : meta_(meta) {
+ DCHECK(meta_->id == 0 || meta_->id == id);
+ meta_->id = id;
+}
HistogramSamples::~HistogramSamples() {}
+// Despite using atomic operations, the increment/add actions below are *not*
+// atomic! Race conditions may cause loss of samples or even completely corrupt
+// the 64-bit sum on 32-bit machines. This is done intentionally to reduce the
+// cost of these operations that could be executed in performance-significant
+// points of the code.
+//
+// TODO(bcwhite): Gather quantitative information as to the cost of using
+// proper atomic increments and improve either globally or for those histograms
+// that really need it.
+
void HistogramSamples::Add(const HistogramSamples& other) {
- sum_ += other.sum();
+ meta_->sum += other.sum();
+
HistogramBase::Count old_redundant_count =
- subtle::NoBarrier_Load(&redundant_count_);
- subtle::NoBarrier_Store(&redundant_count_,
+ subtle::NoBarrier_Load(&meta_->redundant_count);
+ subtle::NoBarrier_Store(&meta_->redundant_count,
old_redundant_count + other.redundant_count());
bool success = AddSubtractImpl(other.Iterator().get(), ADD);
DCHECK(success);
}
bool HistogramSamples::AddFromPickle(PickleIterator* iter) {
- int64 sum;
+ int64_t sum;
HistogramBase::Count redundant_count;
if (!iter->ReadInt64(&sum) || !iter->ReadInt(&redundant_count))
return false;
- sum_ += sum;
+
+ meta_->sum += sum;
+
HistogramBase::Count old_redundant_count =
- subtle::NoBarrier_Load(&redundant_count_);
- subtle::NoBarrier_Store(&redundant_count_,
+ subtle::NoBarrier_Load(&meta_->redundant_count);
+ subtle::NoBarrier_Store(&meta_->redundant_count,
old_redundant_count + redundant_count);
SampleCountPickleIterator pickle_iter(iter);
@@ -90,18 +118,20 @@ bool HistogramSamples::AddFromPickle(PickleIterator* iter) {
}
void HistogramSamples::Subtract(const HistogramSamples& other) {
- sum_ -= other.sum();
+ meta_->sum -= other.sum();
+
HistogramBase::Count old_redundant_count =
- subtle::NoBarrier_Load(&redundant_count_);
- subtle::NoBarrier_Store(&redundant_count_,
+ subtle::NoBarrier_Load(&meta_->redundant_count);
+ subtle::NoBarrier_Store(&meta_->redundant_count,
old_redundant_count - other.redundant_count());
bool success = AddSubtractImpl(other.Iterator().get(), SUBTRACT);
DCHECK(success);
}
bool HistogramSamples::Serialize(Pickle* pickle) const {
- if (!pickle->WriteInt64(sum_) ||
- !pickle->WriteInt(subtle::NoBarrier_Load(&redundant_count_)))
+ if (!pickle->WriteInt64(meta_->sum))
+ return false;
+ if (!pickle->WriteInt(subtle::NoBarrier_Load(&meta_->redundant_count)))
return false;
HistogramBase::Sample min;
@@ -119,13 +149,13 @@ bool HistogramSamples::Serialize(Pickle* pickle) const {
return true;
}
-void HistogramSamples::IncreaseSum(int64 diff) {
- sum_ += diff;
+void HistogramSamples::IncreaseSum(int64_t diff) {
+ meta_->sum += diff;
}
void HistogramSamples::IncreaseRedundantCount(HistogramBase::Count diff) {
- subtle::NoBarrier_Store(&redundant_count_,
- subtle::NoBarrier_Load(&redundant_count_) + diff);
+ subtle::NoBarrier_Store(&meta_->redundant_count,
+ subtle::NoBarrier_Load(&meta_->redundant_count) + diff);
}
SampleCountIterator::~SampleCountIterator() {}
diff --git a/chromium/base/metrics/histogram_samples.h b/chromium/base/metrics/histogram_samples.h
index 54185cf383b..3da3e2d829a 100644
--- a/chromium/base/metrics/histogram_samples.h
+++ b/chromium/base/metrics/histogram_samples.h
@@ -5,9 +5,13 @@
#ifndef BASE_METRICS_HISTOGRAM_SAMPLES_H_
#define BASE_METRICS_HISTOGRAM_SAMPLES_H_
-#include "base/basictypes.h"
-#include "base/metrics/histogram_base.h"
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/atomicops.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram_base.h"
namespace base {
@@ -18,7 +22,35 @@ class SampleCountIterator;
// HistogramSamples is a container storing all samples of a histogram.
class BASE_EXPORT HistogramSamples {
public:
- HistogramSamples();
+ struct Metadata {
+ // Initialized when the sample-set is first created with a value provided
+ // by the caller. It is generally used to identify the sample-set across
+ // threads and processes, though not necessarily uniquely as it is possible
+ // to have multiple sample-sets representing subsets of the data.
+ uint64_t id;
+
+ // The sum of all the entries, effectivly the sum(sample * count) for
+ // all samples. Despite being atomic, no guarantees are made on the
+ // accuracy of this value; there may be races during histogram
+ // accumulation and snapshotting that we choose to accept. It should
+ // be treated as approximate.
+ // TODO(bcwhite): Change this to std::atomic<int64_t>.
+ int64_t sum;
+
+ // A "redundant" count helps identify memory corruption. It redundantly
+ // stores the total number of samples accumulated in the histogram. We
+ // can compare this count to the sum of the counts (TotalCount() function),
+ // and detect problems. Note, depending on the implementation of different
+ // histogram types, there might be races during histogram accumulation
+ // and snapshotting that we choose to accept. In this case, the tallies
+ // might mismatch even when no memory corruption has happened.
+ HistogramBase::AtomicCount redundant_count;
+
+ Metadata() : id(0), sum(0), redundant_count(0) {}
+ };
+
+ explicit HistogramSamples(uint64_t id);
+ HistogramSamples(uint64_t id, Metadata* meta);
virtual ~HistogramSamples();
virtual void Accumulate(HistogramBase::Sample value,
@@ -37,9 +69,10 @@ class BASE_EXPORT HistogramSamples {
virtual bool Serialize(Pickle* pickle) const;
// Accessor fuctions.
- int64 sum() const { return sum_; }
+ uint64_t id() const { return meta_->id; }
+ int64_t sum() const { return meta_->sum; }
HistogramBase::Count redundant_count() const {
- return subtle::NoBarrier_Load(&redundant_count_);
+ return subtle::NoBarrier_Load(&meta_->redundant_count);
}
protected:
@@ -47,20 +80,17 @@ class BASE_EXPORT HistogramSamples {
enum Operator { ADD, SUBTRACT };
virtual bool AddSubtractImpl(SampleCountIterator* iter, Operator op) = 0;
- void IncreaseSum(int64 diff);
+ void IncreaseSum(int64_t diff);
void IncreaseRedundantCount(HistogramBase::Count diff);
private:
- int64 sum_;
-
- // |redundant_count_| helps identify memory corruption. It redundantly stores
- // the total number of samples accumulated in the histogram. We can compare
- // this count to the sum of the counts (TotalCount() function), and detect
- // problems. Note, depending on the implementation of different histogram
- // types, there might be races during histogram accumulation and snapshotting
- // that we choose to accept. In this case, the tallies might mismatch even
- // when no memory corruption has happened.
- HistogramBase::AtomicCount redundant_count_;
+ // In order to support histograms shared through an external memory segment,
+ // meta values may be the local storage or external storage depending on the
+ // wishes of the derived class.
+ Metadata local_meta_;
+ Metadata* meta_;
+
+ DISALLOW_COPY_AND_ASSIGN(HistogramSamples);
};
class BASE_EXPORT SampleCountIterator {
diff --git a/chromium/base/metrics/histogram_snapshot_manager.cc b/chromium/base/metrics/histogram_snapshot_manager.cc
index a7605aa1417..02f87f0105a 100644
--- a/chromium/base/metrics/histogram_snapshot_manager.cc
+++ b/chromium/base/metrics/histogram_snapshot_manager.cc
@@ -41,13 +41,11 @@ void HistogramSnapshotManager::PrepareDelta(const HistogramBase& histogram) {
// Get up-to-date snapshot of sample stats.
scoped_ptr<HistogramSamples> snapshot(histogram.SnapshotSamples());
- const std::string& histogram_name = histogram.histogram_name();
-
- int corruption = histogram.FindCorruption(*snapshot);
// Crash if we detect that our histograms have been overwritten. This may be
// a fair distance from the memory smasher, but we hope to correlate these
// crashes with other events, such as plugins, or usage patterns, etc.
+ int corruption = histogram.FindCorruption(*snapshot);
if (HistogramBase::BUCKET_ORDER_ERROR & corruption) {
// The checksum should have caught this, so crash separately if it didn't.
CHECK_NE(0, HistogramBase::RANGE_CHECKSUM_ERROR & corruption);
@@ -59,29 +57,29 @@ void HistogramSnapshotManager::PrepareDelta(const HistogramBase& histogram) {
// Note, at this point corruption can only be COUNT_HIGH_ERROR or
// COUNT_LOW_ERROR and they never arise together, so we don't need to extract
// bits from corruption.
+ const uint64_t histogram_hash = histogram.name_hash();
if (corruption) {
- DLOG(ERROR) << "Histogram: " << histogram_name
+ DLOG(ERROR) << "Histogram: " << histogram.histogram_name()
<< " has data corruption: " << corruption;
histogram_flattener_->InconsistencyDetected(
static_cast<HistogramBase::Inconsistency>(corruption));
// Don't record corrupt data to metrics services.
- int old_corruption = inconsistencies_[histogram_name];
+ int old_corruption = inconsistencies_[histogram_hash];
if (old_corruption == (corruption | old_corruption))
return; // We've already seen this corruption for this histogram.
- inconsistencies_[histogram_name] |= corruption;
+ inconsistencies_[histogram_hash] |= corruption;
histogram_flattener_->UniqueInconsistencyDetected(
static_cast<HistogramBase::Inconsistency>(corruption));
return;
}
HistogramSamples* to_log;
- std::map<std::string, HistogramSamples*>::iterator it =
- logged_samples_.find(histogram_name);
+ auto it = logged_samples_.find(histogram_hash);
if (it == logged_samples_.end()) {
to_log = snapshot.release();
// This histogram has not been logged before, add a new entry.
- logged_samples_[histogram_name] = to_log;
+ logged_samples_[histogram_hash] = to_log;
} else {
HistogramSamples* already_logged = it->second;
InspectLoggedSamplesInconsistency(*snapshot, already_logged);
diff --git a/chromium/base/metrics/histogram_snapshot_manager.h b/chromium/base/metrics/histogram_snapshot_manager.h
index 5a5f2e93e5e..bad4668067b 100644
--- a/chromium/base/metrics/histogram_snapshot_manager.h
+++ b/chromium/base/metrics/histogram_snapshot_manager.h
@@ -5,10 +5,12 @@
#ifndef BASE_METRICS_HISTOGRAM_SNAPSHOT_MANAGER_H_
#define BASE_METRICS_HISTOGRAM_SNAPSHOT_MANAGER_H_
+#include <stdint.h>
+
#include <map>
#include <string>
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/metrics/histogram_base.h"
namespace base {
@@ -48,10 +50,12 @@ class BASE_EXPORT HistogramSnapshotManager {
// For histograms, track what we've already recorded (as a sample for
// each histogram) so that we can record only the delta with the next log.
- std::map<std::string, HistogramSamples*> logged_samples_;
+ // The information is indexed by the hash of the histogram name.
+ std::map<uint64_t, HistogramSamples*> logged_samples_;
- // List of histograms found to be corrupt, and their problems.
- std::map<std::string, int> inconsistencies_;
+ // Set of histograms found to be corrupt and their problems, indexed
+ // by the hash of the histogram name.
+ std::map<uint64_t, int> inconsistencies_;
// |histogram_flattener_| handles the logistics of recording the histogram
// deltas.
diff --git a/chromium/base/metrics/histogram_snapshot_manager_unittest.cc b/chromium/base/metrics/histogram_snapshot_manager_unittest.cc
index e9e7398bca9..b6a367af2be 100644
--- a/chromium/base/metrics/histogram_snapshot_manager_unittest.cc
+++ b/chromium/base/metrics/histogram_snapshot_manager_unittest.cc
@@ -7,6 +7,7 @@
#include <string>
#include <vector>
+#include "base/macros.h"
#include "base/metrics/histogram_delta_serialization.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/statistics_recorder.h"
diff --git a/chromium/base/metrics/histogram_unittest.cc b/chromium/base/metrics/histogram_unittest.cc
index b144379050b..2fadc304415 100644
--- a/chromium/base/metrics/histogram_unittest.cc
+++ b/chromium/base/metrics/histogram_unittest.cc
@@ -4,8 +4,12 @@
#include "base/metrics/histogram.h"
-#include <climits>
+#include <limits.h>
+#include <stddef.h>
+#include <stdint.h>
+
#include <algorithm>
+#include <climits>
#include <vector>
#include "base/logging.h"
@@ -81,7 +85,7 @@ TEST_F(HistogramTest, NameMatchTest) {
}
TEST_F(HistogramTest, ExponentialRangesTest) {
- // Check that we got a nice exponential when there was enough rooom.
+ // Check that we got a nice exponential when there was enough room.
BucketRanges ranges(9);
Histogram::InitializeBucketRanges(1, 64, &ranges);
EXPECT_EQ(0, ranges.range(0));
@@ -414,11 +418,11 @@ TEST_F(HistogramTest, HistogramSerializeInfo) {
EXPECT_TRUE(iter.ReadInt(&max));
EXPECT_EQ(64, max);
- int64 bucket_count;
+ int64_t bucket_count;
EXPECT_TRUE(iter.ReadInt64(&bucket_count));
EXPECT_EQ(8, bucket_count);
- uint32 checksum;
+ uint32_t checksum;
EXPECT_TRUE(iter.ReadUInt32(&checksum));
EXPECT_EQ(histogram->bucket_ranges()->checksum(), checksum);
@@ -443,8 +447,8 @@ TEST_F(HistogramTest, CustomHistogramSerializeInfo) {
int i;
std::string s;
- int64 bucket_count;
- uint32 ui32;
+ int64_t bucket_count;
+ uint32_t ui32;
EXPECT_TRUE(iter.ReadInt(&i) && iter.ReadString(&s) && iter.ReadInt(&i) &&
iter.ReadInt(&i) && iter.ReadInt(&i) &&
iter.ReadInt64(&bucket_count) && iter.ReadUInt32(&ui32));
diff --git a/chromium/base/metrics/metrics_hashes.cc b/chromium/base/metrics/metrics_hashes.cc
new file mode 100644
index 00000000000..73bce2e00b3
--- /dev/null
+++ b/chromium/base/metrics/metrics_hashes.cc
@@ -0,0 +1,31 @@
+// 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/metrics/metrics_hashes.h"
+
+#include "base/logging.h"
+#include "base/md5.h"
+#include "base/sys_byteorder.h"
+
+namespace base {
+
+namespace {
+
+// Converts the 8-byte prefix of an MD5 hash into a uint64_t value.
+inline uint64_t DigestToUInt64(const base::MD5Digest& digest) {
+ uint64_t value;
+ DCHECK_GE(sizeof(digest.a), sizeof(value));
+ memcpy(&value, digest.a, sizeof(value));
+ return base::NetToHost64(value);
+}
+
+} // namespace
+
+uint64_t HashMetricName(const std::string& name) {
+ base::MD5Digest digest;
+ base::MD5Sum(name.c_str(), name.size(), &digest);
+ return DigestToUInt64(digest);
+}
+
+} // namespace metrics
diff --git a/chromium/base/metrics/metrics_hashes.h b/chromium/base/metrics/metrics_hashes.h
new file mode 100644
index 00000000000..bd040173fb2
--- /dev/null
+++ b/chromium/base/metrics/metrics_hashes.h
@@ -0,0 +1,21 @@
+// 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_METRICS_HASHES_H_
+#define BASE_METRICS_METRICS_HASHES_H_
+
+#include <stdint.h>
+#include <string>
+
+#include "base/base_export.h"
+
+namespace base {
+
+// Computes a uint64_t hash of a given string based on its MD5 hash. Suitable
+// for metric names.
+BASE_EXPORT uint64_t HashMetricName(const std::string& name);
+
+} // namespace metrics
+
+#endif // BASE_METRICS_METRICS_HASHES_H_
diff --git a/chromium/base/metrics/metrics_hashes_unittest.cc b/chromium/base/metrics/metrics_hashes_unittest.cc
new file mode 100644
index 00000000000..aea254ef49b
--- /dev/null
+++ b/chromium/base/metrics/metrics_hashes_unittest.cc
@@ -0,0 +1,35 @@
+// 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/metrics/metrics_hashes.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/format_macros.h"
+#include "base/macros.h"
+#include "base/strings/stringprintf.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+// Make sure our ID hashes are the same as what we see on the server side.
+TEST(MetricsUtilTest, HashMetricName) {
+ static const struct {
+ std::string input;
+ std::string output;
+ } cases[] = {
+ {"Back", "0x0557fa923dcee4d0"},
+ {"Forward", "0x67d2f6740a8eaebf"},
+ {"NewTab", "0x290eb683f96572f1"},
+ };
+
+ for (size_t i = 0; i < arraysize(cases); ++i) {
+ uint64_t hash = HashMetricName(cases[i].input);
+ std::string hash_hex = base::StringPrintf("0x%016" PRIx64, hash);
+ EXPECT_EQ(cases[i].output, hash_hex);
+ }
+}
+
+} // namespace metrics
diff --git a/chromium/base/metrics/sample_map.cc b/chromium/base/metrics/sample_map.cc
index f2540a4d00b..a691243f340 100644
--- a/chromium/base/metrics/sample_map.cc
+++ b/chromium/base/metrics/sample_map.cc
@@ -11,7 +11,9 @@ namespace base {
typedef HistogramBase::Count Count;
typedef HistogramBase::Sample Sample;
-SampleMap::SampleMap() {}
+SampleMap::SampleMap() : SampleMap(0) {}
+
+SampleMap::SampleMap(uint64_t id) : HistogramSamples(id) {}
SampleMap::~SampleMap() {}
diff --git a/chromium/base/metrics/sample_map.h b/chromium/base/metrics/sample_map.h
index 952d34a1c4a..da536e31e67 100644
--- a/chromium/base/metrics/sample_map.h
+++ b/chromium/base/metrics/sample_map.h
@@ -8,18 +8,22 @@
#ifndef BASE_METRICS_SAMPLE_MAP_H_
#define BASE_METRICS_SAMPLE_MAP_H_
+#include <stdint.h>
+
#include <map>
#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/metrics/histogram_base.h"
#include "base/metrics/histogram_samples.h"
namespace base {
-class BASE_EXPORT_PRIVATE SampleMap : public HistogramSamples {
+class BASE_EXPORT SampleMap : public HistogramSamples {
public:
SampleMap();
+ explicit SampleMap(uint64_t id);
~SampleMap() override;
// HistogramSamples implementation:
@@ -40,7 +44,7 @@ class BASE_EXPORT_PRIVATE SampleMap : public HistogramSamples {
DISALLOW_COPY_AND_ASSIGN(SampleMap);
};
-class BASE_EXPORT_PRIVATE SampleMapIterator : public SampleCountIterator {
+class BASE_EXPORT SampleMapIterator : public SampleCountIterator {
public:
typedef std::map<HistogramBase::Sample, HistogramBase::Count>
SampleToCountMap;
diff --git a/chromium/base/metrics/sample_map_unittest.cc b/chromium/base/metrics/sample_map_unittest.cc
index 22ce8e1c8e3..c941d65f061 100644
--- a/chromium/base/metrics/sample_map_unittest.cc
+++ b/chromium/base/metrics/sample_map_unittest.cc
@@ -11,7 +11,7 @@ namespace base {
namespace {
TEST(SampleMapTest, AccumulateTest) {
- SampleMap samples;
+ SampleMap samples(1);
samples.Accumulate(1, 100);
samples.Accumulate(2, 200);
@@ -25,8 +25,8 @@ TEST(SampleMapTest, AccumulateTest) {
}
TEST(SampleMapTest, AddSubtractTest) {
- SampleMap samples1;
- SampleMap samples2;
+ SampleMap samples1(1);
+ SampleMap samples2(2);
samples1.Accumulate(1, 100);
samples1.Accumulate(2, 100);
@@ -56,7 +56,7 @@ TEST(SampleMapTest, AddSubtractTest) {
}
TEST(SampleMapIteratorTest, IterateTest) {
- SampleMap samples;
+ SampleMap samples(1);
samples.Accumulate(1, 100);
samples.Accumulate(2, 200);
samples.Accumulate(4, -300);
@@ -91,14 +91,14 @@ TEST(SampleMapIteratorTest, IterateTest) {
}
TEST(SampleMapIteratorTest, SkipEmptyRanges) {
- SampleMap samples;
+ SampleMap samples(1);
samples.Accumulate(5, 1);
samples.Accumulate(10, 2);
samples.Accumulate(15, 3);
samples.Accumulate(20, 4);
samples.Accumulate(25, 5);
- SampleMap samples2;
+ SampleMap samples2(2);
samples2.Accumulate(5, 1);
samples2.Accumulate(20, 4);
samples2.Accumulate(25, 5);
@@ -132,7 +132,7 @@ TEST(SampleMapIteratorTest, SkipEmptyRanges) {
#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST
TEST(SampleMapIteratorDeathTest, IterateDoneTest) {
- SampleMap samples;
+ SampleMap samples(1);
scoped_ptr<SampleCountIterator> it = samples.Iterator();
diff --git a/chromium/base/metrics/sample_vector.cc b/chromium/base/metrics/sample_vector.cc
index 1202527545c..46faef068fd 100644
--- a/chromium/base/metrics/sample_vector.cc
+++ b/chromium/base/metrics/sample_vector.cc
@@ -13,8 +13,27 @@ typedef HistogramBase::Count Count;
typedef HistogramBase::Sample Sample;
SampleVector::SampleVector(const BucketRanges* bucket_ranges)
- : counts_(bucket_ranges->bucket_count()),
+ : SampleVector(0, bucket_ranges) {}
+
+SampleVector::SampleVector(uint64_t id, const BucketRanges* bucket_ranges)
+ : HistogramSamples(id),
+ local_counts_(bucket_ranges->bucket_count()),
+ counts_(&local_counts_[0]),
+ counts_size_(local_counts_.size()),
+ bucket_ranges_(bucket_ranges) {
+ CHECK_GE(bucket_ranges_->bucket_count(), 1u);
+}
+
+SampleVector::SampleVector(uint64_t id,
+ HistogramBase::AtomicCount* counts,
+ size_t counts_size,
+ Metadata* meta,
+ const BucketRanges* bucket_ranges)
+ : HistogramSamples(id, meta),
+ counts_(counts),
+ counts_size_(bucket_ranges->bucket_count()),
bucket_ranges_(bucket_ranges) {
+ CHECK_LE(bucket_ranges_->bucket_count(), counts_size_);
CHECK_GE(bucket_ranges_->bucket_count(), 1u);
}
@@ -35,20 +54,20 @@ Count SampleVector::GetCount(Sample value) const {
Count SampleVector::TotalCount() const {
Count count = 0;
- for (size_t i = 0; i < counts_.size(); i++) {
+ for (size_t i = 0; i < counts_size_; i++) {
count += subtle::NoBarrier_Load(&counts_[i]);
}
return count;
}
Count SampleVector::GetCountAtIndex(size_t bucket_index) const {
- DCHECK(bucket_index < counts_.size());
+ DCHECK(bucket_index < counts_size_);
return subtle::NoBarrier_Load(&counts_[bucket_index]);
}
scoped_ptr<SampleCountIterator> SampleVector::Iterator() const {
return scoped_ptr<SampleCountIterator>(
- new SampleVectorIterator(&counts_, bucket_ranges_));
+ new SampleVectorIterator(counts_, counts_size_, bucket_ranges_));
}
bool SampleVector::AddSubtractImpl(SampleCountIterator* iter,
@@ -59,7 +78,7 @@ bool SampleVector::AddSubtractImpl(SampleCountIterator* iter,
// Go through the iterator and add the counts into correct bucket.
size_t index = 0;
- while (index < counts_.size() && !iter->Done()) {
+ while (index < counts_size_ && !iter->Done()) {
iter->Get(&min, &max, &count);
if (min == bucket_ranges_->range(index) &&
max == bucket_ranges_->range(index + 1)) {
@@ -109,19 +128,33 @@ size_t SampleVector::GetBucketIndex(Sample value) const {
return mid;
}
-SampleVectorIterator::SampleVectorIterator(const std::vector<Count>* counts,
- const BucketRanges* bucket_ranges)
+SampleVectorIterator::SampleVectorIterator(
+ const std::vector<HistogramBase::AtomicCount>* counts,
+ const BucketRanges* bucket_ranges)
+ : counts_(&(*counts)[0]),
+ counts_size_(counts->size()),
+ bucket_ranges_(bucket_ranges),
+ index_(0) {
+ CHECK_GE(bucket_ranges_->bucket_count(), counts_size_);
+ SkipEmptyBuckets();
+}
+
+SampleVectorIterator::SampleVectorIterator(
+ const HistogramBase::AtomicCount* counts,
+ size_t counts_size,
+ const BucketRanges* bucket_ranges)
: counts_(counts),
+ counts_size_(counts_size),
bucket_ranges_(bucket_ranges),
index_(0) {
- CHECK_GE(bucket_ranges_->bucket_count(), counts_->size());
+ CHECK_GE(bucket_ranges_->bucket_count(), counts_size_);
SkipEmptyBuckets();
}
SampleVectorIterator::~SampleVectorIterator() {}
bool SampleVectorIterator::Done() const {
- return index_ >= counts_->size();
+ return index_ >= counts_size_;
}
void SampleVectorIterator::Next() {
@@ -139,7 +172,7 @@ void SampleVectorIterator::Get(HistogramBase::Sample* min,
if (max != NULL)
*max = bucket_ranges_->range(index_ + 1);
if (count != NULL)
- *count = subtle::NoBarrier_Load(&(*counts_)[index_]);
+ *count = subtle::NoBarrier_Load(&counts_[index_]);
}
bool SampleVectorIterator::GetBucketIndex(size_t* index) const {
@@ -153,8 +186,8 @@ void SampleVectorIterator::SkipEmptyBuckets() {
if (Done())
return;
- while (index_ < counts_->size()) {
- if (subtle::NoBarrier_Load(&(*counts_)[index_]) != 0)
+ while (index_ < counts_size_) {
+ if (subtle::NoBarrier_Load(&counts_[index_]) != 0)
return;
index_++;
}
diff --git a/chromium/base/metrics/sample_vector.h b/chromium/base/metrics/sample_vector.h
index 55f9b965cc6..0317869f95f 100644
--- a/chromium/base/metrics/sample_vector.h
+++ b/chromium/base/metrics/sample_vector.h
@@ -8,10 +8,14 @@
#ifndef BASE_METRICS_SAMPLE_VECTOR_H_
#define BASE_METRICS_SAMPLE_VECTOR_H_
+#include <stddef.h>
+#include <stdint.h>
+
#include <vector>
#include "base/compiler_specific.h"
#include "base/gtest_prod_util.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/metrics/histogram_base.h"
#include "base/metrics/histogram_samples.h"
@@ -20,9 +24,15 @@ namespace base {
class BucketRanges;
-class BASE_EXPORT_PRIVATE SampleVector : public HistogramSamples {
+class BASE_EXPORT SampleVector : public HistogramSamples {
public:
explicit SampleVector(const BucketRanges* bucket_ranges);
+ SampleVector(uint64_t id, const BucketRanges* bucket_ranges);
+ SampleVector(uint64_t id,
+ HistogramBase::AtomicCount* counts,
+ size_t counts_size,
+ Metadata* meta,
+ const BucketRanges* bucket_ranges);
~SampleVector() override;
// HistogramSamples implementation:
@@ -45,7 +55,14 @@ class BASE_EXPORT_PRIVATE SampleVector : public HistogramSamples {
private:
FRIEND_TEST_ALL_PREFIXES(HistogramTest, CorruptSampleCounts);
- std::vector<HistogramBase::AtomicCount> counts_;
+ // In the case where this class manages the memory, here it is.
+ std::vector<HistogramBase::AtomicCount> local_counts_;
+
+ // These are raw pointers rather than objects for flexibility. The actual
+ // memory is either managed by local_counts_ above or by an external object
+ // and passed in directly.
+ HistogramBase::AtomicCount* counts_;
+ size_t counts_size_;
// Shares the same BucketRanges with Histogram object.
const BucketRanges* const bucket_ranges_;
@@ -53,10 +70,13 @@ class BASE_EXPORT_PRIVATE SampleVector : public HistogramSamples {
DISALLOW_COPY_AND_ASSIGN(SampleVector);
};
-class BASE_EXPORT_PRIVATE SampleVectorIterator : public SampleCountIterator {
+class BASE_EXPORT SampleVectorIterator : public SampleCountIterator {
public:
SampleVectorIterator(const std::vector<HistogramBase::AtomicCount>* counts,
const BucketRanges* bucket_ranges);
+ SampleVectorIterator(const HistogramBase::AtomicCount* counts,
+ size_t counts_size,
+ const BucketRanges* bucket_ranges);
~SampleVectorIterator() override;
// SampleCountIterator implementation:
@@ -72,7 +92,8 @@ class BASE_EXPORT_PRIVATE SampleVectorIterator : public SampleCountIterator {
private:
void SkipEmptyBuckets();
- const std::vector<HistogramBase::AtomicCount>* counts_;
+ const HistogramBase::AtomicCount* counts_;
+ size_t counts_size_;
const BucketRanges* bucket_ranges_;
size_t index_;
diff --git a/chromium/base/metrics/sample_vector_unittest.cc b/chromium/base/metrics/sample_vector_unittest.cc
index fd423766699..744cbfaba0f 100644
--- a/chromium/base/metrics/sample_vector_unittest.cc
+++ b/chromium/base/metrics/sample_vector_unittest.cc
@@ -4,6 +4,9 @@
#include "base/metrics/sample_vector.h"
+#include <limits.h>
+#include <stddef.h>
+
#include <vector>
#include "base/memory/scoped_ptr.h"
@@ -20,7 +23,7 @@ TEST(SampleVectorTest, AccumulateTest) {
ranges.set_range(0, 1);
ranges.set_range(1, 5);
ranges.set_range(2, 10);
- SampleVector samples(&ranges);
+ SampleVector samples(1, &ranges);
samples.Accumulate(1, 200);
samples.Accumulate(2, -300);
@@ -50,7 +53,7 @@ TEST(SampleVectorTest, AddSubtractTest) {
ranges.set_range(3, 3);
ranges.set_range(4, INT_MAX);
- SampleVector samples1(&ranges);
+ SampleVector samples1(1, &ranges);
samples1.Accumulate(0, 100);
samples1.Accumulate(2, 100);
samples1.Accumulate(4, 100);
@@ -58,7 +61,7 @@ TEST(SampleVectorTest, AddSubtractTest) {
EXPECT_EQ(300, samples1.TotalCount());
EXPECT_EQ(samples1.redundant_count(), samples1.TotalCount());
- SampleVector samples2(&ranges);
+ SampleVector samples2(2, &ranges);
samples2.Accumulate(1, 200);
samples2.Accumulate(2, 200);
samples2.Accumulate(4, 200);
@@ -91,7 +94,7 @@ TEST(SampleVectorDeathTest, BucketIndexTest) {
// [0, 1) [1, 2) [2, 4) [4, 8) [8, 16) [16, 32) [32, 64) [64, INT_MAX)
BucketRanges ranges(9);
Histogram::InitializeBucketRanges(1, 64, &ranges);
- SampleVector samples(&ranges);
+ SampleVector samples(1, &ranges);
// Normal case
samples.Accumulate(0, 1);
@@ -113,7 +116,7 @@ TEST(SampleVectorDeathTest, BucketIndexTest) {
ranges2.set_range(0, 1);
ranges2.set_range(1, 5);
ranges2.set_range(2, 10);
- SampleVector samples2(&ranges2);
+ SampleVector samples2(2, &ranges2);
// Normal case.
samples2.Accumulate(1, 1);
@@ -134,7 +137,7 @@ TEST(SampleVectorDeathTest, AddSubtractBucketNotMatchTest) {
ranges1.set_range(0, 1);
ranges1.set_range(1, 3);
ranges1.set_range(2, 5);
- SampleVector samples1(&ranges1);
+ SampleVector samples1(1, &ranges1);
// Custom buckets 2: [0, 1) [1, 3) [3, 6) [6, 7)
BucketRanges ranges2(5);
@@ -143,7 +146,7 @@ TEST(SampleVectorDeathTest, AddSubtractBucketNotMatchTest) {
ranges2.set_range(2, 3);
ranges2.set_range(3, 6);
ranges2.set_range(4, 7);
- SampleVector samples2(&ranges2);
+ SampleVector samples2(2, &ranges2);
samples2.Accumulate(1, 100);
samples1.Add(samples2);
@@ -209,7 +212,7 @@ TEST(SampleVectorIteratorTest, IterateTest) {
EXPECT_TRUE(it.Done());
// Create iterator from SampleVector.
- SampleVector samples(&ranges);
+ SampleVector samples(1, &ranges);
samples.Accumulate(0, 0);
samples.Accumulate(1, 1);
samples.Accumulate(2, 2);
@@ -239,7 +242,7 @@ TEST(SampleVectorIteratorDeathTest, IterateDoneTest) {
ranges.set_range(2, 2);
ranges.set_range(3, 3);
ranges.set_range(4, INT_MAX);
- SampleVector samples(&ranges);
+ SampleVector samples(1, &ranges);
scoped_ptr<SampleCountIterator> it = samples.Iterator();
diff --git a/chromium/base/metrics/sparse_histogram.cc b/chromium/base/metrics/sparse_histogram.cc
index 39c276d7877..1ed1e78654d 100644
--- a/chromium/base/metrics/sparse_histogram.cc
+++ b/chromium/base/metrics/sparse_histogram.cc
@@ -4,6 +4,9 @@
#include "base/metrics/sparse_histogram.h"
+#include <utility>
+
+#include "base/metrics/metrics_hashes.h"
#include "base/metrics/sample_map.h"
#include "base/metrics/statistics_recorder.h"
#include "base/pickle.h"
@@ -17,7 +20,7 @@ typedef HistogramBase::Sample Sample;
// static
HistogramBase* SparseHistogram::FactoryGet(const std::string& name,
- int32 flags) {
+ int32_t flags) {
HistogramBase* histogram = StatisticsRecorder::FindHistogram(name);
if (!histogram) {
@@ -33,6 +36,10 @@ HistogramBase* SparseHistogram::FactoryGet(const std::string& name,
SparseHistogram::~SparseHistogram() {}
+uint64_t SparseHistogram::name_hash() const {
+ return samples_.id();
+}
+
HistogramType SparseHistogram::GetHistogramType() const {
return SPARSE_HISTOGRAM;
}
@@ -63,11 +70,11 @@ void SparseHistogram::AddCount(Sample value, int count) {
}
scoped_ptr<HistogramSamples> SparseHistogram::SnapshotSamples() const {
- scoped_ptr<SampleMap> snapshot(new SampleMap());
+ scoped_ptr<SampleMap> snapshot(new SampleMap(name_hash()));
base::AutoLock auto_lock(lock_);
snapshot->Add(samples_);
- return snapshot.Pass();
+ return std::move(snapshot);
}
void SparseHistogram::AddSamples(const HistogramSamples& samples) {
@@ -95,7 +102,8 @@ bool SparseHistogram::SerializeInfoImpl(Pickle* pickle) const {
}
SparseHistogram::SparseHistogram(const std::string& name)
- : HistogramBase(name) {}
+ : HistogramBase(name),
+ samples_(HashMetricName(name)) {}
HistogramBase* SparseHistogram::DeserializeInfoImpl(PickleIterator* iter) {
std::string histogram_name;
@@ -116,7 +124,7 @@ void SparseHistogram::GetParameters(DictionaryValue* params) const {
}
void SparseHistogram::GetCountAndBucketData(Count* count,
- int64* sum,
+ int64_t* sum,
ListValue* buckets) const {
// TODO(kaiwang): Implement. (See HistogramBase::WriteJSON.)
}
diff --git a/chromium/base/metrics/sparse_histogram.h b/chromium/base/metrics/sparse_histogram.h
index 3abd0805369..a77c020d4cb 100644
--- a/chromium/base/metrics/sparse_histogram.h
+++ b/chromium/base/metrics/sparse_histogram.h
@@ -5,13 +5,16 @@
#ifndef BASE_METRICS_SPARSE_HISTOGRAM_H_
#define BASE_METRICS_SPARSE_HISTOGRAM_H_
+#include <stddef.h>
+#include <stdint.h>
+
#include <map>
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/metrics/histogram_base.h"
#include "base/metrics/sample_map.h"
@@ -28,15 +31,16 @@ namespace base {
class HistogramSamples;
-class BASE_EXPORT_PRIVATE SparseHistogram : public HistogramBase {
+class BASE_EXPORT SparseHistogram : public HistogramBase {
public:
// If there's one with same name, return the existing one. If not, create a
// new one.
- static HistogramBase* FactoryGet(const std::string& name, int32 flags);
+ static HistogramBase* FactoryGet(const std::string& name, int32_t flags);
~SparseHistogram() override;
// HistogramBase implementation:
+ uint64_t name_hash() const override;
HistogramType GetHistogramType() const override;
bool HasConstructionArguments(Sample expected_minimum,
Sample expected_maximum,
@@ -57,13 +61,13 @@ class BASE_EXPORT_PRIVATE SparseHistogram : public HistogramBase {
// Clients should always use FactoryGet to create SparseHistogram.
explicit SparseHistogram(const std::string& name);
- friend BASE_EXPORT_PRIVATE HistogramBase* DeserializeHistogramInfo(
+ friend BASE_EXPORT HistogramBase* DeserializeHistogramInfo(
base::PickleIterator* iter);
static HistogramBase* DeserializeInfoImpl(base::PickleIterator* iter);
void GetParameters(DictionaryValue* params) const override;
void GetCountAndBucketData(Count* count,
- int64* sum,
+ int64_t* sum,
ListValue* buckets) const override;
// Helpers for emitting Ascii graphic. Each method appends data to output.
diff --git a/chromium/base/metrics/statistics_recorder.cc b/chromium/base/metrics/statistics_recorder.cc
index 87ffa3dbcd0..15e48d8ae62 100644
--- a/chromium/base/metrics/statistics_recorder.cc
+++ b/chromium/base/metrics/statistics_recorder.cc
@@ -10,6 +10,7 @@
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/metrics/histogram.h"
+#include "base/metrics/metrics_hashes.h"
#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
#include "base/synchronization/lock.h"
@@ -58,9 +59,10 @@ HistogramBase* StatisticsRecorder::RegisterOrDeleteDuplicate(
histogram_to_return = histogram;
} else {
const std::string& name = histogram->histogram_name();
- HistogramMap::iterator it = histograms_->find(HistogramNameRef(name));
+ uint64_t name_hash = histogram->name_hash();
+ HistogramMap::iterator it = histograms_->find(name_hash);
if (histograms_->end() == it) {
- (*histograms_)[HistogramNameRef(name)] = histogram;
+ (*histograms_)[name_hash] = histogram;
ANNOTATE_LEAKING_OBJECT_PTR(histogram); // see crbug.com/79322
// If there are callbacks for this histogram, we set the kCallbackExists
// flag.
@@ -77,6 +79,8 @@ HistogramBase* StatisticsRecorder::RegisterOrDeleteDuplicate(
histogram_to_return = histogram;
} else {
// We already have one histogram with this name.
+ DCHECK_EQ(histogram->histogram_name(),
+ it->second->histogram_name()) << "hash collision";
histogram_to_return = it->second;
histogram_to_delete = histogram;
}
@@ -200,7 +204,7 @@ void StatisticsRecorder::GetHistograms(Histograms* output) {
return;
for (const auto& entry : *histograms_) {
- DCHECK_EQ(entry.first.name_, entry.second->histogram_name());
+ DCHECK_EQ(entry.first, entry.second->name_hash());
output->push_back(entry.second);
}
}
@@ -229,9 +233,10 @@ HistogramBase* StatisticsRecorder::FindHistogram(const std::string& name) {
if (histograms_ == NULL)
return NULL;
- HistogramMap::iterator it = histograms_->find(HistogramNameRef(name));
+ HistogramMap::iterator it = histograms_->find(HashMetricName(name));
if (histograms_->end() == it)
return NULL;
+ DCHECK_EQ(name, it->second->histogram_name()) << "hash collision";
return it->second;
}
@@ -250,9 +255,11 @@ bool StatisticsRecorder::SetCallback(
return false;
callbacks_->insert(std::make_pair(name, cb));
- auto histogram_iterator = histograms_->find(HistogramNameRef(name));
- if (histogram_iterator != histograms_->end())
- histogram_iterator->second->SetFlags(HistogramBase::kCallbackExists);
+ HistogramMap::iterator it = histograms_->find(HashMetricName(name));
+ if (it != histograms_->end()) {
+ DCHECK_EQ(name, it->second->histogram_name()) << "hash collision";
+ it->second->SetFlags(HistogramBase::kCallbackExists);
+ }
return true;
}
@@ -268,9 +275,11 @@ void StatisticsRecorder::ClearCallback(const std::string& name) {
callbacks_->erase(name);
// We also clear the flag from the histogram (if it exists).
- auto histogram_iterator = histograms_->find(HistogramNameRef(name));
- if (histogram_iterator != histograms_->end())
- histogram_iterator->second->ClearFlags(HistogramBase::kCallbackExists);
+ HistogramMap::iterator it = histograms_->find(HashMetricName(name));
+ if (it != histograms_->end()) {
+ DCHECK_EQ(name, it->second->histogram_name()) << "hash collision";
+ it->second->ClearFlags(HistogramBase::kCallbackExists);
+ }
}
// static
@@ -297,7 +306,7 @@ void StatisticsRecorder::GetSnapshot(const std::string& query,
return;
for (const auto& entry : *histograms_) {
- if (entry.first.name_.find(query) != std::string::npos)
+ if (entry.second->histogram_name().find(query) != std::string::npos)
snapshot->push_back(entry.second);
}
}
diff --git a/chromium/base/metrics/statistics_recorder.h b/chromium/base/metrics/statistics_recorder.h
index 0e5168f4137..b1d182e93e4 100644
--- a/chromium/base/metrics/statistics_recorder.h
+++ b/chromium/base/metrics/statistics_recorder.h
@@ -10,16 +10,18 @@
#ifndef BASE_METRICS_STATISTICS_RECORDER_H_
#define BASE_METRICS_STATISTICS_RECORDER_H_
+#include <stdint.h>
+
#include <list>
#include <map>
#include <string>
#include <vector>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/callback.h"
#include "base/gtest_prod_util.h"
#include "base/lazy_instance.h"
+#include "base/macros.h"
#include "base/metrics/histogram_base.h"
namespace base {
@@ -95,24 +97,9 @@ class BASE_EXPORT StatisticsRecorder {
static OnSampleCallback FindCallback(const std::string& histogram_name);
private:
- // HistogramNameRef holds a weak const ref to the name field of the associated
- // Histogram object, allowing re-use of the underlying string storage for the
- // map keys. The wrapper is required as using "const std::string&" as the key
- // results in compile errors.
- struct HistogramNameRef {
- explicit HistogramNameRef(const std::string& name) : name_(name) {};
-
- // Operator < is necessary to use this type as a std::map key.
- bool operator<(const HistogramNameRef& other) const {
- return name_ < other.name_;
- }
-
- // Weak, owned by the associated Histogram object.
- const std::string& name_;
- };
-
- // We keep all registered histograms in a map, from name to histogram.
- typedef std::map<HistogramNameRef, HistogramBase*> HistogramMap;
+ // We keep all registered histograms in a map, indexed by the hash of the
+ // name of the histogram.
+ typedef std::map<uint64_t, HistogramBase*> HistogramMap;
// We keep a map of callbacks to histograms, so that as histograms are
// created, we can set the callback properly.
@@ -121,7 +108,7 @@ class BASE_EXPORT StatisticsRecorder {
// We keep all |bucket_ranges_| in a map, from checksum to a list of
// |bucket_ranges_|. Checksum is calculated from the |ranges_| in
// |bucket_ranges_|.
- typedef std::map<uint32, std::list<const BucketRanges*>*> RangesMap;
+ typedef std::map<uint32_t, std::list<const BucketRanges*>*> RangesMap;
friend struct DefaultLazyInstanceTraits<StatisticsRecorder>;
friend class HistogramBaseTest;
diff --git a/chromium/base/metrics/statistics_recorder_unittest.cc b/chromium/base/metrics/statistics_recorder_unittest.cc
index b18c5803893..af5c1e7bbc3 100644
--- a/chromium/base/metrics/statistics_recorder_unittest.cc
+++ b/chromium/base/metrics/statistics_recorder_unittest.cc
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
+
#include <vector>
#include "base/bind.h"
@@ -72,7 +74,7 @@ TEST_F(StatisticsRecorderTest, NotInitialized) {
DeleteHistogram(histogram);
// RegisterOrDeleteDuplicateRanges is a no-op.
- BucketRanges* ranges = new BucketRanges(3);;
+ BucketRanges* ranges = new BucketRanges(3);
ranges->ResetChecksum();
EXPECT_EQ(ranges,
StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges));
@@ -83,9 +85,9 @@ TEST_F(StatisticsRecorderTest, NotInitialized) {
TEST_F(StatisticsRecorderTest, RegisterBucketRanges) {
std::vector<const BucketRanges*> registered_ranges;
- BucketRanges* ranges1 = new BucketRanges(3);;
+ BucketRanges* ranges1 = new BucketRanges(3);
ranges1->ResetChecksum();
- BucketRanges* ranges2 = new BucketRanges(4);;
+ BucketRanges* ranges2 = new BucketRanges(4);
ranges2->ResetChecksum();
// Register new ranges.
@@ -109,7 +111,7 @@ TEST_F(StatisticsRecorderTest, RegisterBucketRanges) {
EXPECT_EQ(0, ranges1->range(2));
// Register ranges with same values.
- BucketRanges* ranges3 = new BucketRanges(3);;
+ BucketRanges* ranges3 = new BucketRanges(3);
ranges3->ResetChecksum();
EXPECT_EQ(ranges1, // returning ranges1
StatisticsRecorder::RegisterOrDeleteDuplicateRanges(ranges3));
@@ -263,8 +265,7 @@ TEST_F(StatisticsRecorderTest, ToJSON) {
std::string json(StatisticsRecorder::ToJSON(std::string()));
// Check for valid JSON.
- scoped_ptr<Value> root;
- root.reset(JSONReader::DeprecatedRead(json));
+ scoped_ptr<Value> root = JSONReader::Read(json);
ASSERT_TRUE(root.get());
DictionaryValue* root_dict = NULL;
@@ -289,7 +290,7 @@ TEST_F(StatisticsRecorderTest, ToJSON) {
std::string query("TestHistogram2");
json = StatisticsRecorder::ToJSON(query);
- root.reset(JSONReader::DeprecatedRead(json));
+ root = JSONReader::Read(json);
ASSERT_TRUE(root.get());
ASSERT_TRUE(root->GetAsDictionary(&root_dict));
diff --git a/chromium/base/metrics/user_metrics.cc b/chromium/base/metrics/user_metrics.cc
index 9db5840ab57..55467e66eeb 100644
--- a/chromium/base/metrics/user_metrics.cc
+++ b/chromium/base/metrics/user_metrics.cc
@@ -4,9 +4,12 @@
#include "base/metrics/user_metrics.h"
+#include <stddef.h>
+
#include <vector>
#include "base/lazy_instance.h"
+#include "base/macros.h"
#include "base/threading/thread_checker.h"
namespace base {
diff --git a/chromium/base/move.h b/chromium/base/move.h
index 87dc52d16c5..0af416e00e1 100644
--- a/chromium/base/move.h
+++ b/chromium/base/move.h
@@ -5,230 +5,53 @@
#ifndef BASE_MOVE_H_
#define BASE_MOVE_H_
+#include <utility>
+
#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "build/build_config.h"
-// Macro with the boilerplate that makes a type move-only in C++03.
-//
-// USAGE
-//
-// This macro should be used instead of DISALLOW_COPY_AND_ASSIGN to create
-// a "move-only" type. Unlike DISALLOW_COPY_AND_ASSIGN, this macro should be
-// the first line in a class declaration.
-//
-// A class using this macro must call .Pass() (or somehow be an r-value already)
-// before it can be:
-//
-// * Passed as a function argument
-// * Used as the right-hand side of an assignment
-// * Returned from a function
-//
-// Each class will still need to define their own "move constructor" and "move
-// operator=" to make this useful. Here's an example of the macro, the move
-// constructor, and the move operator= from the scoped_ptr class:
-//
-// template <typename T>
-// class scoped_ptr {
-// MOVE_ONLY_TYPE_FOR_CPP_03(scoped_ptr, RValue)
-// public:
-// scoped_ptr(RValue& other) : ptr_(other.release()) { }
-// scoped_ptr& operator=(RValue& other) {
-// swap(other);
-// return *this;
-// }
-// };
-//
-// Note that the constructor must NOT be marked explicit.
-//
-// For consistency, the second parameter to the macro should always be RValue
-// unless you have a strong reason to do otherwise. It is only exposed as a
-// macro parameter so that the move constructor and move operator= don't look
-// like they're using a phantom type.
-//
-//
-// HOW THIS WORKS
-//
-// For a thorough explanation of this technique, see:
-//
-// http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Move_Constructor
-//
-// The summary is that we take advantage of 2 properties:
-//
-// 1) non-const references will not bind to r-values.
-// 2) C++ can apply one user-defined conversion when initializing a
-// variable.
-//
-// The first lets us disable the copy constructor and assignment operator
-// by declaring private version of them with a non-const reference parameter.
-//
-// For l-values, direct initialization still fails like in
-// DISALLOW_COPY_AND_ASSIGN because the copy constructor and assignment
-// operators are private.
-//
-// For r-values, the situation is different. The copy constructor and
-// assignment operator are not viable due to (1), so we are trying to call
-// a non-existent constructor and non-existing operator= rather than a private
-// one. Since we have not committed an error quite yet, we can provide an
-// alternate conversion sequence and a constructor. We add
-//
-// * a private struct named "RValue"
-// * a user-defined conversion "operator RValue()"
-// * a "move constructor" and "move operator=" that take the RValue& as
-// their sole parameter.
-//
-// Only r-values will trigger this sequence and execute our "move constructor"
-// or "move operator=." L-values will match the private copy constructor and
-// operator= first giving a "private in this context" error. This combination
-// gives us a move-only type.
-//
-// For signaling a destructive transfer of data from an l-value, we provide a
-// method named Pass() which creates an r-value for the current instance
-// triggering the move constructor or move operator=.
-//
-// Other ways to get r-values is to use the result of an expression like a
-// function call.
-//
-// Here's an example with comments explaining what gets triggered where:
-//
-// class Foo {
-// MOVE_ONLY_TYPE_FOR_CPP_03(Foo, RValue);
-//
-// public:
-// ... API ...
-// Foo(RValue other); // Move constructor.
-// Foo& operator=(RValue rhs); // Move operator=
-// };
-//
-// Foo MakeFoo(); // Function that returns a Foo.
-//
-// Foo f;
-// Foo f_copy(f); // ERROR: Foo(Foo&) is private in this context.
-// Foo f_assign;
-// f_assign = f; // ERROR: operator=(Foo&) is private in this context.
-//
-//
-// Foo f(MakeFoo()); // R-value so alternate conversion executed.
-// Foo f_copy(f.Pass()); // R-value so alternate conversion executed.
-// f = f_copy.Pass(); // R-value so alternate conversion executed.
-//
-//
-// IMPLEMENTATION SUBTLETIES WITH RValue
-//
-// The RValue struct is just a container for a pointer back to the original
-// object. It should only ever be created as a temporary, and no external
-// class should ever declare it or use it in a parameter.
-//
-// It is tempting to want to use the RValue type in function parameters, but
-// excluding the limited usage here for the move constructor and move
-// operator=, doing so would mean that the function could take both r-values
-// and l-values equially which is unexpected. See COMPARED To Boost.Move for
-// more details.
-//
-// An alternate, and incorrect, implementation of the RValue class used by
-// Boost.Move makes RValue a fieldless child of the move-only type. RValue&
-// is then used in place of RValue in the various operators. The RValue& is
-// "created" by doing *reinterpret_cast<RValue*>(this). This has the appeal
-// of never creating a temporary RValue struct even with optimizations
-// disabled. Also, by virtue of inheritance you can treat the RValue
-// reference as if it were the move-only type itself. Unfortunately,
-// using the result of this reinterpret_cast<> is actually undefined behavior
-// due to C++98 5.2.10.7. In certain compilers (e.g., NaCl) the optimizer
-// will generate non-working code.
-//
-// In optimized builds, both implementations generate the same assembly so we
-// choose the one that adheres to the standard.
-//
+// TODO(crbug.com/566182): DEPRECATED!
+// Use DISALLOW_COPY_AND_ASSIGN instead, or if your type will be used in
+// Callbacks, use DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND instead.
+#define MOVE_ONLY_TYPE_FOR_CPP_03(type) \
+ DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND(type)
+
+// A macro to disallow the copy constructor and copy assignment functions.
+// This should be used in the private: declarations for a class.
//
-// WHY HAVE typedef void MoveOnlyTypeForCPP03
+// Use this macro instead of DISALLOW_COPY_AND_ASSIGN if you want to pass
+// ownership of the type through a base::Callback without heap-allocating it
+// into a scoped_ptr. The class must define a move constructor and move
+// assignment operator to make this work.
//
-// Callback<>/Bind() needs to understand movable-but-not-copyable semantics
-// to call .Pass() appropriately when it is expected to transfer the value.
-// The cryptic typedef MoveOnlyTypeForCPP03 is added to make this check
-// easy and automatic in helper templates for Callback<>/Bind().
+// This version of the macro adds a Pass() function and a cryptic
+// MoveOnlyTypeForCPP03 typedef for the base::Callback implementation to use.
// See IsMoveOnlyType template and its usage in base/callback_internal.h
// for more details.
-//
-//
-// COMPARED TO C++11
-//
-// In C++11, you would implement this functionality using an r-value reference
-// and our .Pass() method would be replaced with a call to std::move().
-//
-// This emulation also has a deficiency where it uses up the single
-// user-defined conversion allowed by C++ during initialization. This can
-// cause problems in some API edge cases. For instance, in scoped_ptr, it is
-// impossible to make a function "void Foo(scoped_ptr<Parent> p)" accept a
-// value of type scoped_ptr<Child> even if you add a constructor to
-// scoped_ptr<> that would make it look like it should work. C++11 does not
-// have this deficiency.
-//
-//
-// COMPARED TO Boost.Move
-//
-// Our implementation similar to Boost.Move, but we keep the RValue struct
-// private to the move-only type, and we don't use the reinterpret_cast<> hack.
-//
-// In Boost.Move, RValue is the boost::rv<> template. This type can be used
-// when writing APIs like:
-//
-// void MyFunc(boost::rv<Foo>& f)
-//
-// that can take advantage of rv<> to avoid extra copies of a type. However you
-// would still be able to call this version of MyFunc with an l-value:
-//
-// Foo f;
-// MyFunc(f); // Uh oh, we probably just destroyed |f| w/o calling Pass().
-//
-// unless someone is very careful to also declare a parallel override like:
-//
-// void MyFunc(const Foo& f)
-//
-// that would catch the l-values first. This was declared unsafe in C++11 and
-// a C++11 compiler will explicitly fail MyFunc(f). Unfortunately, we cannot
-// ensure this in C++03.
-//
-// Since we have no need for writing such APIs yet, our implementation keeps
-// RValue private and uses a .Pass() method to do the conversion instead of
-// trying to write a version of "std::move()." Writing an API like std::move()
-// would require the RValue struct to be public.
-//
-//
-// CAVEATS
-//
-// If you include a move-only type as a field inside a class that does not
-// explicitly declare a copy constructor, the containing class's implicit
-// copy constructor will change from Containing(const Containing&) to
-// Containing(Containing&). This can cause some unexpected errors.
-//
-// http://llvm.org/bugs/show_bug.cgi?id=11528
-//
-// The workaround is to explicitly declare your copy constructor.
-//
-#define MOVE_ONLY_TYPE_FOR_CPP_03(type, rvalue_type) \
- private: \
- struct rvalue_type { \
- explicit rvalue_type(type* object) : object(object) {} \
- type* object; \
- }; \
- type(type&); \
- void operator=(type&); \
- public: \
- operator rvalue_type() { return rvalue_type(this); } \
- type Pass() WARN_UNUSED_RESULT { return type(rvalue_type(this)); } \
- typedef void MoveOnlyTypeForCPP03; \
+// TODO(crbug.com/566182): Remove this macro and use DISALLOW_COPY_AND_ASSIGN
+// everywhere instead.
+#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_MACOSX)
+#define DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND(type) \
+ private: \
+ type(const type&) = delete; \
+ void operator=(const type&) = delete; \
+ \
+ public: \
+ typedef void MoveOnlyTypeForCPP03; \
+ \
private:
-
-#define MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(type) \
- private: \
- 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); } \
+#else
+#define DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND(type) \
+ private: \
+ type(const type&) = delete; \
+ void operator=(const type&) = delete; \
+ \
+ public: \
+ type&& Pass() WARN_UNUSED_RESULT { return std::move(*this); } \
+ typedef void MoveOnlyTypeForCPP03; \
+ \
private:
+#endif
#endif // BASE_MOVE_H_
diff --git a/chromium/base/move_unittest.cc b/chromium/base/move_unittest.cc
deleted file mode 100644
index 1f4ce84cb6a..00000000000
--- a/chromium/base/move_unittest.cc
+++ /dev/null
@@ -1,49 +0,0 @@
-// 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
index 030c171eceb..60a11f2b460 100644
--- a/chromium/base/native_library_ios.mm
+++ b/chromium/base/native_library_ios.mm
@@ -16,6 +16,8 @@ std::string NativeLibraryLoadError::ToString() const {
NativeLibrary LoadNativeLibrary(const base::FilePath& library_path,
NativeLibraryLoadError* error) {
NOTIMPLEMENTED();
+ if (error)
+ error->message = "Not implemented.";
return nullptr;
}
diff --git a/chromium/base/native_library_mac.mm b/chromium/base/native_library_mac.mm
index 8122c28cf4a..16848858fd0 100644
--- a/chromium/base/native_library_mac.mm
+++ b/chromium/base/native_library_mac.mm
@@ -52,7 +52,8 @@ NativeLibrary LoadNativeLibrary(const base::FilePath& library_path,
if (library_path.Extension() == "dylib" || !DirectoryExists(library_path)) {
void* dylib = dlopen(library_path.value().c_str(), RTLD_LAZY);
if (!dylib) {
- error->message = dlerror();
+ if (error)
+ error->message = dlerror();
return NULL;
}
NativeLibrary native_lib = new NativeLibraryStruct();
diff --git a/chromium/base/native_library_unittest.cc b/chromium/base/native_library_unittest.cc
new file mode 100644
index 00000000000..b3cff1d79e3
--- /dev/null
+++ b/chromium/base/native_library_unittest.cc
@@ -0,0 +1,29 @@
+// 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_path.h"
+#include "base/native_library.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+const FilePath::CharType kDummyLibraryPath[] =
+ FILE_PATH_LITERAL("dummy_library");
+
+TEST(NativeLibraryTest, LoadFailure) {
+ NativeLibraryLoadError error;
+ NativeLibrary library =
+ LoadNativeLibrary(FilePath(kDummyLibraryPath), &error);
+ EXPECT_TRUE(library == nullptr);
+ EXPECT_FALSE(error.ToString().empty());
+}
+
+// |error| is optional and can be null.
+TEST(NativeLibraryTest, LoadFailureWithNullError) {
+ NativeLibrary library =
+ LoadNativeLibrary(FilePath(kDummyLibraryPath), nullptr);
+ EXPECT_TRUE(library == nullptr);
+}
+
+} // namespace base
diff --git a/chromium/base/numerics/safe_conversions.h b/chromium/base/numerics/safe_conversions.h
index 13c24ce4fcb..baac188fd2a 100644
--- a/chromium/base/numerics/safe_conversions.h
+++ b/chromium/base/numerics/safe_conversions.h
@@ -5,7 +5,10 @@
#ifndef BASE_NUMERICS_SAFE_CONVERSIONS_H_
#define BASE_NUMERICS_SAFE_CONVERSIONS_H_
+#include <stddef.h>
+
#include <limits>
+#include <type_traits>
#include "base/logging.h"
#include "base/numerics/safe_conversions_impl.h"
@@ -23,7 +26,7 @@ inline bool IsValueInRangeForNumericType(Src value) {
// Convenience function for determining if a numeric value is negative without
// throwing compiler warnings on: unsigned(value) < 0.
template <typename T>
-typename enable_if<std::numeric_limits<T>::is_signed, bool>::type
+typename std::enable_if<std::numeric_limits<T>::is_signed, bool>::type
IsValueNegative(T value) {
static_assert(std::numeric_limits<T>::is_specialized,
"Argument must be numeric.");
@@ -31,8 +34,8 @@ IsValueNegative(T value) {
}
template <typename T>
-typename enable_if<!std::numeric_limits<T>::is_signed, bool>::type
-IsValueNegative(T) {
+typename std::enable_if<!std::numeric_limits<T>::is_signed, bool>::type
+ IsValueNegative(T) {
static_assert(std::numeric_limits<T>::is_specialized,
"Argument must be numeric.");
return false;
@@ -47,10 +50,30 @@ inline Dst checked_cast(Src value) {
return static_cast<Dst>(value);
}
+// HandleNaN will cause this class to CHECK(false).
+struct SaturatedCastNaNBehaviorCheck {
+ template <typename T>
+ static T HandleNaN() {
+ CHECK(false);
+ return T();
+ }
+};
+
+// HandleNaN will return 0 in this case.
+struct SaturatedCastNaNBehaviorReturnZero {
+ template <typename T>
+ static T HandleNaN() {
+ return T();
+ }
+};
+
// saturated_cast<> is analogous to static_cast<> for numeric types, except
// that the specified numeric conversion will saturate rather than overflow or
-// underflow. NaN assignment to an integral will trigger a CHECK condition.
-template <typename Dst, typename Src>
+// underflow. NaN assignment to an integral will defer the behavior to a
+// specified class. By default, it will return 0.
+template <typename Dst,
+ class NaNHandler = SaturatedCastNaNBehaviorReturnZero,
+ typename Src>
inline Dst saturated_cast(Src value) {
// Optimization for floating point values, which already saturate.
if (std::numeric_limits<Dst>::is_iec559)
@@ -68,8 +91,7 @@ inline Dst saturated_cast(Src value) {
// Should fail only on attempting to assign NaN to a saturated integer.
case internal::RANGE_INVALID:
- CHECK(false);
- return std::numeric_limits<Dst>::max();
+ return NaNHandler::template HandleNaN<Dst>();
}
NOTREACHED();
diff --git a/chromium/base/numerics/safe_conversions_impl.h b/chromium/base/numerics/safe_conversions_impl.h
index f4bc9161a0d..02e68e25de9 100644
--- a/chromium/base/numerics/safe_conversions_impl.h
+++ b/chromium/base/numerics/safe_conversions_impl.h
@@ -5,6 +5,9 @@
#ifndef BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
#define BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_
+#include <limits.h>
+#include <stdint.h>
+
#include <limits>
#include "base/template_util.h"
diff --git a/chromium/base/numerics/safe_math.h b/chromium/base/numerics/safe_math.h
index cd89b2d5246..d169690a827 100644
--- a/chromium/base/numerics/safe_math.h
+++ b/chromium/base/numerics/safe_math.h
@@ -5,6 +5,8 @@
#ifndef BASE_NUMERICS_SAFE_MATH_H_
#define BASE_NUMERICS_SAFE_MATH_H_
+#include <stddef.h>
+
#include "base/numerics/safe_math_impl.h"
namespace base {
@@ -36,9 +38,8 @@ namespace internal {
// CheckedNumeric<int> checked_int = untrusted_input_value;
// int x = checked_int.ValueOrDefault(0) | kFlagValues;
// Comparison:
-// CheckedNumeric<size_t> checked_size;
-// CheckedNumeric<int> checked_size = untrusted_input_value;
-// checked_size = checked_size + HEADER LENGTH;
+// CheckedNumeric<size_t> checked_size = untrusted_input_value;
+// checked_size += HEADER LENGTH;
// if (checked_size.IsValid() && checked_size.ValueOrDie() < buffer_size)
// Do stuff...
template <typename T>
@@ -181,15 +182,15 @@ class CheckedNumeric {
template <typename Src>
static CheckedNumeric<T> cast(
Src u,
- typename enable_if<std::numeric_limits<Src>::is_specialized, int>::type =
- 0) {
+ typename std::enable_if<std::numeric_limits<Src>::is_specialized,
+ int>::type = 0) {
return u;
}
template <typename Src>
static CheckedNumeric<T> cast(
const CheckedNumeric<Src>& u,
- typename enable_if<!is_same<Src, T>::value, int>::type = 0) {
+ typename std::enable_if<!is_same<Src, T>::value, int>::type = 0) {
return u;
}
diff --git a/chromium/base/numerics/safe_math_impl.h b/chromium/base/numerics/safe_math_impl.h
index 1bb5c5b83f2..4fbcc045b84 100644
--- a/chromium/base/numerics/safe_math_impl.h
+++ b/chromium/base/numerics/safe_math_impl.h
@@ -5,11 +5,13 @@
#ifndef BASE_NUMERICS_SAFE_MATH_IMPL_H_
#define BASE_NUMERICS_SAFE_MATH_IMPL_H_
+#include <stddef.h>
#include <stdint.h>
#include <cmath>
#include <cstdlib>
#include <limits>
+#include <type_traits>
#include "base/numerics/safe_conversions.h"
#include "base/template_util.h"
@@ -63,21 +65,21 @@ struct IntegerForSizeAndSign<8, false> {
template <typename Integer>
struct UnsignedIntegerForSize {
- typedef typename enable_if<
+ typedef typename std::enable_if<
std::numeric_limits<Integer>::is_integer,
typename IntegerForSizeAndSign<sizeof(Integer), false>::type>::type type;
};
template <typename Integer>
struct SignedIntegerForSize {
- typedef typename enable_if<
+ typedef typename std::enable_if<
std::numeric_limits<Integer>::is_integer,
typename IntegerForSizeAndSign<sizeof(Integer), true>::type>::type type;
};
template <typename Integer>
struct TwiceWiderInteger {
- typedef typename enable_if<
+ typedef typename std::enable_if<
std::numeric_limits<Integer>::is_integer,
typename IntegerForSizeAndSign<
sizeof(Integer) * 2,
@@ -86,8 +88,9 @@ struct TwiceWiderInteger {
template <typename Integer>
struct PositionOfSignBit {
- static const typename enable_if<std::numeric_limits<Integer>::is_integer,
- size_t>::type value = 8 * sizeof(Integer) - 1;
+ static const typename std::enable_if<std::numeric_limits<Integer>::is_integer,
+ size_t>::type value =
+ 8 * sizeof(Integer) - 1;
};
// This is used for UnsignedAbs, where we need to support floating-point
@@ -129,7 +132,7 @@ T BinaryComplement(T x) {
// way to coalesce things into the CheckedNumericState specializations below.
template <typename T>
-typename enable_if<std::numeric_limits<T>::is_integer, T>::type
+typename std::enable_if<std::numeric_limits<T>::is_integer, T>::type
CheckedAdd(T x, T y, RangeConstraint* validity) {
// Since the value of x+y is undefined if we have a signed type, we compute
// it using the unsigned type of the same size.
@@ -152,7 +155,7 @@ CheckedAdd(T x, T y, RangeConstraint* validity) {
}
template <typename T>
-typename enable_if<std::numeric_limits<T>::is_integer, T>::type
+typename std::enable_if<std::numeric_limits<T>::is_integer, T>::type
CheckedSub(T x, T y, RangeConstraint* validity) {
// Since the value of x+y is undefined if we have a signed type, we compute
// it using the unsigned type of the same size.
@@ -179,9 +182,9 @@ CheckedSub(T x, T y, RangeConstraint* validity) {
// slow case we need to manually check that the result won't be truncated by
// checking with division against the appropriate bound.
template <typename T>
-typename enable_if<
- std::numeric_limits<T>::is_integer && sizeof(T) * 2 <= sizeof(uintmax_t),
- T>::type
+typename std::enable_if<std::numeric_limits<T>::is_integer &&
+ sizeof(T) * 2 <= sizeof(uintmax_t),
+ T>::type
CheckedMul(T x, T y, RangeConstraint* validity) {
typedef typename TwiceWiderInteger<T>::type IntermediateType;
IntermediateType tmp =
@@ -191,9 +194,10 @@ CheckedMul(T x, T y, RangeConstraint* validity) {
}
template <typename T>
-typename enable_if<std::numeric_limits<T>::is_integer&& std::numeric_limits<
- T>::is_signed&&(sizeof(T) * 2 > sizeof(uintmax_t)),
- T>::type
+typename std::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) {
@@ -220,10 +224,10 @@ CheckedMul(T x, T y, RangeConstraint* validity) {
}
template <typename T>
-typename enable_if<std::numeric_limits<T>::is_integer &&
- !std::numeric_limits<T>::is_signed &&
- (sizeof(T) * 2 > sizeof(uintmax_t)),
- T>::type
+typename std::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) {
*validity = (y == 0 || x <= std::numeric_limits<T>::max() / y)
? RANGE_VALID
@@ -233,11 +237,11 @@ CheckedMul(T x, T y, RangeConstraint* validity) {
// Division just requires a check for an invalid negation on signed min/-1.
template <typename T>
-T CheckedDiv(
- T x,
- T y,
- RangeConstraint* validity,
- typename enable_if<std::numeric_limits<T>::is_integer, int>::type = 0) {
+T CheckedDiv(T x,
+ T y,
+ RangeConstraint* validity,
+ typename std::enable_if<std::numeric_limits<T>::is_integer,
+ int>::type = 0) {
if (std::numeric_limits<T>::is_signed && x == std::numeric_limits<T>::min() &&
y == static_cast<T>(-1)) {
*validity = RANGE_OVERFLOW;
@@ -249,27 +253,27 @@ T CheckedDiv(
}
template <typename T>
-typename enable_if<
- std::numeric_limits<T>::is_integer&& std::numeric_limits<T>::is_signed,
- T>::type
+typename std::enable_if<std::numeric_limits<T>::is_integer &&
+ std::numeric_limits<T>::is_signed,
+ T>::type
CheckedMod(T x, T y, RangeConstraint* validity) {
*validity = y > 0 ? RANGE_VALID : RANGE_INVALID;
return x % y;
}
template <typename T>
-typename enable_if<
- std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed,
- T>::type
+typename std::enable_if<std::numeric_limits<T>::is_integer &&
+ !std::numeric_limits<T>::is_signed,
+ T>::type
CheckedMod(T x, T y, RangeConstraint* validity) {
*validity = RANGE_VALID;
return x % y;
}
template <typename T>
-typename enable_if<
- std::numeric_limits<T>::is_integer&& std::numeric_limits<T>::is_signed,
- T>::type
+typename std::enable_if<std::numeric_limits<T>::is_integer &&
+ std::numeric_limits<T>::is_signed,
+ T>::type
CheckedNeg(T value, RangeConstraint* validity) {
*validity =
value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW;
@@ -278,9 +282,9 @@ CheckedNeg(T value, RangeConstraint* validity) {
}
template <typename T>
-typename enable_if<
- std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed,
- T>::type
+typename std::enable_if<std::numeric_limits<T>::is_integer &&
+ !std::numeric_limits<T>::is_signed,
+ T>::type
CheckedNeg(T value, RangeConstraint* validity) {
// The only legal unsigned negation is zero.
*validity = value ? RANGE_UNDERFLOW : RANGE_VALID;
@@ -289,9 +293,9 @@ CheckedNeg(T value, RangeConstraint* validity) {
}
template <typename T>
-typename enable_if<
- std::numeric_limits<T>::is_integer&& std::numeric_limits<T>::is_signed,
- T>::type
+typename std::enable_if<std::numeric_limits<T>::is_integer &&
+ std::numeric_limits<T>::is_signed,
+ T>::type
CheckedAbs(T value, RangeConstraint* validity) {
*validity =
value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW;
@@ -299,9 +303,9 @@ CheckedAbs(T value, RangeConstraint* validity) {
}
template <typename T>
-typename enable_if<
- std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed,
- T>::type
+typename std::enable_if<std::numeric_limits<T>::is_integer &&
+ !std::numeric_limits<T>::is_signed,
+ T>::type
CheckedAbs(T value, RangeConstraint* validity) {
// T is unsigned, so |value| must already be positive.
*validity = RANGE_VALID;
@@ -309,9 +313,9 @@ CheckedAbs(T value, RangeConstraint* validity) {
}
template <typename T>
-typename enable_if<std::numeric_limits<T>::is_integer &&
- std::numeric_limits<T>::is_signed,
- typename UnsignedIntegerForSize<T>::type>::type
+typename std::enable_if<std::numeric_limits<T>::is_integer &&
+ std::numeric_limits<T>::is_signed,
+ typename UnsignedIntegerForSize<T>::type>::type
CheckedUnsignedAbs(T value) {
typedef typename UnsignedIntegerForSize<T>::type UnsignedT;
return value == std::numeric_limits<T>::min()
@@ -320,9 +324,9 @@ CheckedUnsignedAbs(T value) {
}
template <typename T>
-typename enable_if<std::numeric_limits<T>::is_integer &&
- !std::numeric_limits<T>::is_signed,
- T>::type
+typename std::enable_if<std::numeric_limits<T>::is_integer &&
+ !std::numeric_limits<T>::is_signed,
+ T>::type
CheckedUnsignedAbs(T value) {
// T is unsigned, so |value| must already be positive.
return value;
@@ -330,12 +334,12 @@ CheckedUnsignedAbs(T value) {
// These are the floating point stubs that the compiler needs to see. Only the
// negation operation is ever called.
-#define BASE_FLOAT_ARITHMETIC_STUBS(NAME) \
- template <typename T> \
- typename enable_if<std::numeric_limits<T>::is_iec559, T>::type \
- Checked##NAME(T, T, RangeConstraint*) { \
- NOTREACHED(); \
- return 0; \
+#define BASE_FLOAT_ARITHMETIC_STUBS(NAME) \
+ template <typename T> \
+ typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type \
+ Checked##NAME(T, T, RangeConstraint*) { \
+ NOTREACHED(); \
+ return 0; \
}
BASE_FLOAT_ARITHMETIC_STUBS(Add)
@@ -347,14 +351,14 @@ BASE_FLOAT_ARITHMETIC_STUBS(Mod)
#undef BASE_FLOAT_ARITHMETIC_STUBS
template <typename T>
-typename enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedNeg(
+typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedNeg(
T value,
RangeConstraint*) {
return -value;
}
template <typename T>
-typename enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedAbs(
+typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedAbs(
T value,
RangeConstraint*) {
return std::abs(value);
@@ -414,8 +418,8 @@ class CheckedNumericState<T, NUMERIC_INTEGER> {
template <typename Src>
explicit CheckedNumericState(
Src value,
- typename enable_if<std::numeric_limits<Src>::is_specialized, int>::type =
- 0)
+ typename std::enable_if<std::numeric_limits<Src>::is_specialized,
+ int>::type = 0)
: value_(static_cast<T>(value)),
validity_(DstRangeRelationToSrcRange<T>(value)) {}
@@ -439,7 +443,8 @@ class CheckedNumericState<T, NUMERIC_FLOATING> {
CheckedNumericState(
Src value,
RangeConstraint validity,
- typename enable_if<std::numeric_limits<Src>::is_integer, int>::type = 0) {
+ typename std::enable_if<std::numeric_limits<Src>::is_integer, int>::type =
+ 0) {
switch (DstRangeRelationToSrcRange<T>(value)) {
case RANGE_VALID:
value_ = static_cast<T>(value);
@@ -465,8 +470,8 @@ class CheckedNumericState<T, NUMERIC_FLOATING> {
template <typename Src>
explicit CheckedNumericState(
Src value,
- typename enable_if<std::numeric_limits<Src>::is_specialized, int>::type =
- 0)
+ typename std::enable_if<std::numeric_limits<Src>::is_specialized,
+ int>::type = 0)
: value_(static_cast<T>(value)) {}
// Copy constructor.
diff --git a/chromium/base/numerics/safe_numerics_unittest.cc b/chromium/base/numerics/safe_numerics_unittest.cc
index 81873ea2eba..cb63ad0d08f 100644
--- a/chromium/base/numerics/safe_numerics_unittest.cc
+++ b/chromium/base/numerics/safe_numerics_unittest.cc
@@ -2,19 +2,23 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#if defined(COMPILER_MSVC) && defined(ARCH_CPU_32_BITS)
-#include <mmintrin.h>
-#endif
+#include <stddef.h>
#include <stdint.h>
#include <limits>
+#include <type_traits>
#include "base/compiler_specific.h"
#include "base/numerics/safe_conversions.h"
#include "base/numerics/safe_math.h"
#include "base/template_util.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
+#if defined(COMPILER_MSVC) && defined(ARCH_CPU_32_BITS)
+#include <mmintrin.h>
+#endif
+
using std::numeric_limits;
using base::CheckedNumeric;
using base::checked_cast;
@@ -30,7 +34,6 @@ using base::internal::RANGE_INVALID;
using base::internal::RANGE_OVERFLOW;
using base::internal::RANGE_UNDERFLOW;
using base::internal::SignedIntegerForSize;
-using base::enable_if;
// These tests deliberately cause arithmetic overflows. If the compiler is
// aggressive enough, it can const fold these overflows. Disable warnings about
@@ -76,9 +79,9 @@ template <typename Dst>
static void TestSpecializedArithmetic(
const char* dst,
int line,
- typename enable_if<
- numeric_limits<Dst>::is_integer&& numeric_limits<Dst>::is_signed,
- int>::type = 0) {
+ typename std::enable_if<numeric_limits<Dst>::is_integer &&
+ numeric_limits<Dst>::is_signed,
+ int>::type = 0) {
typedef numeric_limits<Dst> DstLimits;
TEST_EXPECTED_VALIDITY(RANGE_OVERFLOW,
-CheckedNumeric<Dst>(DstLimits::min()));
@@ -132,9 +135,9 @@ template <typename Dst>
static void TestSpecializedArithmetic(
const char* dst,
int line,
- typename enable_if<
- numeric_limits<Dst>::is_integer && !numeric_limits<Dst>::is_signed,
- int>::type = 0) {
+ typename std::enable_if<numeric_limits<Dst>::is_integer &&
+ !numeric_limits<Dst>::is_signed,
+ int>::type = 0) {
typedef numeric_limits<Dst> DstLimits;
TEST_EXPECTED_VALIDITY(RANGE_VALID, -CheckedNumeric<Dst>(DstLimits::min()));
TEST_EXPECTED_VALIDITY(RANGE_VALID,
@@ -172,7 +175,7 @@ template <typename Dst>
void TestSpecializedArithmetic(
const char* dst,
int line,
- typename enable_if<numeric_limits<Dst>::is_iec559, int>::type = 0) {
+ typename std::enable_if<numeric_limits<Dst>::is_iec559, int>::type = 0) {
typedef numeric_limits<Dst> DstLimits;
TEST_EXPECTED_VALIDITY(RANGE_VALID, -CheckedNumeric<Dst>(DstLimits::min()));
@@ -347,7 +350,6 @@ struct TestNumericConversion<Dst, Src, SIGN_PRESERVING_VALUE_PRESERVING> {
"Comparison must be sign preserving and value preserving");
const CheckedNumeric<Dst> checked_dst = SrcLimits::max();
- ;
TEST_EXPECTED_VALIDITY(RANGE_VALID, checked_dst);
if (MaxExponent<Dst>::value > MaxExponent<Src>::value) {
if (MaxExponent<Dst>::value >= MaxExponent<Src>::value * 2 - 1) {
@@ -664,8 +666,25 @@ TEST(SafeNumerics, CastTests) {
EXPECT_EQ(saturated_cast<float>(-double_large), -double_infinity);
EXPECT_EQ(numeric_limits<int>::min(), saturated_cast<int>(double_small_int));
EXPECT_EQ(numeric_limits<int>::max(), saturated_cast<int>(double_large_int));
+
+ float not_a_number = std::numeric_limits<float>::infinity() -
+ std::numeric_limits<float>::infinity();
+ EXPECT_TRUE(std::isnan(not_a_number));
+ EXPECT_EQ(0, saturated_cast<int>(not_a_number));
+}
+
+#if GTEST_HAS_DEATH_TEST
+
+TEST(SafeNumerics, SaturatedCastChecks) {
+ float not_a_number = std::numeric_limits<float>::infinity() -
+ std::numeric_limits<float>::infinity();
+ EXPECT_TRUE(std::isnan(not_a_number));
+ EXPECT_DEATH((saturated_cast<int, base::SaturatedCastNaNBehaviorCheck>(
+ not_a_number)), "");
}
+#endif // GTEST_HAS_DEATH_TEST
+
TEST(SafeNumerics, IsValueInRangeForNumericType) {
EXPECT_TRUE(IsValueInRangeForNumericType<uint32_t>(0));
EXPECT_TRUE(IsValueInRangeForNumericType<uint32_t>(1));
diff --git a/chromium/base/observer_list.h b/chromium/base/observer_list.h
index a454430fc94..31564212e05 100644
--- a/chromium/base/observer_list.h
+++ b/chromium/base/observer_list.h
@@ -5,13 +5,16 @@
#ifndef BASE_OBSERVER_LIST_H_
#define BASE_OBSERVER_LIST_H_
+#include <stddef.h>
+
#include <algorithm>
#include <limits>
#include <vector>
-#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/weak_ptr.h"
+#include "base/stl_util.h"
///////////////////////////////////////////////////////////////////////////////
//
@@ -157,8 +160,7 @@ ObserverType* ObserverListBase<ObserverType>::Iterator::GetNext() {
template <class ObserverType>
void ObserverListBase<ObserverType>::AddObserver(ObserverType* obs) {
DCHECK(obs);
- if (std::find(observers_.begin(), observers_.end(), obs)
- != observers_.end()) {
+ if (ContainsValue(observers_, obs)) {
NOTREACHED() << "Observers can only be added once!";
return;
}
diff --git a/chromium/base/observer_list_threadsafe.h b/chromium/base/observer_list_threadsafe.h
index b9b4a624ca8..6154ae9b8dc 100644
--- a/chromium/base/observer_list_threadsafe.h
+++ b/chromium/base/observer_list_threadsafe.h
@@ -8,10 +8,10 @@
#include <algorithm>
#include <map>
-#include "base/basictypes.h"
#include "base/bind.h"
#include "base/location.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
#include "base/observer_list.h"
@@ -67,9 +67,8 @@ template <class T, class Method, class Params>
class UnboundMethod {
public:
UnboundMethod(Method m, const Params& p) : m_(m), p_(p) {
- COMPILE_ASSERT(
- (internal::ParamsUseScopedRefptrCorrectly<Params>::value),
- badunboundmethodparams);
+ static_assert((internal::ParamsUseScopedRefptrCorrectly<Params>::value),
+ "bad unbound method params");
}
void Run(T* obj) const {
DispatchToMethod(obj, m_, p_);
diff --git a/chromium/base/os_compat_android.cc b/chromium/base/os_compat_android.cc
index b2756b2b226..1eb6536bb1e 100644
--- a/chromium/base/os_compat_android.cc
+++ b/chromium/base/os_compat_android.cc
@@ -6,6 +6,7 @@
#include <asm/unistd.h>
#include <errno.h>
+#include <limits.h>
#include <math.h>
#include <sys/stat.h>
#include <sys/syscall.h>
diff --git a/chromium/base/path_service.cc b/chromium/base/path_service.cc
index 97a0ce5c02c..3f954d79e4b 100644
--- a/chromium/base/path_service.cc
+++ b/chromium/base/path_service.cc
@@ -16,6 +16,7 @@
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/synchronization/lock.h"
+#include "build/build_config.h"
namespace base {
@@ -126,19 +127,9 @@ struct PathData {
providers = &base_provider_posix;
#endif
}
-
- ~PathData() {
- Provider* p = providers;
- while (p) {
- Provider* next = p->next;
- if (!p->is_static)
- delete p;
- p = next;
- }
- }
};
-static LazyInstance<PathData> g_path_data = LAZY_INSTANCE_INITIALIZER;
+static LazyInstance<PathData>::Leaky g_path_data = LAZY_INSTANCE_INITIALIZER;
static PathData* GetPathData() {
return g_path_data.Pointer();
diff --git a/chromium/base/path_service_unittest.cc b/chromium/base/path_service_unittest.cc
index 569c0f482e7..2b7bea88ab1 100644
--- a/chromium/base/path_service_unittest.cc
+++ b/chromium/base/path_service_unittest.cc
@@ -4,7 +4,6 @@
#include "base/path_service.h"
-#include "base/basictypes.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
diff --git a/chromium/base/pickle.cc b/chromium/base/pickle.cc
index 489c7f890a7..d83391bb524 100644
--- a/chromium/base/pickle.cc
+++ b/chromium/base/pickle.cc
@@ -11,6 +11,7 @@
#include "base/bits.h"
#include "base/macros.h"
+#include "build/build_config.h"
namespace base {
@@ -30,7 +31,7 @@ inline bool PickleIterator::ReadBuiltinType(Type* result) {
const char* read_from = GetReadPointerAndAdvance<Type>();
if (!read_from)
return false;
- if (sizeof(Type) > sizeof(uint32))
+ if (sizeof(Type) > sizeof(uint32_t))
memcpy(result, read_from, sizeof(*result));
else
*result = *reinterpret_cast<const Type*>(read_from);
@@ -71,10 +72,10 @@ const char* PickleIterator::GetReadPointerAndAdvance(int num_bytes) {
inline const char* PickleIterator::GetReadPointerAndAdvance(
int num_elements,
size_t size_element) {
- // Check for int32 overflow.
- int64 num_bytes = static_cast<int64>(num_elements) * size_element;
+ // Check for int32_t overflow.
+ int64_t num_bytes = static_cast<int64_t>(num_elements) * size_element;
int num_bytes32 = static_cast<int>(num_bytes);
- if (num_bytes != static_cast<int64>(num_bytes32))
+ if (num_bytes != static_cast<int64_t>(num_bytes32))
return NULL;
return GetReadPointerAndAdvance(num_bytes32);
}
@@ -91,26 +92,26 @@ bool PickleIterator::ReadLong(long* result) {
return ReadBuiltinType(result);
}
-bool PickleIterator::ReadUInt16(uint16* result) {
+bool PickleIterator::ReadUInt16(uint16_t* result) {
return ReadBuiltinType(result);
}
-bool PickleIterator::ReadUInt32(uint32* result) {
+bool PickleIterator::ReadUInt32(uint32_t* result) {
return ReadBuiltinType(result);
}
-bool PickleIterator::ReadInt64(int64* result) {
+bool PickleIterator::ReadInt64(int64_t* result) {
return ReadBuiltinType(result);
}
-bool PickleIterator::ReadUInt64(uint64* result) {
+bool PickleIterator::ReadUInt64(uint64_t* result) {
return ReadBuiltinType(result);
}
bool PickleIterator::ReadSizeT(size_t* result) {
// Always read size_t as a 64-bit value to ensure compatibility between 32-bit
// and 64-bit processes.
- uint64 result_uint64 = 0;
+ uint64_t result_uint64 = 0;
bool success = ReadBuiltinType(&result_uint64);
*result = static_cast<size_t>(result_uint64);
// Fail if the cast above truncates the value.
@@ -207,7 +208,7 @@ bool PickleIterator::ReadBytes(const char** data, int length) {
return true;
}
-// Payload is uint32 aligned.
+// Payload is uint32_t aligned.
Pickle::Pickle()
: header_(NULL),
@@ -222,7 +223,7 @@ Pickle::Pickle()
Pickle::Pickle(int header_size)
: header_(NULL),
- header_size_(bits::Align(header_size, sizeof(uint32))),
+ header_size_(bits::Align(header_size, sizeof(uint32_t))),
capacity_after_header_(0),
write_offset_(0) {
DCHECK_GE(static_cast<size_t>(header_size), sizeof(Header));
@@ -242,7 +243,7 @@ Pickle::Pickle(const char* data, int data_len)
if (header_size_ > static_cast<unsigned int>(data_len))
header_size_ = 0;
- if (header_size_ != bits::Align(header_size_, sizeof(uint32)))
+ if (header_size_ != bits::Align(header_size_, sizeof(uint32_t)))
header_size_ = 0;
// If there is anything wrong with the data, we're not going to use it.
@@ -310,12 +311,12 @@ bool Pickle::WriteBytes(const void* data, int length) {
}
void Pickle::Reserve(size_t length) {
- size_t data_len = bits::Align(length, sizeof(uint32));
+ size_t data_len = bits::Align(length, sizeof(uint32_t));
DCHECK_GE(data_len, length);
#ifdef ARCH_CPU_64_BITS
- DCHECK_LE(data_len, kuint32max);
+ DCHECK_LE(data_len, std::numeric_limits<uint32_t>::max());
#endif
- DCHECK_LE(write_offset_, kuint32max - data_len);
+ DCHECK_LE(write_offset_, std::numeric_limits<uint32_t>::max() - data_len);
size_t new_size = write_offset_ + data_len;
if (new_size > capacity_after_header_)
Resize(capacity_after_header_ * 2 + new_size);
@@ -329,6 +330,13 @@ void Pickle::Resize(size_t new_capacity) {
header_ = reinterpret_cast<Header*>(p);
}
+void* Pickle::ClaimBytes(size_t num_bytes) {
+ void* p = ClaimUninitializedBytesInternal(num_bytes);
+ CHECK(p);
+ memset(p, 0, num_bytes);
+ return p;
+}
+
size_t Pickle::GetTotalAllocatedSize() const {
if (capacity_after_header_ == kCapacityReadOnly)
return 0;
@@ -354,7 +362,7 @@ bool Pickle::PeekNext(size_t header_size,
const char* start,
const char* end,
size_t* pickle_size) {
- DCHECK_EQ(header_size, bits::Align(header_size, sizeof(uint32)));
+ DCHECK_EQ(header_size, bits::Align(header_size, sizeof(uint32_t)));
DCHECK_GE(header_size, sizeof(Header));
DCHECK_LE(header_size, static_cast<size_t>(kPayloadUnit));
@@ -384,16 +392,15 @@ template void Pickle::WriteBytesStatic<2>(const void* data);
template void Pickle::WriteBytesStatic<4>(const void* data);
template void Pickle::WriteBytesStatic<8>(const void* data);
-inline void Pickle::WriteBytesCommon(const void* data, size_t length) {
+inline void* Pickle::ClaimUninitializedBytesInternal(size_t length) {
DCHECK_NE(kCapacityReadOnly, capacity_after_header_)
<< "oops: pickle is readonly";
- MSAN_CHECK_MEM_IS_INITIALIZED(data, length);
- size_t data_len = bits::Align(length, sizeof(uint32));
+ size_t data_len = bits::Align(length, sizeof(uint32_t));
DCHECK_GE(data_len, length);
#ifdef ARCH_CPU_64_BITS
- DCHECK_LE(data_len, kuint32max);
+ DCHECK_LE(data_len, std::numeric_limits<uint32_t>::max());
#endif
- DCHECK_LE(write_offset_, kuint32max - data_len);
+ DCHECK_LE(write_offset_, std::numeric_limits<uint32_t>::max() - data_len);
size_t new_size = write_offset_ + data_len;
if (new_size > capacity_after_header_) {
size_t new_capacity = capacity_after_header_ * 2;
@@ -404,10 +411,18 @@ inline void Pickle::WriteBytesCommon(const void* data, size_t length) {
}
char* write = mutable_payload() + write_offset_;
- memcpy(write, data, length);
- memset(write + length, 0, data_len - length);
- header_->payload_size = static_cast<uint32>(new_size);
+ memset(write + length, 0, data_len - length); // Always initialize padding
+ header_->payload_size = static_cast<uint32_t>(new_size);
write_offset_ = new_size;
+ return write;
+}
+
+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);
+ void* write = ClaimUninitializedBytesInternal(length);
+ memcpy(write, data, length);
}
} // namespace base
diff --git a/chromium/base/pickle.h b/chromium/base/pickle.h
index 22b8055cbae..02bc432ad0b 100644
--- a/chromium/base/pickle.h
+++ b/chromium/base/pickle.h
@@ -5,10 +5,12 @@
#ifndef BASE_PICKLE_H_
#define BASE_PICKLE_H_
+#include <stddef.h>
+#include <stdint.h>
+
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/gtest_prod_util.h"
#include "base/logging.h"
@@ -34,10 +36,10 @@ class BASE_EXPORT PickleIterator {
bool ReadBool(bool* result) WARN_UNUSED_RESULT;
bool ReadInt(int* result) WARN_UNUSED_RESULT;
bool ReadLong(long* result) WARN_UNUSED_RESULT;
- bool ReadUInt16(uint16* result) WARN_UNUSED_RESULT;
- bool ReadUInt32(uint32* result) WARN_UNUSED_RESULT;
- bool ReadInt64(int64* result) WARN_UNUSED_RESULT;
- bool ReadUInt64(uint64* result) WARN_UNUSED_RESULT;
+ bool ReadUInt16(uint16_t* result) WARN_UNUSED_RESULT;
+ bool ReadUInt32(uint32_t* result) WARN_UNUSED_RESULT;
+ bool ReadInt64(int64_t* result) WARN_UNUSED_RESULT;
+ bool ReadUInt64(uint64_t* result) WARN_UNUSED_RESULT;
bool ReadSizeT(size_t* result) WARN_UNUSED_RESULT;
bool ReadFloat(float* result) WARN_UNUSED_RESULT;
bool ReadDouble(double* result) WARN_UNUSED_RESULT;
@@ -179,22 +181,14 @@ class BASE_EXPORT Pickle {
bool WriteLongUsingDangerousNonPortableLessPersistableForm(long value) {
return WritePOD(value);
}
- bool WriteUInt16(uint16 value) {
- return WritePOD(value);
- }
- bool WriteUInt32(uint32 value) {
- return WritePOD(value);
- }
- bool WriteInt64(int64 value) {
- return WritePOD(value);
- }
- bool WriteUInt64(uint64 value) {
- return WritePOD(value);
- }
+ bool WriteUInt16(uint16_t value) { return WritePOD(value); }
+ bool WriteUInt32(uint32_t value) { return WritePOD(value); }
+ bool WriteInt64(int64_t value) { return WritePOD(value); }
+ bool WriteUInt64(uint64_t value) { return WritePOD(value); }
bool WriteSizeT(size_t value) {
// Always write size_t as a 64-bit value to ensure compatibility between
// 32-bit and 64-bit processes.
- return WritePOD(static_cast<uint64>(value));
+ return WritePOD(static_cast<uint64_t>(value));
}
bool WriteFloat(float value) {
return WritePOD(value);
@@ -219,7 +213,7 @@ class BASE_EXPORT Pickle {
// Payload follows after allocation of Header (header size is customizable).
struct Header {
- uint32 payload_size; // Specifies the size of the payload.
+ uint32_t payload_size; // Specifies the size of the payload.
};
// Returns the header, cast to a user-specified type T. The type T must be a
@@ -265,6 +259,13 @@ class BASE_EXPORT Pickle {
// of the header.
void Resize(size_t new_capacity);
+ // Claims |num_bytes| bytes of payload. This is similar to Reserve() in that
+ // it may grow the capacity, but it also advances the write offset of the
+ // pickle by |num_bytes|. Claimed memory, including padding, is zeroed.
+ //
+ // Returns the address of the first byte claimed.
+ void* ClaimBytes(size_t num_bytes);
+
// Find the end of the pickled data that starts at range_start. Returns NULL
// if the entire Pickle is not found in the given data range.
static const char* FindNext(size_t header_size,
@@ -306,6 +307,8 @@ class BASE_EXPORT Pickle {
WriteBytesStatic<sizeof(data)>(&data);
return true;
}
+
+ inline void* ClaimUninitializedBytesInternal(size_t num_bytes);
inline void WriteBytesCommon(const void* data, size_t length);
FRIEND_TEST_ALL_PREFIXES(PickleTest, DeepCopyResize);
diff --git a/chromium/base/pickle_unittest.cc b/chromium/base/pickle_unittest.cc
index f58e7eceaf4..b195a81e5e9 100644
--- a/chromium/base/pickle_unittest.cc
+++ b/chromium/base/pickle_unittest.cc
@@ -2,9 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <limits.h>
+#include <stddef.h>
+#include <stdint.h>
+
#include <string>
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/pickle.h"
#include "base/strings/string16.h"
@@ -19,10 +23,10 @@ const bool testbool1 = false;
const bool testbool2 = true;
const int testint = 2093847192;
const long testlong = 1093847192;
-const uint16 testuint16 = 32123;
-const uint32 testuint32 = 1593847192;
-const int64 testint64 = -0x7E8CA9253104BDFCLL;
-const uint64 testuint64 = 0xCE8CA9253104BDF7ULL;
+const uint16_t testuint16 = 32123;
+const uint32_t testuint32 = 1593847192;
+const int64_t testint64 = -0x7E8CA9253104BDFCLL;
+const uint64_t testuint64 = 0xCE8CA9253104BDF7ULL;
const size_t testsizet = 0xFEDC7654;
const float testfloat = 3.1415926935f;
const double testdouble = 2.71828182845904523;
@@ -53,19 +57,19 @@ void VerifyResult(const Pickle& pickle) {
EXPECT_TRUE(iter.ReadLong(&outlong));
EXPECT_EQ(testlong, outlong);
- uint16 outuint16;
+ uint16_t outuint16;
EXPECT_TRUE(iter.ReadUInt16(&outuint16));
EXPECT_EQ(testuint16, outuint16);
- uint32 outuint32;
+ uint32_t outuint32;
EXPECT_TRUE(iter.ReadUInt32(&outuint32));
EXPECT_EQ(testuint32, outuint32);
- int64 outint64;
+ int64_t outint64;
EXPECT_TRUE(iter.ReadInt64(&outint64));
EXPECT_EQ(testint64, outint64);
- uint64 outuint64;
+ uint64_t outuint64;
EXPECT_TRUE(iter.ReadUInt64(&outuint64));
EXPECT_EQ(testuint64, outuint64);
@@ -147,12 +151,13 @@ TEST(PickleTest, EncodeDecode) {
TEST(PickleTest, SizeTFrom64Bit) {
Pickle pickle;
// Under the hood size_t is always written as a 64-bit value, so simulate a
- // 64-bit size_t even on 32-bit architectures by explicitly writing a uint64.
+ // 64-bit size_t even on 32-bit architectures by explicitly writing a
+ // uint64_t.
EXPECT_TRUE(pickle.WriteUInt64(testuint64));
PickleIterator iter(pickle);
size_t outsizet;
- if (sizeof(size_t) < sizeof(uint64)) {
+ if (sizeof(size_t) < sizeof(uint64_t)) {
// ReadSizeT() should return false when the original written value can't be
// represented as a size_t.
EXPECT_FALSE(iter.ReadSizeT(&outsizet));
@@ -398,10 +403,10 @@ TEST(PickleTest, Resize) {
// construct a message that will be exactly the size of one payload unit,
// note that any data will have a 4-byte header indicating the size
- const size_t payload_size_after_header = unit - sizeof(uint32);
+ const size_t payload_size_after_header = unit - sizeof(uint32_t);
Pickle pickle;
- pickle.WriteData(data_ptr,
- static_cast<int>(payload_size_after_header - sizeof(uint32)));
+ pickle.WriteData(
+ data_ptr, static_cast<int>(payload_size_after_header - sizeof(uint32_t)));
size_t cur_payload = payload_size_after_header;
// note: we assume 'unit' is a power of 2
@@ -409,7 +414,7 @@ TEST(PickleTest, Resize) {
EXPECT_EQ(pickle.payload_size(), payload_size_after_header);
// fill out a full page (noting data header)
- pickle.WriteData(data_ptr, static_cast<int>(unit - sizeof(uint32)));
+ pickle.WriteData(data_ptr, static_cast<int>(unit - sizeof(uint32_t)));
cur_payload += unit;
EXPECT_EQ(unit * 2, pickle.capacity_after_header());
EXPECT_EQ(cur_payload, pickle.payload_size());
@@ -430,7 +435,7 @@ struct CustomHeader : Pickle::Header {
} // namespace
TEST(PickleTest, HeaderPadding) {
- const uint32 kMagic = 0x12345678;
+ const uint32_t kMagic = 0x12345678;
Pickle pickle(sizeof(CustomHeader));
pickle.WriteInt(kMagic);
@@ -442,7 +447,7 @@ TEST(PickleTest, HeaderPadding) {
int result;
ASSERT_TRUE(iter.ReadInt(&result));
- EXPECT_EQ(static_cast<uint32>(result), kMagic);
+ EXPECT_EQ(static_cast<uint32_t>(result), kMagic);
}
TEST(PickleTest, EqualsOperator) {
@@ -524,4 +529,50 @@ TEST(PickleTest, DeepCopyResize) {
EXPECT_EQ(pickle.capacity_after_header(), pickle2.capacity_after_header());
}
+namespace {
+
+// Publicly exposes the ClaimBytes interface for testing.
+class TestingPickle : public Pickle {
+ public:
+ TestingPickle() {}
+
+ void* ClaimBytes(size_t num_bytes) { return Pickle::ClaimBytes(num_bytes); }
+};
+
+} // namespace
+
+// Checks that claimed bytes are zero-initialized.
+TEST(PickleTest, ClaimBytesInitialization) {
+ static const int kChunkSize = 64;
+ TestingPickle pickle;
+ const char* bytes = static_cast<const char*>(pickle.ClaimBytes(kChunkSize));
+ for (size_t i = 0; i < kChunkSize; ++i) {
+ EXPECT_EQ(0, bytes[i]);
+ }
+}
+
+// Checks that ClaimBytes properly advances the write offset.
+TEST(PickleTest, ClaimBytes) {
+ std::string data("Hello, world!");
+
+ TestingPickle pickle;
+ pickle.WriteSizeT(data.size());
+ void* bytes = pickle.ClaimBytes(data.size());
+ pickle.WriteInt(42);
+ memcpy(bytes, data.data(), data.size());
+
+ PickleIterator iter(pickle);
+ size_t out_data_length;
+ EXPECT_TRUE(iter.ReadSizeT(&out_data_length));
+ EXPECT_EQ(data.size(), out_data_length);
+
+ const char* out_data = nullptr;
+ EXPECT_TRUE(iter.ReadBytes(&out_data, out_data_length));
+ EXPECT_EQ(data, std::string(out_data, out_data_length));
+
+ int out_value;
+ EXPECT_TRUE(iter.ReadInt(&out_value));
+ EXPECT_EQ(42, out_value);
+}
+
} // namespace base
diff --git a/chromium/base/posix/safe_strerror.cc b/chromium/base/posix/safe_strerror.cc
index e80e8f8bd98..798658e9620 100644
--- a/chromium/base/posix/safe_strerror.cc
+++ b/chromium/base/posix/safe_strerror.cc
@@ -20,7 +20,11 @@
namespace base {
-#define USE_HISTORICAL_STRERRO_R (defined(__GLIBC__) || defined(OS_NACL))
+#if defined(__GLIBC__) || defined(OS_NACL)
+#define USE_HISTORICAL_STRERRO_R 1
+#else
+#define USE_HISTORICAL_STRERRO_R 0
+#endif
#if USE_HISTORICAL_STRERRO_R && defined(__GNUC__)
// GCC will complain about the unused second wrap function unless we tell it
diff --git a/chromium/base/posix/safe_strerror.h b/chromium/base/posix/safe_strerror.h
index 862a75066cc..29453129105 100644
--- a/chromium/base/posix/safe_strerror.h
+++ b/chromium/base/posix/safe_strerror.h
@@ -5,6 +5,8 @@
#ifndef BASE_POSIX_SAFE_STRERROR_H_
#define BASE_POSIX_SAFE_STRERROR_H_
+#include <stddef.h>
+
#include <string>
#include "base/base_export.h"
diff --git a/chromium/base/posix/unix_domain_socket_linux.cc b/chromium/base/posix/unix_domain_socket_linux.cc
index 62c930fdee7..8b3094eedfc 100644
--- a/chromium/base/posix/unix_domain_socket_linux.cc
+++ b/chromium/base/posix/unix_domain_socket_linux.cc
@@ -12,10 +12,10 @@
#include "base/files/scoped_file.h"
#include "base/logging.h"
-#include "base/memory/scoped_vector.h"
#include "base/pickle.h"
#include "base/posix/eintr_wrapper.h"
#include "base/stl_util.h"
+#include "build/build_config.h"
#if !defined(OS_NACL_NONSFI)
#include <sys/uio.h>
@@ -86,7 +86,7 @@ bool UnixDomainSocket::SendMsg(int fd,
ssize_t UnixDomainSocket::RecvMsg(int fd,
void* buf,
size_t length,
- ScopedVector<ScopedFD>* fds) {
+ std::vector<ScopedFD>* fds) {
return UnixDomainSocket::RecvMsgWithPid(fd, buf, length, fds, NULL);
}
@@ -94,7 +94,7 @@ ssize_t UnixDomainSocket::RecvMsg(int fd,
ssize_t UnixDomainSocket::RecvMsgWithPid(int fd,
void* buf,
size_t length,
- ScopedVector<ScopedFD>* fds,
+ std::vector<ScopedFD>* fds,
ProcessId* pid) {
return UnixDomainSocket::RecvMsgWithFlags(fd, buf, length, 0, fds, pid);
}
@@ -104,7 +104,7 @@ ssize_t UnixDomainSocket::RecvMsgWithFlags(int fd,
void* buf,
size_t length,
int flags,
- ScopedVector<ScopedFD>* fds,
+ std::vector<ScopedFD>* fds,
ProcessId* out_pid) {
fds->clear();
@@ -165,7 +165,7 @@ ssize_t UnixDomainSocket::RecvMsgWithFlags(int fd,
if (wire_fds) {
for (unsigned i = 0; i < wire_fds_len; ++i)
- fds->push_back(new ScopedFD(wire_fds[i]));
+ fds->push_back(ScopedFD(wire_fds[i])); // TODO(mdempsky): emplace_back
}
if (out_pid) {
@@ -219,7 +219,7 @@ ssize_t UnixDomainSocket::SendRecvMsgWithFlags(int fd,
// return EOF instead of hanging.
send_sock.reset();
- ScopedVector<ScopedFD> recv_fds;
+ std::vector<ScopedFD> recv_fds;
// When porting to OSX keep in mind it doesn't support MSG_NOSIGNAL, so the
// sender might get a SIGPIPE.
const ssize_t reply_len = RecvMsgWithFlags(
@@ -236,7 +236,7 @@ ssize_t UnixDomainSocket::SendRecvMsgWithFlags(int fd,
}
if (result_fd)
- *result_fd = recv_fds.empty() ? -1 : recv_fds[0]->release();
+ *result_fd = recv_fds.empty() ? -1 : recv_fds[0].release();
return reply_len;
}
diff --git a/chromium/base/posix/unix_domain_socket_linux.h b/chromium/base/posix/unix_domain_socket_linux.h
index 94da4b4f911..2ba739e1083 100644
--- a/chromium/base/posix/unix_domain_socket_linux.h
+++ b/chromium/base/posix/unix_domain_socket_linux.h
@@ -5,14 +5,15 @@
#ifndef BASE_POSIX_UNIX_DOMAIN_SOCKET_LINUX_H_
#define BASE_POSIX_UNIX_DOMAIN_SOCKET_LINUX_H_
+#include <stddef.h>
#include <stdint.h>
#include <sys/types.h>
#include <vector>
#include "base/base_export.h"
#include "base/files/scoped_file.h"
-#include "base/memory/scoped_vector.h"
#include "base/process/process_handle.h"
+#include "build/build_config.h"
namespace base {
@@ -42,7 +43,7 @@ class BASE_EXPORT UnixDomainSocket {
static ssize_t RecvMsg(int fd,
void* msg,
size_t length,
- ScopedVector<ScopedFD>* fds);
+ std::vector<ScopedFD>* fds);
// Same as RecvMsg above, but also returns the sender's process ID (as seen
// from the caller's namespace). However, before using this function to
@@ -51,7 +52,7 @@ class BASE_EXPORT UnixDomainSocket {
static ssize_t RecvMsgWithPid(int fd,
void* msg,
size_t length,
- ScopedVector<ScopedFD>* fds,
+ std::vector<ScopedFD>* fds,
ProcessId* pid);
#if !defined(OS_NACL_NONSFI)
@@ -94,7 +95,7 @@ class BASE_EXPORT UnixDomainSocket {
void* msg,
size_t length,
int flags,
- ScopedVector<ScopedFD>* fds,
+ std::vector<ScopedFD>* fds,
ProcessId* pid);
};
diff --git a/chromium/base/posix/unix_domain_socket_linux_unittest.cc b/chromium/base/posix/unix_domain_socket_linux_unittest.cc
index 175ec52f086..e4b63c0cd48 100644
--- a/chromium/base/posix/unix_domain_socket_linux_unittest.cc
+++ b/chromium/base/posix/unix_domain_socket_linux_unittest.cc
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
+#include <stdint.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
@@ -11,7 +13,6 @@
#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"
@@ -40,7 +41,7 @@ TEST(UnixDomainSocketTest, SendRecvMsgAbortOnReplyFDClose) {
static_cast<uint8_t*>(NULL), 0U, static_cast<int*>(NULL), request));
// Receive the message.
- ScopedVector<ScopedFD> message_fds;
+ std::vector<ScopedFD> message_fds;
uint8_t buffer[16];
ASSERT_EQ(static_cast<int>(request.size()),
UnixDomainSocket::RecvMsg(fds[0], buffer, sizeof(buffer),
@@ -95,7 +96,7 @@ TEST(UnixDomainSocketTest, RecvPid) {
// sizeof(kHello) bytes and it wasn't just truncated to fit the buffer.
char buf[sizeof(kHello) + 1];
ProcessId sender_pid;
- ScopedVector<ScopedFD> fd_vec;
+ std::vector<ScopedFD> fd_vec;
const ssize_t nread = UnixDomainSocket::RecvMsgWithPid(
recv_sock.get(), buf, sizeof(buf), &fd_vec, &sender_pid);
ASSERT_EQ(sizeof(kHello), static_cast<size_t>(nread));
@@ -124,7 +125,7 @@ TEST(UnixDomainSocketTest, RecvPidWithMaxDescriptors) {
// sizeof(kHello) bytes and it wasn't just truncated to fit the buffer.
char buf[sizeof(kHello) + 1];
ProcessId sender_pid;
- ScopedVector<ScopedFD> recv_fds;
+ std::vector<ScopedFD> recv_fds;
const ssize_t nread = UnixDomainSocket::RecvMsgWithPid(
recv_sock.get(), buf, sizeof(buf), &recv_fds, &sender_pid);
ASSERT_EQ(sizeof(kHello), static_cast<size_t>(nread));
@@ -148,7 +149,7 @@ TEST(UnixDomianSocketTest, RecvPidDisconnectedSocket) {
char ch;
ProcessId sender_pid;
- ScopedVector<ScopedFD> recv_fds;
+ std::vector<ScopedFD> recv_fds;
const ssize_t nread = UnixDomainSocket::RecvMsgWithPid(
recv_sock.get(), &ch, sizeof(ch), &recv_fds, &sender_pid);
ASSERT_EQ(0, nread);
diff --git a/chromium/base/power_monitor/power_monitor.cc b/chromium/base/power_monitor/power_monitor.cc
index 98c9c68c1df..10332995941 100644
--- a/chromium/base/power_monitor/power_monitor.cc
+++ b/chromium/base/power_monitor/power_monitor.cc
@@ -3,6 +3,9 @@
// found in the LICENSE file.
#include "base/power_monitor/power_monitor.h"
+
+#include <utility>
+
#include "base/power_monitor/power_monitor_source.h"
namespace base {
@@ -11,7 +14,7 @@ static PowerMonitor* g_power_monitor = NULL;
PowerMonitor::PowerMonitor(scoped_ptr<PowerMonitorSource> source)
: observers_(new ObserverListThreadSafe<PowerObserver>()),
- source_(source.Pass()) {
+ source_(std::move(source)) {
DCHECK(!g_power_monitor);
g_power_monitor = this;
}
diff --git a/chromium/base/power_monitor/power_monitor.h b/chromium/base/power_monitor/power_monitor.h
index 4acb3bf122d..683eeb9733c 100644
--- a/chromium/base/power_monitor/power_monitor.h
+++ b/chromium/base/power_monitor/power_monitor.h
@@ -6,7 +6,7 @@
#define BASE_POWER_MONITOR_POWER_MONITOR_H_
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/observer_list_threadsafe.h"
#include "base/power_monitor/power_observer.h"
diff --git a/chromium/base/power_monitor/power_monitor_device_source.cc b/chromium/base/power_monitor/power_monitor_device_source.cc
index 0a3997517ec..f54b7ba3c83 100644
--- a/chromium/base/power_monitor/power_monitor_device_source.cc
+++ b/chromium/base/power_monitor/power_monitor_device_source.cc
@@ -5,6 +5,7 @@
#include "base/power_monitor/power_monitor_device_source.h"
#include "base/time/time.h"
+#include "build/build_config.h"
namespace base {
diff --git a/chromium/base/power_monitor/power_monitor_device_source.h b/chromium/base/power_monitor/power_monitor_device_source.h
index fa0b039bfb4..2dabac8865e 100644
--- a/chromium/base/power_monitor/power_monitor_device_source.h
+++ b/chromium/base/power_monitor/power_monitor_device_source.h
@@ -6,11 +6,12 @@
#define BASE_POWER_MONITOR_POWER_MONITOR_DEVICE_SOURCE_H_
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/observer_list_threadsafe.h"
#include "base/power_monitor/power_monitor_source.h"
#include "base/power_monitor/power_observer.h"
+#include "build/build_config.h"
#if defined(OS_WIN)
#include <windows.h>
diff --git a/chromium/base/power_monitor/power_monitor_source.h b/chromium/base/power_monitor/power_monitor_source.h
index b8f41850ef2..e63f4f82bf9 100644
--- a/chromium/base/power_monitor/power_monitor_source.h
+++ b/chromium/base/power_monitor/power_monitor_source.h
@@ -6,7 +6,7 @@
#define BASE_POWER_MONITOR_POWER_MONITOR_SOURCE_H_
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/observer_list_threadsafe.h"
#include "base/synchronization/lock.h"
diff --git a/chromium/base/power_monitor/power_monitor_unittest.cc b/chromium/base/power_monitor/power_monitor_unittest.cc
index 2df82618f4c..798a21c8c47 100644
--- a/chromium/base/power_monitor/power_monitor_unittest.cc
+++ b/chromium/base/power_monitor/power_monitor_unittest.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/macros.h"
#include "base/power_monitor/power_monitor.h"
#include "base/test/power_monitor_test_base.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/base/prefs/default_pref_store.cc b/chromium/base/prefs/default_pref_store.cc
index efb4a754f45..b08ef7a5286 100644
--- a/chromium/base/prefs/default_pref_store.cc
+++ b/chromium/base/prefs/default_pref_store.cc
@@ -3,6 +3,9 @@
// found in the LICENSE file.
#include "base/prefs/default_pref_store.h"
+
+#include <utility>
+
#include "base/logging.h"
using base::Value;
@@ -29,7 +32,7 @@ bool DefaultPrefStore::HasObservers() const {
void DefaultPrefStore::SetDefaultValue(const std::string& key,
scoped_ptr<Value> value) {
DCHECK(!GetValue(key, NULL));
- prefs_.SetValue(key, value.Pass());
+ prefs_.SetValue(key, std::move(value));
}
void DefaultPrefStore::ReplaceDefaultValue(const std::string& key,
@@ -37,7 +40,7 @@ void DefaultPrefStore::ReplaceDefaultValue(const std::string& key,
const Value* old_value = NULL;
GetValue(key, &old_value);
bool notify = !old_value->Equals(value.get());
- prefs_.SetValue(key, value.Pass());
+ prefs_.SetValue(key, std::move(value));
if (notify)
FOR_EACH_OBSERVER(Observer, observers_, OnPrefValueChanged(key));
}
diff --git a/chromium/base/prefs/default_pref_store.h b/chromium/base/prefs/default_pref_store.h
index e736b069823..ac5364d2bb1 100644
--- a/chromium/base/prefs/default_pref_store.h
+++ b/chromium/base/prefs/default_pref_store.h
@@ -7,6 +7,7 @@
#include <string>
+#include "base/macros.h"
#include "base/observer_list.h"
#include "base/prefs/base_prefs_export.h"
#include "base/prefs/pref_store.h"
diff --git a/chromium/base/prefs/default_pref_store_unittest.cc b/chromium/base/prefs/default_pref_store_unittest.cc
index 9299937587f..597ca558a4f 100644
--- a/chromium/base/prefs/default_pref_store_unittest.cc
+++ b/chromium/base/prefs/default_pref_store_unittest.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/macros.h"
#include "base/prefs/default_pref_store.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/base/prefs/json_pref_store.cc b/chromium/base/prefs/json_pref_store.cc
index 87943d168ed..ffc750ed81b 100644
--- a/chromium/base/prefs/json_pref_store.cc
+++ b/chromium/base/prefs/json_pref_store.cc
@@ -4,7 +4,10 @@
#include "base/prefs/json_pref_store.h"
+#include <stddef.h>
+
#include <algorithm>
+#include <utility>
#include "base/bind.h"
#include "base/callback.h"
@@ -12,6 +15,7 @@
#include "base/files/file_util.h"
#include "base/json/json_file_value_serializer.h"
#include "base/json/json_string_value_serializer.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/metrics/histogram.h"
#include "base/prefs/pref_filter.h"
@@ -118,7 +122,7 @@ scoped_ptr<JsonPrefStore::ReadResult> ReadPrefsFromDisk(
scoped_ptr<JsonPrefStore::ReadResult> read_result(
new JsonPrefStore::ReadResult);
JSONFileValueDeserializer deserializer(path);
- read_result->value.reset(deserializer.Deserialize(&error_code, &error_msg));
+ read_result->value = 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());
@@ -126,7 +130,7 @@ scoped_ptr<JsonPrefStore::ReadResult> ReadPrefsFromDisk(
if (read_result->error == PersistentPrefStore::PREF_READ_ERROR_NONE)
RecordJsonDataSizeHistogram(path, deserializer.get_last_read_size());
- return read_result.Pass();
+ return read_result;
}
} // namespace
@@ -149,8 +153,7 @@ JsonPrefStore::JsonPrefStore(
: JsonPrefStore(pref_filename,
base::FilePath(),
sequenced_task_runner,
- pref_filter.Pass()) {
-}
+ std::move(pref_filter)) {}
JsonPrefStore::JsonPrefStore(
const base::FilePath& pref_filename,
@@ -163,7 +166,7 @@ JsonPrefStore::JsonPrefStore(
prefs_(new base::DictionaryValue()),
read_only_(false),
writer_(pref_filename, sequenced_task_runner),
- pref_filter_(pref_filter.Pass()),
+ pref_filter_(std::move(pref_filter)),
initialized_(false),
filtering_in_progress_(false),
pending_lossy_write_(false),
@@ -218,40 +221,41 @@ bool JsonPrefStore::GetMutableValue(const std::string& key,
void JsonPrefStore::SetValue(const std::string& key,
scoped_ptr<base::Value> value,
- uint32 flags) {
+ uint32_t flags) {
DCHECK(CalledOnValidThread());
DCHECK(value);
base::Value* old_value = nullptr;
prefs_->Get(key, &old_value);
if (!old_value || !value->Equals(old_value)) {
- prefs_->Set(key, value.Pass());
+ prefs_->Set(key, std::move(value));
ReportValueChanged(key, flags);
}
}
void JsonPrefStore::SetValueSilently(const std::string& key,
scoped_ptr<base::Value> value,
- uint32 flags) {
+ uint32_t flags) {
DCHECK(CalledOnValidThread());
DCHECK(value);
base::Value* old_value = nullptr;
prefs_->Get(key, &old_value);
if (!old_value || !value->Equals(old_value)) {
- prefs_->Set(key, value.Pass());
+ prefs_->Set(key, std::move(value));
ScheduleWrite(flags);
}
}
-void JsonPrefStore::RemoveValue(const std::string& key, uint32 flags) {
+void JsonPrefStore::RemoveValue(const std::string& key, uint32_t flags) {
DCHECK(CalledOnValidThread());
if (prefs_->RemovePath(key, nullptr))
ReportValueChanged(key, flags);
}
-void JsonPrefStore::RemoveValueSilently(const std::string& key, uint32 flags) {
+void JsonPrefStore::RemoveValueSilently(const std::string& key,
+ uint32_t flags) {
DCHECK(CalledOnValidThread());
prefs_->RemovePath(key, nullptr);
@@ -308,7 +312,7 @@ void JsonPrefStore::SchedulePendingLossyWrites() {
writer_.ScheduleWrite(this);
}
-void JsonPrefStore::ReportValueChanged(const std::string& key, uint32 flags) {
+void JsonPrefStore::ReportValueChanged(const std::string& key, uint32_t flags) {
DCHECK(CalledOnValidThread());
if (pref_filter_)
@@ -354,7 +358,6 @@ void JsonPrefStore::OnFileRead(scoped_ptr<ReadResult> read_result) {
case PREF_READ_ERROR_NO_FILE:
// If the file just doesn't exist, maybe this is first run. In any case
// there's no harm in writing out default prefs in this case.
- break;
case PREF_READ_ERROR_JSON_PARSE:
case PREF_READ_ERROR_JSON_REPEAT:
break;
@@ -362,8 +365,6 @@ void JsonPrefStore::OnFileRead(scoped_ptr<ReadResult> read_result) {
// This is a special error code to be returned by ReadPrefs when it
// can't complete synchronously, it should never be returned by the read
// operation itself.
- NOTREACHED();
- break;
case PREF_READ_ERROR_MAX_ENUM:
NOTREACHED();
break;
@@ -377,9 +378,10 @@ void JsonPrefStore::OnFileRead(scoped_ptr<ReadResult> read_result) {
&JsonPrefStore::FinalizeFileRead, AsWeakPtr(),
initialization_successful));
pref_filter_->FilterOnLoad(post_filter_on_load_callback,
- unfiltered_prefs.Pass());
+ std::move(unfiltered_prefs));
} else {
- FinalizeFileRead(initialization_successful, unfiltered_prefs.Pass(), false);
+ FinalizeFileRead(initialization_successful, std::move(unfiltered_prefs),
+ false);
}
}
@@ -419,7 +421,7 @@ void JsonPrefStore::FinalizeFileRead(bool initialization_successful,
return;
}
- prefs_ = prefs.Pass();
+ prefs_ = std::move(prefs);
initialized_ = true;
@@ -436,7 +438,7 @@ void JsonPrefStore::FinalizeFileRead(bool initialization_successful,
return;
}
-void JsonPrefStore::ScheduleWrite(uint32 flags) {
+void JsonPrefStore::ScheduleWrite(uint32_t flags) {
if (read_only_)
return;
@@ -497,9 +499,9 @@ void JsonPrefStore::WriteCountHistogram::ReportOutstandingWrites() {
// There may be several report intervals that elapsed that don't have any
// writes in them. Report these too.
- int64 total_num_intervals_elapsed =
+ int64_t total_num_intervals_elapsed =
(time_since_last_report / report_interval_);
- for (int64 i = 0; i < total_num_intervals_elapsed - 1; ++i)
+ for (int64_t i = 0; i < total_num_intervals_elapsed - 1; ++i)
histogram->Add(0);
writes_since_last_report_ = 0;
diff --git a/chromium/base/prefs/json_pref_store.h b/chromium/base/prefs/json_pref_store.h
index d9dcdbdc6cd..6342977f9ba 100644
--- a/chromium/base/prefs/json_pref_store.h
+++ b/chromium/base/prefs/json_pref_store.h
@@ -5,15 +5,17 @@
#ifndef BASE_PREFS_JSON_PREF_STORE_H_
#define BASE_PREFS_JSON_PREF_STORE_H_
+#include <stdint.h>
+
#include <set>
#include <string>
-#include "base/basictypes.h"
#include "base/callback_forward.h"
#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/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
@@ -84,11 +86,11 @@ class BASE_PREFS_EXPORT JsonPrefStore
bool GetMutableValue(const std::string& key, base::Value** result) override;
void SetValue(const std::string& key,
scoped_ptr<base::Value> value,
- uint32 flags) override;
+ uint32_t flags) override;
void SetValueSilently(const std::string& key,
scoped_ptr<base::Value> value,
- uint32 flags) override;
- void RemoveValue(const std::string& key, uint32 flags) override;
+ uint32_t flags) override;
+ void RemoveValue(const std::string& key, uint32_t flags) override;
bool ReadOnly() const override;
PrefReadError GetReadError() const override;
// Note this method may be asynchronous if this instance has a |pref_filter_|
@@ -98,11 +100,11 @@ class BASE_PREFS_EXPORT JsonPrefStore
void ReadPrefsAsync(ReadErrorDelegate* error_delegate) override;
void CommitPendingWrite() override;
void SchedulePendingLossyWrites() override;
- void ReportValueChanged(const std::string& key, uint32 flags) override;
+ void ReportValueChanged(const std::string& key, uint32_t 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, uint32 flags);
+ void RemoveValueSilently(const std::string& key, uint32_t flags);
// Registers |on_next_successful_write| to be called once, on the next
// successful write event of |writer_|.
@@ -194,7 +196,7 @@ class BASE_PREFS_EXPORT JsonPrefStore
// Schedule a write with the file writer as long as |flags| doesn't contain
// WriteablePrefStore::LOSSY_PREF_WRITE_FLAG.
- void ScheduleWrite(uint32 flags);
+ void ScheduleWrite(uint32_t flags);
const base::FilePath path_;
const base::FilePath alternate_path_;
diff --git a/chromium/base/prefs/json_pref_store_unittest.cc b/chromium/base/prefs/json_pref_store_unittest.cc
index 5195a18c436..41cad8985cf 100644
--- a/chromium/base/prefs/json_pref_store_unittest.cc
+++ b/chromium/base/prefs/json_pref_store_unittest.cc
@@ -4,10 +4,15 @@
#include "base/prefs/json_pref_store.h"
+#include <stdint.h>
+
+#include <utility>
+
#include "base/bind.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/location.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
@@ -73,12 +78,12 @@ void InterceptingPrefFilter::FilterOnLoad(
const PostFilterOnLoadCallback& post_filter_on_load_callback,
scoped_ptr<base::DictionaryValue> pref_store_contents) {
post_filter_on_load_callback_ = post_filter_on_load_callback;
- intercepted_prefs_ = pref_store_contents.Pass();
+ intercepted_prefs_ = std::move(pref_store_contents);
}
void InterceptingPrefFilter::ReleasePrefs() {
EXPECT_FALSE(post_filter_on_load_callback_.is_null());
- post_filter_on_load_callback_.Run(intercepted_prefs_.Pass(), false);
+ post_filter_on_load_callback_.Run(std::move(intercepted_prefs_), false);
post_filter_on_load_callback_.Reset();
}
@@ -228,7 +233,7 @@ void RunBasicJsonPrefStoreTest(JsonPrefStore* pref_store,
WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
EXPECT_TRUE(pref_store->GetValue(kLongIntPref, &actual));
EXPECT_TRUE(actual->GetAsString(&string_value));
- int64 value;
+ int64_t value;
base::StringToInt64(string_value, &value);
EXPECT_EQ(214748364842LL, value);
@@ -348,7 +353,7 @@ TEST_F(JsonPrefStoreTest, RemoveClearsEmptyParent) {
scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
dict->SetString("key", "value");
- pref_store->SetValue("dict", dict.Pass(),
+ pref_store->SetValue("dict", std::move(dict),
WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
pref_store->RemoveValue("dict.key",
@@ -392,8 +397,9 @@ 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_.task_runner(), intercepting_pref_filter.Pass());
+ scoped_refptr<JsonPrefStore> pref_store =
+ new JsonPrefStore(input_file, message_loop_.task_runner(),
+ std::move(intercepting_pref_filter));
ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE,
pref_store->ReadPrefs());
@@ -437,8 +443,9 @@ 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_.task_runner(), intercepting_pref_filter.Pass());
+ scoped_refptr<JsonPrefStore> pref_store =
+ new JsonPrefStore(input_file, message_loop_.task_runner(),
+ std::move(intercepting_pref_filter));
MockPrefStoreObserver mock_observer;
pref_store->AddObserver(&mock_observer);
@@ -673,7 +680,7 @@ TEST_F(JsonPrefStoreTest, WriteCountHistogramTestBasic) {
base::TimeDelta::FromSeconds(10),
base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
scoped_ptr<base::Clock>(test_clock));
- int32 report_interval =
+ int32_t report_interval =
JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
histogram.RecordWriteOccured();
@@ -697,7 +704,7 @@ TEST_F(JsonPrefStoreTest, WriteCountHistogramTestSinglePeriod) {
base::TimeDelta::FromSeconds(10),
base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
scoped_ptr<base::Clock>(test_clock));
- int32 report_interval =
+ int32_t report_interval =
JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
histogram.RecordWriteOccured();
@@ -736,7 +743,7 @@ TEST_F(JsonPrefStoreTest, WriteCountHistogramTestMultiplePeriods) {
base::TimeDelta::FromSeconds(10),
base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
scoped_ptr<base::Clock>(test_clock));
- int32 report_interval =
+ int32_t report_interval =
JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
histogram.RecordWriteOccured();
@@ -775,7 +782,7 @@ TEST_F(JsonPrefStoreTest, WriteCountHistogramTestPeriodWithGaps) {
base::TimeDelta::FromSeconds(10),
base::FilePath(FILE_PATH_LITERAL("/tmp/Local State")),
scoped_ptr<base::Clock>(test_clock));
- int32 report_interval =
+ int32_t report_interval =
JsonPrefStore::WriteCountHistogram::kHistogramWriteReportIntervalMins;
// 1 write in the first period.
diff --git a/chromium/base/prefs/overlay_user_pref_store.cc b/chromium/base/prefs/overlay_user_pref_store.cc
index d76b537ce62..dd5b68e0a63 100644
--- a/chromium/base/prefs/overlay_user_pref_store.cc
+++ b/chromium/base/prefs/overlay_user_pref_store.cc
@@ -4,6 +4,8 @@
#include "base/prefs/overlay_user_pref_store.h"
+#include <utility>
+
#include "base/memory/scoped_ptr.h"
#include "base/values.h"
@@ -64,28 +66,28 @@ bool OverlayUserPrefStore::GetMutableValue(const std::string& key,
void OverlayUserPrefStore::SetValue(const std::string& key,
scoped_ptr<base::Value> value,
- uint32 flags) {
+ uint32_t flags) {
if (!ShallBeStoredInOverlay(key)) {
- underlay_->SetValue(GetUnderlayKey(key), value.Pass(), flags);
+ underlay_->SetValue(GetUnderlayKey(key), std::move(value), flags);
return;
}
- if (overlay_.SetValue(key, value.Pass()))
+ if (overlay_.SetValue(key, std::move(value)))
ReportValueChanged(key, flags);
}
void OverlayUserPrefStore::SetValueSilently(const std::string& key,
scoped_ptr<base::Value> value,
- uint32 flags) {
+ uint32_t flags) {
if (!ShallBeStoredInOverlay(key)) {
- underlay_->SetValueSilently(GetUnderlayKey(key), value.Pass(), flags);
+ underlay_->SetValueSilently(GetUnderlayKey(key), std::move(value), flags);
return;
}
- overlay_.SetValue(key, value.Pass());
+ overlay_.SetValue(key, std::move(value));
}
-void OverlayUserPrefStore::RemoveValue(const std::string& key, uint32 flags) {
+void OverlayUserPrefStore::RemoveValue(const std::string& key, uint32_t flags) {
if (!ShallBeStoredInOverlay(key)) {
underlay_->RemoveValue(GetUnderlayKey(key), flags);
return;
@@ -126,7 +128,7 @@ void OverlayUserPrefStore::SchedulePendingLossyWrites() {
}
void OverlayUserPrefStore::ReportValueChanged(const std::string& key,
- uint32 flags) {
+ uint32_t flags) {
FOR_EACH_OBSERVER(PrefStore::Observer, observers_, OnPrefValueChanged(key));
}
diff --git a/chromium/base/prefs/overlay_user_pref_store.h b/chromium/base/prefs/overlay_user_pref_store.h
index 737b4262f3e..35ada57123f 100644
--- a/chromium/base/prefs/overlay_user_pref_store.h
+++ b/chromium/base/prefs/overlay_user_pref_store.h
@@ -5,10 +5,12 @@
#ifndef BASE_PREFS_OVERLAY_USER_PREF_STORE_H_
#define BASE_PREFS_OVERLAY_USER_PREF_STORE_H_
+#include <stdint.h>
+
#include <map>
#include <string>
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/observer_list.h"
#include "base/prefs/base_prefs_export.h"
@@ -41,18 +43,18 @@ class BASE_PREFS_EXPORT OverlayUserPrefStore : public PersistentPrefStore,
bool GetMutableValue(const std::string& key, base::Value** result) override;
void SetValue(const std::string& key,
scoped_ptr<base::Value> value,
- uint32 flags) override;
+ uint32_t flags) override;
void SetValueSilently(const std::string& key,
scoped_ptr<base::Value> value,
- uint32 flags) override;
- void RemoveValue(const std::string& key, uint32 flags) override;
+ uint32_t flags) override;
+ void RemoveValue(const std::string& key, uint32_t flags) override;
bool ReadOnly() const override;
PrefReadError GetReadError() const override;
PrefReadError ReadPrefs() override;
void ReadPrefsAsync(ReadErrorDelegate* delegate) override;
void CommitPendingWrite() override;
void SchedulePendingLossyWrites() override;
- void ReportValueChanged(const std::string& key, uint32 flags) override;
+ void ReportValueChanged(const std::string& key, uint32_t flags) override;
// Methods of PrefStore::Observer.
void OnPrefValueChanged(const std::string& key) override;
diff --git a/chromium/base/prefs/pref_change_registrar.h b/chromium/base/prefs/pref_change_registrar.h
index acf0a684962..cd5a233244c 100644
--- a/chromium/base/prefs/pref_change_registrar.h
+++ b/chromium/base/prefs/pref_change_registrar.h
@@ -8,8 +8,8 @@
#include <map>
#include <string>
-#include "base/basictypes.h"
#include "base/callback.h"
+#include "base/macros.h"
#include "base/prefs/base_prefs_export.h"
#include "base/prefs/pref_observer.h"
diff --git a/chromium/base/prefs/pref_member.cc b/chromium/base/prefs/pref_member.cc
index 64c3d6a9934..934237d37ca 100644
--- a/chromium/base/prefs/pref_member.cc
+++ b/chromium/base/prefs/pref_member.cc
@@ -4,6 +4,8 @@
#include "base/prefs/pref_member.h"
+#include <utility>
+
#include "base/callback.h"
#include "base/callback_helpers.h"
#include "base/location.h"
@@ -56,7 +58,7 @@ void PrefMemberBase::MoveToThread(
// Load the value from preferences if it hasn't been loaded so far.
if (!internal())
UpdateValueFromPref(base::Closure());
- internal()->MoveToThread(task_runner.Pass());
+ internal()->MoveToThread(std::move(task_runner));
}
void PrefMemberBase::OnPreferenceChanged(PrefService* service,
@@ -124,7 +126,7 @@ void PrefMemberBase::Internal::UpdateValue(
void PrefMemberBase::Internal::MoveToThread(
scoped_refptr<SingleThreadTaskRunner> task_runner) {
CheckOnCorrectThread();
- thread_task_runner_ = task_runner.Pass();
+ thread_task_runner_ = std::move(task_runner);
}
bool PrefMemberVectorStringUpdate(const base::Value& value,
diff --git a/chromium/base/prefs/pref_member.h b/chromium/base/prefs/pref_member.h
index 6dceb439ed7..4290c0db651 100644
--- a/chromium/base/prefs/pref_member.h
+++ b/chromium/base/prefs/pref_member.h
@@ -27,11 +27,11 @@
#include <string>
#include <vector>
-#include "base/basictypes.h"
#include "base/bind.h"
#include "base/callback_forward.h"
#include "base/files/file_path.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/prefs/base_prefs_export.h"
#include "base/prefs/pref_observer.h"
diff --git a/chromium/base/prefs/pref_notifier_impl.h b/chromium/base/prefs/pref_notifier_impl.h
index cbf025c0015..6e62e232549 100644
--- a/chromium/base/prefs/pref_notifier_impl.h
+++ b/chromium/base/prefs/pref_notifier_impl.h
@@ -11,6 +11,7 @@
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/containers/hash_tables.h"
+#include "base/macros.h"
#include "base/observer_list.h"
#include "base/prefs/base_prefs_export.h"
#include "base/prefs/pref_notifier.h"
diff --git a/chromium/base/prefs/pref_notifier_impl_unittest.cc b/chromium/base/prefs/pref_notifier_impl_unittest.cc
index c3cbf4f48c1..cb3c3b5ebd7 100644
--- a/chromium/base/prefs/pref_notifier_impl_unittest.cc
+++ b/chromium/base/prefs/pref_notifier_impl_unittest.cc
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
+
#include "base/bind.h"
#include "base/callback.h"
#include "base/prefs/mock_pref_change_callback.h"
diff --git a/chromium/base/prefs/pref_registry.cc b/chromium/base/prefs/pref_registry.cc
index 74f4b522088..77fb9a59ad0 100644
--- a/chromium/base/prefs/pref_registry.cc
+++ b/chromium/base/prefs/pref_registry.cc
@@ -17,7 +17,8 @@ PrefRegistry::PrefRegistry()
PrefRegistry::~PrefRegistry() {
}
-uint32 PrefRegistry::GetRegistrationFlags(const std::string& pref_name) const {
+uint32_t 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;
@@ -50,7 +51,7 @@ void PrefRegistry::SetDefaultPrefValue(const std::string& pref_name,
void PrefRegistry::RegisterPreference(const std::string& path,
base::Value* default_value,
- uint32 flags) {
+ uint32_t flags) {
base::Value::Type orig_type = default_value->GetType();
DCHECK(orig_type != base::Value::TYPE_NULL &&
orig_type != base::Value::TYPE_BINARY) <<
diff --git a/chromium/base/prefs/pref_registry.h b/chromium/base/prefs/pref_registry.h
index caf2a1afaf1..7e141d8b7e5 100644
--- a/chromium/base/prefs/pref_registry.h
+++ b/chromium/base/prefs/pref_registry.h
@@ -5,7 +5,10 @@
#ifndef BASE_PREFS_PREF_REGISTRY_H_
#define BASE_PREFS_PREF_REGISTRY_H_
+#include <stdint.h>
+
#include "base/containers/hash_tables.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/prefs/base_prefs_export.h"
#include "base/prefs/pref_value_map.h"
@@ -32,7 +35,7 @@ class BASE_PREFS_EXPORT PrefRegistry : public base::RefCounted<PrefRegistry> {
// 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 {
+ enum PrefRegistrationFlags : uint32_t {
// No flags are specified.
NO_REGISTRATION_FLAGS = 0,
@@ -44,13 +47,13 @@ class BASE_PREFS_EXPORT PrefRegistry : public base::RefCounted<PrefRegistry> {
};
typedef PrefValueMap::const_iterator const_iterator;
- typedef base::hash_map<std::string, uint32> PrefRegistrationFlagsMap;
+ typedef base::hash_map<std::string, uint32_t> 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;
+ uint32_t GetRegistrationFlags(const std::string& pref_name) const;
// Gets the registered defaults.
scoped_refptr<PrefStore> defaults();
@@ -72,7 +75,7 @@ class BASE_PREFS_EXPORT PrefRegistry : public base::RefCounted<PrefRegistry> {
// a preference. |flags| is a bitmask of |PrefRegistrationFlags|.
void RegisterPreference(const std::string& path,
base::Value* default_value,
- uint32 flags);
+ uint32_t flags);
scoped_refptr<DefaultPrefStore> defaults_;
diff --git a/chromium/base/prefs/pref_registry_simple.cc b/chromium/base/prefs/pref_registry_simple.cc
index 93c268686d5..b5c73e22cd5 100644
--- a/chromium/base/prefs/pref_registry_simple.cc
+++ b/chromium/base/prefs/pref_registry_simple.cc
@@ -66,14 +66,14 @@ void PrefRegistrySimple::RegisterDictionaryPref(
}
void PrefRegistrySimple::RegisterInt64Pref(const std::string& path,
- int64 default_value) {
+ int64_t default_value) {
RegisterPrefAndNotify(
path, new base::StringValue(base::Int64ToString(default_value)),
NO_REGISTRATION_FLAGS);
}
void PrefRegistrySimple::RegisterUint64Pref(const std::string& path,
- uint64 default_value) {
+ uint64_t default_value) {
RegisterPrefAndNotify(
path, new base::StringValue(base::Uint64ToString(default_value)),
NO_REGISTRATION_FLAGS);
@@ -81,81 +81,80 @@ void PrefRegistrySimple::RegisterUint64Pref(const std::string& path,
void PrefRegistrySimple::RegisterBooleanPref(const std::string& path,
bool default_value,
- uint32 flags) {
+ uint32_t flags) {
RegisterPrefAndNotify(path, new base::FundamentalValue(default_value), flags);
}
void PrefRegistrySimple::RegisterIntegerPref(const std::string& path,
int default_value,
- uint32 flags) {
+ uint32_t flags) {
RegisterPrefAndNotify(path, new base::FundamentalValue(default_value), flags);
}
void PrefRegistrySimple::RegisterDoublePref(const std::string& path,
double default_value,
- uint32 flags) {
+ uint32_t flags) {
RegisterPrefAndNotify(path, new base::FundamentalValue(default_value), flags);
}
void PrefRegistrySimple::RegisterStringPref(const std::string& path,
const std::string& default_value,
- uint32 flags) {
+ uint32_t flags) {
RegisterPrefAndNotify(path, new base::StringValue(default_value), flags);
}
void PrefRegistrySimple::RegisterFilePathPref(
const std::string& path,
const base::FilePath& default_value,
- uint32 flags) {
+ uint32_t flags) {
RegisterPrefAndNotify(path, new base::StringValue(default_value.value()),
flags);
}
void PrefRegistrySimple::RegisterListPref(const std::string& path,
- uint32 flags) {
+ uint32_t flags) {
RegisterPrefAndNotify(path, new base::ListValue(), flags);
}
void PrefRegistrySimple::RegisterListPref(const std::string& path,
base::ListValue* default_value,
- uint32 flags) {
+ uint32_t flags) {
RegisterPrefAndNotify(path, default_value, flags);
}
void PrefRegistrySimple::RegisterDictionaryPref(const std::string& path,
- uint32 flags) {
+ uint32_t flags) {
RegisterPrefAndNotify(path, new base::DictionaryValue(), flags);
}
void PrefRegistrySimple::RegisterDictionaryPref(
const std::string& path,
base::DictionaryValue* default_value,
- uint32 flags) {
+ uint32_t flags) {
RegisterPrefAndNotify(path, default_value, flags);
}
void PrefRegistrySimple::RegisterInt64Pref(const std::string& path,
- int64 default_value,
- uint32 flags) {
+ int64_t default_value,
+ uint32_t flags) {
RegisterPrefAndNotify(
path, new base::StringValue(base::Int64ToString(default_value)), flags);
}
void PrefRegistrySimple::RegisterUint64Pref(const std::string& path,
- uint64 default_value,
- uint32 flags) {
+ uint64_t default_value,
+ uint32_t flags) {
RegisterPrefAndNotify(
path, new base::StringValue(base::Uint64ToString(default_value)), flags);
}
void PrefRegistrySimple::OnPrefRegistered(const std::string& path,
base::Value* default_value,
- uint32 flags) {
-}
+ uint32_t flags) {}
void PrefRegistrySimple::RegisterPrefAndNotify(const std::string& path,
base::Value* default_value,
- uint32 flags) {
+ uint32_t 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 6b69e30cc0d..6afc012b3f3 100644
--- a/chromium/base/prefs/pref_registry_simple.h
+++ b/chromium/base/prefs/pref_registry_simple.h
@@ -5,8 +5,11 @@
#ifndef BASE_PREFS_PREF_REGISTRY_SIMPLE_H_
#define BASE_PREFS_PREF_REGISTRY_SIMPLE_H_
+#include <stdint.h>
+
#include <string>
+#include "base/macros.h"
#include "base/prefs/base_prefs_export.h"
#include "base/prefs/pref_registry.h"
@@ -34,36 +37,40 @@ class BASE_PREFS_EXPORT PrefRegistrySimple : public PrefRegistry {
base::ListValue* default_value);
void RegisterDictionaryPref(const std::string& path,
base::DictionaryValue* default_value);
- void RegisterInt64Pref(const std::string& path, int64 default_value);
- void RegisterUint64Pref(const std::string&, uint64 default_value);
+ void RegisterInt64Pref(const std::string& path, int64_t default_value);
+ void RegisterUint64Pref(const std::string&, uint64_t default_value);
// 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);
+ uint32_t flags);
+ void RegisterIntegerPref(const std::string&,
+ int default_value,
+ uint32_t flags);
void RegisterDoublePref(const std::string&,
double default_value,
- uint32 flags);
+ uint32_t flags);
void RegisterStringPref(const std::string&,
const std::string& default_value,
- uint32 flags);
+ uint32_t 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);
+ uint32_t flags);
+ void RegisterListPref(const std::string&, uint32_t flags);
+ void RegisterDictionaryPref(const std::string&, uint32_t flags);
void RegisterListPref(const std::string&,
base::ListValue* default_value,
- uint32 flags);
+ uint32_t flags);
void RegisterDictionaryPref(const std::string&,
base::DictionaryValue* default_value,
- uint32 flags);
- void RegisterInt64Pref(const std::string&, int64 default_value, uint32 flags);
+ uint32_t flags);
+ void RegisterInt64Pref(const std::string&,
+ int64_t default_value,
+ uint32_t flags);
void RegisterUint64Pref(const std::string&,
- uint64 default_value,
- uint32 flags);
+ uint64_t default_value,
+ uint32_t flags);
protected:
~PrefRegistrySimple() override;
@@ -71,12 +78,12 @@ class BASE_PREFS_EXPORT PrefRegistrySimple : public PrefRegistry {
// Allows subclasses to hook into pref registration.
virtual void OnPrefRegistered(const std::string&,
base::Value* default_value,
- uint32 flags);
+ uint32_t flags);
private:
void RegisterPrefAndNotify(const std::string&,
base::Value* default_value,
- uint32 flags);
+ uint32_t flags);
DISALLOW_COPY_AND_ASSIGN(PrefRegistrySimple);
};
diff --git a/chromium/base/prefs/pref_service.cc b/chromium/base/prefs/pref_service.cc
index c53b8966b34..077bb1d25ff 100644
--- a/chromium/base/prefs/pref_service.cc
+++ b/chromium/base/prefs/pref_service.cc
@@ -5,6 +5,7 @@
#include "base/prefs/pref_service.h"
#include <algorithm>
+#include <utility>
#include "base/bind.h"
#include "base/files/file_path.h"
@@ -40,8 +41,8 @@ class ReadErrorHandler : public PersistentPrefStore::ReadErrorDelegate {
// 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;
+uint32_t GetWriteFlags(const PrefService::Preference* pref) {
+ uint32_t write_flags = WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS;
if (!pref)
return write_flags;
@@ -197,7 +198,7 @@ scoped_ptr<base::DictionaryValue> PrefService::GetPreferenceValues() const {
for (const auto& it : *pref_registry_) {
out->Set(it.first, GetPreferenceValue(it.first)->CreateDeepCopy());
}
- return out.Pass();
+ return out;
}
scoped_ptr<base::DictionaryValue> PrefService::GetPreferenceValuesOmitDefaults()
@@ -210,7 +211,7 @@ scoped_ptr<base::DictionaryValue> PrefService::GetPreferenceValuesOmitDefaults()
continue;
out->Set(it.first, pref->GetValue()->CreateDeepCopy());
}
- return out.Pass();
+ return out;
}
scoped_ptr<base::DictionaryValue>
@@ -222,7 +223,7 @@ PrefService::GetPreferenceValuesWithoutPathExpansion() const {
DCHECK(value);
out->SetWithoutPathExpansion(it.first, value->CreateDeepCopy());
}
- return out.Pass();
+ return out;
}
const PrefService::Preference* PrefService::FindPreference(
@@ -402,11 +403,11 @@ void PrefService::SetFilePath(const std::string& path,
SetUserPrefValue(path, base::CreateFilePathValue(value));
}
-void PrefService::SetInt64(const std::string& path, int64 value) {
+void PrefService::SetInt64(const std::string& path, int64_t value) {
SetUserPrefValue(path, new base::StringValue(base::Int64ToString(value)));
}
-int64 PrefService::GetInt64(const std::string& path) const {
+int64_t PrefService::GetInt64(const std::string& path) const {
DCHECK(CalledOnValidThread());
const base::Value* value = GetPreferenceValue(path);
@@ -418,16 +419,16 @@ int64 PrefService::GetInt64(const std::string& path) const {
bool rv = value->GetAsString(&result);
DCHECK(rv);
- int64 val;
+ int64_t val;
base::StringToInt64(result, &val);
return val;
}
-void PrefService::SetUint64(const std::string& path, uint64 value) {
+void PrefService::SetUint64(const std::string& path, uint64_t value) {
SetUserPrefValue(path, new base::StringValue(base::Uint64ToString(value)));
}
-uint64 PrefService::GetUint64(const std::string& path) const {
+uint64_t PrefService::GetUint64(const std::string& path) const {
DCHECK(CalledOnValidThread());
const base::Value* value = GetPreferenceValue(path);
@@ -439,7 +440,7 @@ uint64 PrefService::GetUint64(const std::string& path) const {
bool rv = value->GetAsString(&result);
DCHECK(rv);
- uint64 val;
+ uint64_t val;
base::StringToUint64(result, &val);
return val;
}
@@ -499,7 +500,7 @@ void PrefService::SetUserPrefValue(const std::string& path,
return;
}
- user_pref_store_->SetValue(path, owned_value.Pass(), GetWriteFlags(pref));
+ user_pref_store_->SetValue(path, std::move(owned_value), GetWriteFlags(pref));
}
void PrefService::UpdateCommandLinePrefStore(PrefStore* command_line_store) {
diff --git a/chromium/base/prefs/pref_service.h b/chromium/base/prefs/pref_service.h
index 25c2f8bac14..bec7830f6d7 100644
--- a/chromium/base/prefs/pref_service.h
+++ b/chromium/base/prefs/pref_service.h
@@ -11,12 +11,15 @@
#ifndef BASE_PREFS_PREF_SERVICE_H_
#define BASE_PREFS_PREF_SERVICE_H_
+#include <stdint.h>
+
#include <set>
#include <string>
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/containers/hash_tables.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/observer_list.h"
@@ -130,7 +133,7 @@ class BASE_PREFS_EXPORT PrefService : public base::NonThreadSafe {
// Return the registration flags for this pref as a bitmask of
// PrefRegistry::PrefRegistrationFlags.
- uint32 registration_flags() const { return registration_flags_; }
+ uint32_t registration_flags() const { return registration_flags_; }
private:
friend class PrefService;
@@ -143,7 +146,7 @@ class BASE_PREFS_EXPORT PrefService : public base::NonThreadSafe {
const base::Value::Type type_;
- uint32 registration_flags_;
+ uint32_t registration_flags_;
// Reference to the PrefService in which this pref was created.
const PrefService* pref_service_;
@@ -220,12 +223,12 @@ class BASE_PREFS_EXPORT PrefService : public base::NonThreadSafe {
// 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 std::string& path, int64 value);
- int64 GetInt64(const std::string& path) const;
+ void SetInt64(const std::string& path, int64_t value);
+ int64_t GetInt64(const std::string& path) const;
// As above, but for unsigned values.
- void SetUint64(const std::string& path, uint64 value);
- uint64 GetUint64(const std::string& path) const;
+ void SetUint64(const std::string& path, uint64_t value);
+ uint64_t 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.
diff --git a/chromium/base/prefs/pref_service_factory.cc b/chromium/base/prefs/pref_service_factory.cc
index 8caf073e7bb..2380a86b5ac 100644
--- a/chromium/base/prefs/pref_service_factory.cc
+++ b/chromium/base/prefs/pref_service_factory.cc
@@ -59,7 +59,7 @@ scoped_ptr<PrefService> PrefServiceFactory::Create(
pref_registry,
read_error_callback_,
async_));
- return pref_service.Pass();
+ return pref_service;
}
} // namespace base
diff --git a/chromium/base/prefs/pref_service_factory.h b/chromium/base/prefs/pref_service_factory.h
index ca608c2237b..f84e0370c0f 100644
--- a/chromium/base/prefs/pref_service_factory.h
+++ b/chromium/base/prefs/pref_service_factory.h
@@ -5,8 +5,8 @@
#ifndef BASE_PREFS_PREF_SERVICE_FACTORY_H_
#define BASE_PREFS_PREF_SERVICE_FACTORY_H_
-#include "base/basictypes.h"
#include "base/callback.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/prefs/base_prefs_export.h"
#include "base/prefs/persistent_pref_store.h"
diff --git a/chromium/base/prefs/pref_service_unittest.cc b/chromium/base/prefs/pref_service_unittest.cc
index 2506b1d3f57..649c35fcf7f 100644
--- a/chromium/base/prefs/pref_service_unittest.cc
+++ b/chromium/base/prefs/pref_service_unittest.cc
@@ -2,8 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
+#include <stdint.h>
+
#include <string>
+#include "base/macros.h"
#include "base/prefs/json_pref_store.h"
#include "base/prefs/mock_pref_change_callback.h"
#include "base/prefs/pref_change_registrar.h"
@@ -234,29 +238,29 @@ class WriteFlagChecker : public TestingPrefStore {
public:
WriteFlagChecker() {}
- void ReportValueChanged(const std::string& key, uint32 flags) override {
+ void ReportValueChanged(const std::string& key, uint32_t flags) override {
SetLastWriteFlags(flags);
}
void SetValue(const std::string& key,
scoped_ptr<base::Value> value,
- uint32 flags) override {
+ uint32_t flags) override {
SetLastWriteFlags(flags);
}
void SetValueSilently(const std::string& key,
scoped_ptr<base::Value> value,
- uint32 flags) override {
+ uint32_t flags) override {
SetLastWriteFlags(flags);
}
- void RemoveValue(const std::string& key, uint32 flags) override {
+ void RemoveValue(const std::string& key, uint32_t flags) override {
SetLastWriteFlags(flags);
}
- uint32 GetLastFlagsAndClear() {
+ uint32_t GetLastFlagsAndClear() {
CHECK(last_write_flags_set_);
- uint32 result = last_write_flags_;
+ uint32_t result = last_write_flags_;
last_write_flags_set_ = false;
last_write_flags_ = WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS;
return result;
@@ -267,14 +271,14 @@ class WriteFlagChecker : public TestingPrefStore {
private:
~WriteFlagChecker() override {}
- void SetLastWriteFlags(uint32 flags) {
+ void SetLastWriteFlags(uint32_t 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;
+ uint32_t last_write_flags_ = WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS;
};
TEST(PrefServiceTest, WriteablePrefStoreFlags) {
@@ -286,14 +290,14 @@ TEST(PrefServiceTest, WriteablePrefStoreFlags) {
// The first 8 bits of write flags are reserved for subclasses. Create a
// custom flag in this range
- uint32 kCustomRegistrationFlag = 1 << 2;
+ uint32_t 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;
+ uint32_t registration_flags;
+ uint32_t write_flags;
};
const RegistrationToWriteFlags kRegistrationToWriteFlags[] = {
{"none",
diff --git a/chromium/base/prefs/pref_store.h b/chromium/base/prefs/pref_store.h
index b736ac3d799..f95c8c42cb5 100644
--- a/chromium/base/prefs/pref_store.h
+++ b/chromium/base/prefs/pref_store.h
@@ -7,7 +7,7 @@
#include <string>
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/prefs/base_prefs_export.h"
diff --git a/chromium/base/prefs/pref_value_map.cc b/chromium/base/prefs/pref_value_map.cc
index 93eadb72db4..2340e3c273d 100644
--- a/chromium/base/prefs/pref_value_map.cc
+++ b/chromium/base/prefs/pref_value_map.cc
@@ -5,6 +5,7 @@
#include "base/prefs/pref_value_map.h"
#include <map>
+#include <utility>
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
@@ -40,7 +41,7 @@ bool PrefValueMap::SetValue(const std::string& key,
if (old_value && value->Equals(old_value))
return false;
- prefs_.set(key, value.Pass());
+ prefs_.set(key, std::move(value));
return true;
}
diff --git a/chromium/base/prefs/pref_value_map.h b/chromium/base/prefs/pref_value_map.h
index 7d43f2b96ca..349fe685201 100644
--- a/chromium/base/prefs/pref_value_map.h
+++ b/chromium/base/prefs/pref_value_map.h
@@ -8,8 +8,8 @@
#include <string>
#include <vector>
-#include "base/basictypes.h"
#include "base/containers/scoped_ptr_hash_map.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/prefs/base_prefs_export.h"
diff --git a/chromium/base/prefs/pref_value_store.cc b/chromium/base/prefs/pref_value_store.cc
index 1a0ec08dccb..fe7cd67d08e 100644
--- a/chromium/base/prefs/pref_value_store.cc
+++ b/chromium/base/prefs/pref_value_store.cc
@@ -4,6 +4,8 @@
#include "base/prefs/pref_value_store.h"
+#include <stddef.h>
+
#include "base/logging.h"
#include "base/prefs/pref_notifier.h"
#include "base/prefs/pref_observer.h"
diff --git a/chromium/base/prefs/pref_value_store.h b/chromium/base/prefs/pref_value_store.h
index 5b832da5007..8ec8c593849 100644
--- a/chromium/base/prefs/pref_value_store.h
+++ b/chromium/base/prefs/pref_value_store.h
@@ -9,8 +9,8 @@
#include <string>
#include <vector>
-#include "base/basictypes.h"
#include "base/callback.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/prefs/base_prefs_export.h"
#include "base/prefs/pref_store.h"
diff --git a/chromium/base/prefs/scoped_user_pref_update.h b/chromium/base/prefs/scoped_user_pref_update.h
index f8bebfe435c..29ad8526cd3 100644
--- a/chromium/base/prefs/scoped_user_pref_update.h
+++ b/chromium/base/prefs/scoped_user_pref_update.h
@@ -10,7 +10,7 @@
#include <string>
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/prefs/base_prefs_export.h"
#include "base/prefs/pref_service.h"
#include "base/threading/non_thread_safe.h"
diff --git a/chromium/base/prefs/testing_pref_service.h b/chromium/base/prefs/testing_pref_service.h
index cbc978dd4ef..85a2879f8ac 100644
--- a/chromium/base/prefs/testing_pref_service.h
+++ b/chromium/base/prefs/testing_pref_service.h
@@ -5,6 +5,7 @@
#ifndef BASE_PREFS_TESTING_PREF_SERVICE_H_
#define BASE_PREFS_TESTING_PREF_SERVICE_H_
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/prefs/pref_registry.h"
diff --git a/chromium/base/prefs/testing_pref_store.cc b/chromium/base/prefs/testing_pref_store.cc
index 2322f4e4768..33e1dc22e55 100644
--- a/chromium/base/prefs/testing_pref_store.cc
+++ b/chromium/base/prefs/testing_pref_store.cc
@@ -4,6 +4,8 @@
#include "base/prefs/testing_pref_store.h"
+#include <utility>
+
#include "base/memory/scoped_ptr.h"
#include "base/values.h"
@@ -44,8 +46,8 @@ bool TestingPrefStore::IsInitializationComplete() const {
void TestingPrefStore::SetValue(const std::string& key,
scoped_ptr<base::Value> value,
- uint32 flags) {
- if (prefs_.SetValue(key, value.Pass())) {
+ uint32_t flags) {
+ if (prefs_.SetValue(key, std::move(value))) {
committed_ = false;
NotifyPrefValueChanged(key);
}
@@ -53,12 +55,12 @@ void TestingPrefStore::SetValue(const std::string& key,
void TestingPrefStore::SetValueSilently(const std::string& key,
scoped_ptr<base::Value> value,
- uint32 flags) {
- if (prefs_.SetValue(key, value.Pass()))
+ uint32_t flags) {
+ if (prefs_.SetValue(key, std::move(value)))
committed_ = false;
}
-void TestingPrefStore::RemoveValue(const std::string& key, uint32 flags) {
+void TestingPrefStore::RemoveValue(const std::string& key, uint32_t flags) {
if (prefs_.RemoveValue(key)) {
committed_ = false;
NotifyPrefValueChanged(key);
@@ -109,7 +111,7 @@ void TestingPrefStore::NotifyInitializationCompleted() {
}
void TestingPrefStore::ReportValueChanged(const std::string& key,
- uint32 flags) {
+ uint32_t flags) {
FOR_EACH_OBSERVER(Observer, observers_, OnPrefValueChanged(key));
}
diff --git a/chromium/base/prefs/testing_pref_store.h b/chromium/base/prefs/testing_pref_store.h
index 72e61b3030d..713e69a7d4e 100644
--- a/chromium/base/prefs/testing_pref_store.h
+++ b/chromium/base/prefs/testing_pref_store.h
@@ -5,10 +5,12 @@
#ifndef BASE_PREFS_TESTING_PREF_STORE_H_
#define BASE_PREFS_TESTING_PREF_STORE_H_
+#include <stdint.h>
+
#include <string>
-#include "base/basictypes.h"
#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "base/observer_list.h"
#include "base/prefs/persistent_pref_store.h"
#include "base/prefs/pref_value_map.h"
@@ -30,14 +32,14 @@ class TestingPrefStore : public PersistentPrefStore {
// PersistentPrefStore overrides:
bool GetMutableValue(const std::string& key, base::Value** result) override;
- void ReportValueChanged(const std::string& key, uint32 flags) override;
+ void ReportValueChanged(const std::string& key, uint32_t flags) override;
void SetValue(const std::string& key,
scoped_ptr<base::Value> value,
- uint32 flags) override;
+ uint32_t flags) override;
void SetValueSilently(const std::string& key,
scoped_ptr<base::Value> value,
- uint32 flags) override;
- void RemoveValue(const std::string& key, uint32 flags) override;
+ uint32_t flags) override;
+ void RemoveValue(const std::string& key, uint32_t 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 f22f93aed69..fdb087fc9ec 100644
--- a/chromium/base/prefs/value_map_pref_store.cc
+++ b/chromium/base/prefs/value_map_pref_store.cc
@@ -5,6 +5,7 @@
#include "base/prefs/value_map_pref_store.h"
#include <algorithm>
+#include <utility>
#include "base/stl_util.h"
#include "base/values.h"
@@ -30,12 +31,12 @@ bool ValueMapPrefStore::HasObservers() const {
void ValueMapPrefStore::SetValue(const std::string& key,
scoped_ptr<base::Value> value,
- uint32 flags) {
- if (prefs_.SetValue(key, value.Pass()))
+ uint32_t flags) {
+ if (prefs_.SetValue(key, std::move(value)))
FOR_EACH_OBSERVER(Observer, observers_, OnPrefValueChanged(key));
}
-void ValueMapPrefStore::RemoveValue(const std::string& key, uint32 flags) {
+void ValueMapPrefStore::RemoveValue(const std::string& key, uint32_t flags) {
if (prefs_.RemoveValue(key))
FOR_EACH_OBSERVER(Observer, observers_, OnPrefValueChanged(key));
}
@@ -46,14 +47,14 @@ bool ValueMapPrefStore::GetMutableValue(const std::string& key,
}
void ValueMapPrefStore::ReportValueChanged(const std::string& key,
- uint32 flags) {
+ uint32_t flags) {
FOR_EACH_OBSERVER(Observer, observers_, OnPrefValueChanged(key));
}
void ValueMapPrefStore::SetValueSilently(const std::string& key,
scoped_ptr<base::Value> value,
- uint32 flags) {
- prefs_.SetValue(key, value.Pass());
+ uint32_t flags) {
+ prefs_.SetValue(key, std::move(value));
}
ValueMapPrefStore::~ValueMapPrefStore() {}
diff --git a/chromium/base/prefs/value_map_pref_store.h b/chromium/base/prefs/value_map_pref_store.h
index badfef783e1..eac785d4e25 100644
--- a/chromium/base/prefs/value_map_pref_store.h
+++ b/chromium/base/prefs/value_map_pref_store.h
@@ -5,10 +5,12 @@
#ifndef BASE_PREFS_VALUE_MAP_PREF_STORE_H_
#define BASE_PREFS_VALUE_MAP_PREF_STORE_H_
+#include <stdint.h>
+
#include <map>
#include <string>
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/observer_list.h"
#include "base/prefs/base_prefs_export.h"
#include "base/prefs/pref_value_map.h"
@@ -30,13 +32,13 @@ class BASE_PREFS_EXPORT ValueMapPrefStore : public WriteablePrefStore {
// WriteablePrefStore overrides:
void SetValue(const std::string& key,
scoped_ptr<base::Value> value,
- uint32 flags) override;
- void RemoveValue(const std::string& key, uint32 flags) override;
+ uint32_t flags) override;
+ void RemoveValue(const std::string& key, uint32_t flags) override;
bool GetMutableValue(const std::string& key, base::Value** value) override;
- void ReportValueChanged(const std::string& key, uint32 flags) override;
+ void ReportValueChanged(const std::string& key, uint32_t flags) override;
void SetValueSilently(const std::string& key,
scoped_ptr<base::Value> value,
- uint32 flags) override;
+ uint32_t flags) override;
protected:
~ValueMapPrefStore() override;
diff --git a/chromium/base/prefs/writeable_pref_store.h b/chromium/base/prefs/writeable_pref_store.h
index cde3c84d0f1..f7da279ac02 100644
--- a/chromium/base/prefs/writeable_pref_store.h
+++ b/chromium/base/prefs/writeable_pref_store.h
@@ -5,9 +5,11 @@
#ifndef BASE_PREFS_WRITEABLE_PREF_STORE_H_
#define BASE_PREFS_WRITEABLE_PREF_STORE_H_
+#include <stdint.h>
+
#include <string>
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/prefs/pref_store.h"
@@ -20,7 +22,7 @@ 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 {
+ enum PrefWriteFlags : uint32_t {
// No flags are specified.
DEFAULT_PREF_WRITE_FLAGS = 0,
@@ -35,10 +37,10 @@ class BASE_PREFS_EXPORT WriteablePrefStore : public PrefStore {
// a bitmask of PrefWriteFlags.
virtual void SetValue(const std::string& key,
scoped_ptr<base::Value> value,
- uint32 flags) = 0;
+ uint32_t flags) = 0;
// Removes the value for |key|.
- virtual void RemoveValue(const std::string& key, uint32 flags) = 0;
+ virtual void RemoveValue(const std::string& key, uint32_t flags) = 0;
// Equivalent to PrefStore::GetValue but returns a mutable value.
virtual bool GetMutableValue(const std::string& key,
@@ -49,7 +51,7 @@ class BASE_PREFS_EXPORT WriteablePrefStore : public PrefStore {
// value. SetValue takes care of notifications itself. Note that
// ReportValueChanged will trigger notifications even if nothing has changed.
// |flags| is a bitmask of PrefWriteFlags.
- virtual void ReportValueChanged(const std::string& key, uint32 flags) = 0;
+ virtual void ReportValueChanged(const std::string& key, uint32_t flags) = 0;
// Same as SetValue, but doesn't generate notifications. This is used by
// PrefService::GetMutableUserPref() in order to put empty entries
@@ -58,7 +60,7 @@ class BASE_PREFS_EXPORT WriteablePrefStore : public PrefStore {
// of PrefWriteFlags.
virtual void SetValueSilently(const std::string& key,
scoped_ptr<base::Value> value,
- uint32 flags) = 0;
+ uint32_t flags) = 0;
protected:
~WriteablePrefStore() override {}
diff --git a/chromium/base/process/BUILD.gn b/chromium/base/process/BUILD.gn
deleted file mode 100644
index eabbde538f1..00000000000
--- a/chromium/base/process/BUILD.gn
+++ /dev/null
@@ -1,115 +0,0 @@
-# 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",
- "port_provider_mac.h",
- "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_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 || is_ios) {
- 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",
- ]
- }
-
- if (is_ios) {
- sources += [
- "memory_stubs.cc",
- "process_metrics.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 e6c2119c141..d286f4e7539 100644
--- a/chromium/base/process/internal_linux.cc
+++ b/chromium/base/process/internal_linux.cc
@@ -4,6 +4,7 @@
#include "base/process/internal_linux.h"
+#include <limits.h>
#include <unistd.h>
#include <map>
@@ -114,12 +115,12 @@ void ParseProcStat(const std::string& contents, ProcStatMap* output) {
}
}
-int64 GetProcStatsFieldAsInt64(const std::vector<std::string>& proc_stats,
- ProcStatsFields field_num) {
+int64_t GetProcStatsFieldAsInt64(const std::vector<std::string>& proc_stats,
+ ProcStatsFields field_num) {
DCHECK_GE(field_num, VM_PPID);
CHECK_LT(static_cast<size_t>(field_num), proc_stats.size());
- int64 value;
+ int64_t value;
return StringToInt64(proc_stats[field_num], &value) ? value : 0;
}
@@ -132,7 +133,7 @@ size_t GetProcStatsFieldAsSizeT(const std::vector<std::string>& proc_stats,
return StringToSizeT(proc_stats[field_num], &value) ? value : 0;
}
-int64 ReadProcStatsAndGetFieldAsInt64(pid_t pid, ProcStatsFields field_num) {
+int64_t ReadProcStatsAndGetFieldAsInt64(pid_t pid, ProcStatsFields field_num) {
std::string stats_data;
if (!ReadProcStats(pid, &stats_data))
return 0;
diff --git a/chromium/base/process/internal_linux.h b/chromium/base/process/internal_linux.h
index 1837f94ce52..ba793f7cc7c 100644
--- a/chromium/base/process/internal_linux.h
+++ b/chromium/base/process/internal_linux.h
@@ -8,6 +8,8 @@
#ifndef BASE_PROCESS_INTERNAL_LINUX_H_
#define BASE_PROCESS_INTERNAL_LINUX_H_
+#include <stddef.h>
+#include <stdint.h>
#include <unistd.h>
#include "base/files/file_path.h"
@@ -63,8 +65,8 @@ enum ProcStatsFields {
// Reads the |field_num|th field from |proc_stats|. Returns 0 on failure.
// This version does not handle the first 3 values, since the first value is
// simply |pid|, and the next two values are strings.
-int64 GetProcStatsFieldAsInt64(const std::vector<std::string>& proc_stats,
- ProcStatsFields field_num);
+int64_t GetProcStatsFieldAsInt64(const std::vector<std::string>& proc_stats,
+ ProcStatsFields field_num);
// Same as GetProcStatsFieldAsInt64(), but for size_t values.
size_t GetProcStatsFieldAsSizeT(const std::vector<std::string>& proc_stats,
@@ -72,7 +74,7 @@ size_t GetProcStatsFieldAsSizeT(const std::vector<std::string>& proc_stats,
// Convenience wrapper around GetProcStatsFieldAsInt64(), ParseProcStats() and
// ReadProcStats(). See GetProcStatsFieldAsInt64() for details.
-int64 ReadProcStatsAndGetFieldAsInt64(pid_t pid, ProcStatsFields field_num);
+int64_t ReadProcStatsAndGetFieldAsInt64(pid_t pid, ProcStatsFields field_num);
// Same as ReadProcStatsAndGetFieldAsInt64() but for size_t values.
size_t ReadProcStatsAndGetFieldAsSizeT(pid_t pid,
diff --git a/chromium/base/process/kill.h b/chromium/base/process/kill.h
index bb4103fb643..c664f33262f 100644
--- a/chromium/base/process/kill.h
+++ b/chromium/base/process/kill.h
@@ -12,6 +12,7 @@
#include "base/process/process.h"
#include "base/process/process_handle.h"
#include "base/time/time.h"
+#include "build/build_config.h"
namespace base {
diff --git a/chromium/base/process/kill_mac.cc b/chromium/base/process/kill_mac.cc
index a4e0a14cf8f..0110c908dc6 100644
--- a/chromium/base/process/kill_mac.cc
+++ b/chromium/base/process/kill_mac.cc
@@ -4,6 +4,7 @@
#include "base/process/kill.h"
+#include <errno.h>
#include <signal.h>
#include <sys/event.h>
#include <sys/types.h>
diff --git a/chromium/base/process/kill_posix.cc b/chromium/base/process/kill_posix.cc
index f0d2d442274..85470e05f97 100644
--- a/chromium/base/process/kill_posix.cc
+++ b/chromium/base/process/kill_posix.cc
@@ -4,6 +4,7 @@
#include "base/process/kill.h"
+#include <errno.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
@@ -12,10 +13,12 @@
#include "base/files/file_util.h"
#include "base/files/scoped_file.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/posix/eintr_wrapper.h"
#include "base/process/process_iterator.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/platform_thread.h"
+#include "build/build_config.h"
namespace base {
diff --git a/chromium/base/process/kill_win.cc b/chromium/base/process/kill_win.cc
index 7cbf9489051..a9c04fbce62 100644
--- a/chromium/base/process/kill_win.cc
+++ b/chromium/base/process/kill_win.cc
@@ -4,12 +4,14 @@
#include "base/process/kill.h"
-#include <io.h>
#include <windows.h>
+#include <io.h>
+#include <stdint.h>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "base/process/process_iterator.h"
#include "base/win/object_watcher.h"
@@ -156,9 +158,9 @@ bool WaitForProcessesToExit(const FilePath::StringType& executable_name,
NamedProcessIterator iter(executable_name, filter);
for (const ProcessEntry* entry = iter.NextProcessEntry(); entry;
entry = iter.NextProcessEntry()) {
- DWORD remaining_wait = static_cast<DWORD>(std::max(
- static_cast<int64>(0),
- wait.InMilliseconds() - (GetTickCount() - start_time)));
+ DWORD remaining_wait = static_cast<DWORD>(
+ std::max(static_cast<int64_t>(0),
+ wait.InMilliseconds() - (GetTickCount() - start_time)));
HANDLE process = OpenProcess(SYNCHRONIZE,
FALSE,
entry->th32ProcessID);
diff --git a/chromium/base/process/launch.cc b/chromium/base/process/launch.cc
index c179b2f5f37..f09317dc73d 100644
--- a/chromium/base/process/launch.cc
+++ b/chromium/base/process/launch.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "base/process/launch.h"
+#include "build/build_config.h"
namespace base {
diff --git a/chromium/base/process/launch.h b/chromium/base/process/launch.h
index 42b8a7670d9..9a76e2048ee 100644
--- a/chromium/base/process/launch.h
+++ b/chromium/base/process/launch.h
@@ -7,16 +7,19 @@
#ifndef BASE_PROCESS_LAUNCH_H_
#define BASE_PROCESS_LAUNCH_H_
+#include <stddef.h>
+
#include <string>
#include <utility>
#include <vector>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/environment.h"
+#include "base/macros.h"
#include "base/process/process.h"
#include "base/process/process_handle.h"
#include "base/strings/string_piece.h"
+#include "build/build_config.h"
#if defined(OS_POSIX)
#include "base/posix/file_descriptor_shuffle.h"
diff --git a/chromium/base/process/launch_posix.cc b/chromium/base/process/launch_posix.cc
index f076733d783..4bd3da312a6 100644
--- a/chromium/base/process/launch_posix.cc
+++ b/chromium/base/process/launch_posix.cc
@@ -10,6 +10,8 @@
#include <sched.h>
#include <setjmp.h>
#include <signal.h>
+#include <stddef.h>
+#include <stdint.h>
#include <stdlib.h>
#include <sys/resource.h>
#include <sys/syscall.h>
diff --git a/chromium/base/process/launch_win.cc b/chromium/base/process/launch_win.cc
index 54b06675100..1ffb9799554 100644
--- a/chromium/base/process/launch_win.cc
+++ b/chromium/base/process/launch_win.cc
@@ -272,8 +272,10 @@ Process LaunchProcess(const string16& cmdline,
// If this code is run under a debugger, the launched process is
// automatically associated with a job object created by the debugger.
- // The CREATE_BREAKAWAY_FROM_JOB flag is used to prevent this.
- flags |= CREATE_BREAKAWAY_FROM_JOB;
+ // The CREATE_BREAKAWAY_FROM_JOB flag is used to prevent this on Windows
+ // releases that do not support nested jobs.
+ if (win::GetVersion() < win::VERSION_WIN8)
+ flags |= CREATE_BREAKAWAY_FROM_JOB;
}
if (options.force_breakaway_from_job_)
@@ -300,7 +302,7 @@ Process LaunchProcess(const string16& cmdline,
DestroyEnvironmentBlock(enviroment_block);
if (!launched) {
DPLOG(ERROR) << "Command line:" << std::endl << UTF16ToUTF8(cmdline)
- << std::endl;;
+ << std::endl;
return Process();
}
} else {
@@ -309,7 +311,7 @@ Process LaunchProcess(const string16& cmdline,
inherit_handles, flags, NULL, NULL,
startup_info, &temp_process_info)) {
DPLOG(ERROR) << "Command line:" << std::endl << UTF16ToUTF8(cmdline)
- << std::endl;;
+ << std::endl;
return Process();
}
}
diff --git a/chromium/base/process/memory.cc b/chromium/base/process/memory.cc
index 133a72a0f75..75d45303eba 100644
--- a/chromium/base/process/memory.cc
+++ b/chromium/base/process/memory.cc
@@ -5,6 +5,7 @@
#include "base/debug/alias.h"
#include "base/logging.h"
#include "base/process/memory.h"
+#include "build/build_config.h"
namespace base {
diff --git a/chromium/base/process/memory.h b/chromium/base/process/memory.h
index da27151d1b1..f7fc569abaf 100644
--- a/chromium/base/process/memory.h
+++ b/chromium/base/process/memory.h
@@ -5,8 +5,9 @@
#ifndef BASE_PROCESS_MEMORY_H_
#define BASE_PROCESS_MEMORY_H_
+#include <stddef.h>
+
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/process/process_handle.h"
#include "build/build_config.h"
diff --git a/chromium/base/process/memory_linux.cc b/chromium/base/process/memory_linux.cc
index 6dbe8b7b394..6cdc2ca40cd 100644
--- a/chromium/base/process/memory_linux.cc
+++ b/chromium/base/process/memory_linux.cc
@@ -4,6 +4,8 @@
#include "base/process/memory.h"
+#include <stddef.h>
+
#include <new>
#include "base/files/file_path.h"
@@ -11,6 +13,7 @@
#include "base/logging.h"
#include "base/process/internal_linux.h"
#include "base/strings/string_number_conversions.h"
+#include "build/build_config.h"
#if defined(USE_TCMALLOC)
// Used by UncheckedMalloc. If tcmalloc is linked to the executable
diff --git a/chromium/base/process/memory_mac.mm b/chromium/base/process/memory_mac.mm
index 17249a239b9..1e1a1ba536f 100644
--- a/chromium/base/process/memory_mac.mm
+++ b/chromium/base/process/memory_mac.mm
@@ -10,6 +10,7 @@
#include <mach/mach_vm.h>
#include <malloc/malloc.h>
#import <objc/runtime.h>
+#include <stddef.h>
#include <new>
@@ -18,6 +19,7 @@
#include "base/mac/mac_util.h"
#include "base/mac/mach_logging.h"
#include "base/scoped_clear_errno.h"
+#include "build/build_config.h"
#include "third_party/apple_apsl/CFBase.h"
#include "third_party/apple_apsl/malloc.h"
diff --git a/chromium/base/process/memory_stubs.cc b/chromium/base/process/memory_stubs.cc
index b06c7d5f2b5..7ed012d8803 100644
--- a/chromium/base/process/memory_stubs.cc
+++ b/chromium/base/process/memory_stubs.cc
@@ -4,6 +4,9 @@
#include "base/process/memory.h"
+#include <stddef.h>
+#include <stdlib.h>
+
namespace base {
void EnableTerminationOnOutOfMemory() {
@@ -16,4 +19,22 @@ bool AdjustOOMScore(ProcessId process, int score) {
return false;
}
+// UncheckedMalloc and Calloc exist so that platforms making use of
+// EnableTerminationOnOutOfMemory have a way to allocate memory without
+// crashing. This _stubs.cc file is for platforms that do not support
+// EnableTerminationOnOutOfMemory (note the empty implementation above). As
+// such, these two Unchecked.alloc functions need only trivially pass-through to
+// their respective stdlib function since those functions will return null on a
+// failure to allocate.
+
+bool UncheckedMalloc(size_t size, void** result) {
+ *result = malloc(size);
+ return *result != nullptr;
+}
+
+bool UncheckedCalloc(size_t num_items, size_t size, void** result) {
+ *result = calloc(num_items, size);
+ return *result != nullptr;
+}
+
} // namespace base
diff --git a/chromium/base/process/memory_unittest.cc b/chromium/base/process/memory_unittest.cc
index 98f049a3bf9..6137c1c932d 100644
--- a/chromium/base/process/memory_unittest.cc
+++ b/chromium/base/process/memory_unittest.cc
@@ -6,11 +6,14 @@
#include "base/process/memory.h"
+#include <stddef.h>
+
#include <limits>
#include "base/compiler_specific.h"
#include "base/debug/alias.h"
#include "base/strings/stringprintf.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#if defined(OS_WIN)
diff --git a/chromium/base/process/memory_unittest_mac.h b/chromium/base/process/memory_unittest_mac.h
index 472d2c59627..713589bd2ed 100644
--- a/chromium/base/process/memory_unittest_mac.h
+++ b/chromium/base/process/memory_unittest_mac.h
@@ -8,7 +8,10 @@
#ifndef BASE_PROCESS_MEMORY_UNITTEST_MAC_H_
#define BASE_PROCESS_MEMORY_UNITTEST_MAC_H_
-#include "base/basictypes.h"
+#include <stddef.h>
+#include <sys/types.h>
+
+#include "build/build_config.h"
namespace base {
diff --git a/chromium/base/process/memory_unittest_mac.mm b/chromium/base/process/memory_unittest_mac.mm
index bc4bf65347d..26fe1af4dd5 100644
--- a/chromium/base/process/memory_unittest_mac.mm
+++ b/chromium/base/process/memory_unittest_mac.mm
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "base/process/memory_unittest_mac.h"
+#include "build/build_config.h"
#import <Foundation/Foundation.h>
#include <CoreFoundation/CoreFoundation.h>
diff --git a/chromium/base/process/memory_win.cc b/chromium/base/process/memory_win.cc
index b949b5d8854..42f707d9ac0 100644
--- a/chromium/base/process/memory_win.cc
+++ b/chromium/base/process/memory_win.cc
@@ -6,6 +6,7 @@
#include <new.h>
#include <psapi.h>
+#include <stddef.h>
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
diff --git a/chromium/base/process/port_provider_mac.cc b/chromium/base/process/port_provider_mac.cc
new file mode 100644
index 00000000000..ac13949ac83
--- /dev/null
+++ b/chromium/base/process/port_provider_mac.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/process/port_provider_mac.h"
+
+namespace base {
+
+PortProvider::PortProvider() : lock_(), observer_list_() {}
+PortProvider::~PortProvider() {}
+
+void PortProvider::AddObserver(Observer* observer) {
+ base::AutoLock l(lock_);
+ observer_list_.AddObserver(observer);
+}
+
+void PortProvider::RemoveObserver(Observer* observer) {
+ base::AutoLock l(lock_);
+ observer_list_.RemoveObserver(observer);
+}
+
+void PortProvider::NotifyObservers(ProcessHandle process) {
+ base::AutoLock l(lock_);
+ FOR_EACH_OBSERVER(Observer, observer_list_, OnReceivedTaskPort(process));
+}
+
+} // namespace base
diff --git a/chromium/base/process/port_provider_mac.h b/chromium/base/process/port_provider_mac.h
index bdee4a8a293..2f40297f286 100644
--- a/chromium/base/process/port_provider_mac.h
+++ b/chromium/base/process/port_provider_mac.h
@@ -8,7 +8,10 @@
#include <mach/mach.h>
#include "base/base_export.h"
+#include "base/macros.h"
+#include "base/observer_list.h"
#include "base/process/process_handle.h"
+#include "base/synchronization/lock.h"
namespace base {
@@ -17,11 +20,40 @@ namespace base {
// privileges.
class BASE_EXPORT PortProvider {
public:
- virtual ~PortProvider() {}
+ PortProvider();
+ virtual ~PortProvider();
+
+ class Observer {
+ public:
+ virtual ~Observer() {};
+ // Called by the PortProvider to notify observers that the task port was
+ // received for a given process.
+ // No guarantees are made about the thread on which this notification will
+ // be sent.
+ // Observers must not call AddObserver() or RemoveObserver() in this
+ // callback, as doing so will deadlock.
+ virtual void OnReceivedTaskPort(ProcessHandle process) = 0;
+ };
// Returns the mach task port for |process| if possible, or else
// |MACH_PORT_NULL|.
virtual mach_port_t TaskForPid(ProcessHandle process) const = 0;
+
+ // Observer interface.
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
+
+ protected:
+ // Called by subclasses to send a notification to observers.
+ void NotifyObservers(ProcessHandle process);
+
+ private:
+ // ObserverList is not thread-safe, so |lock_| ensures consistency of
+ // |observer_list_|.
+ base::Lock lock_;
+ base::ObserverList<Observer> observer_list_;
+
+ DISALLOW_COPY_AND_ASSIGN(PortProvider);
};
} // namespace base
diff --git a/chromium/base/process/process.h b/chromium/base/process/process.h
index 2a83cb088ac..75f6a009df1 100644
--- a/chromium/base/process/process.h
+++ b/chromium/base/process/process.h
@@ -6,7 +6,6 @@
#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"
@@ -32,19 +31,17 @@ namespace base {
// the process dies, and it may be reused by the system, which means that it may
// end up pointing to the wrong process.
class BASE_EXPORT Process {
- MOVE_ONLY_TYPE_FOR_CPP_03(Process, RValue)
+ MOVE_ONLY_TYPE_FOR_CPP_03(Process)
public:
explicit Process(ProcessHandle handle = kNullProcessHandle);
- // Move constructor for C++03 move emulation of this type.
- Process(RValue other);
+ Process(Process&& other);
// The destructor does not terminate the process.
~Process();
- // Move operator= for C++03 move emulation of this type.
- Process& operator=(RValue other);
+ Process& operator=(Process&& other);
// Returns an object for the current process.
static Process Current();
@@ -125,6 +122,13 @@ class BASE_EXPORT Process {
// of this value is OS dependent.
int GetPriority() const;
+#if defined(OS_CHROMEOS)
+ // Get the PID in its PID namespace.
+ // If the process is not in a PID namespace or /proc/<pid>/status does not
+ // report NSpid, kNullProcessId is returned.
+ ProcessId GetPidInNamespace() const;
+#endif
+
private:
#if defined(OS_WIN)
bool is_current_process_;
@@ -134,6 +138,14 @@ class BASE_EXPORT Process {
#endif
};
+#if defined(OS_CHROMEOS)
+// Exposed for testing.
+// Given the contents of the /proc/<pid>/cgroup file, determine whether the
+// process is backgrounded or not.
+BASE_EXPORT bool IsProcessBackgroundedCGroup(
+ const StringPiece& cgroup_contents);
+#endif // defined(OS_CHROMEOS)
+
} // namespace base
#endif // BASE_PROCESS_PROCESS_H_
diff --git a/chromium/base/process/process_handle.cc b/chromium/base/process/process_handle.cc
new file mode 100644
index 00000000000..1f22b93d319
--- /dev/null
+++ b/chromium/base/process/process_handle.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 <stdint.h>
+
+#include "base/logging.h"
+#include "base/process/process_handle.h"
+#include "build/build_config.h"
+
+namespace base {
+
+namespace {
+bool g_have_unique_id = false;
+uint32_t g_unique_id;
+
+// The process which set |g_unique_id|.
+ProcessId g_procid;
+
+// Mangle IDs so that they are not accidentally used as PIDs, e.g. as an
+// argument to kill or waitpid.
+uint32_t MangleProcessId(ProcessId process_id) {
+ // Add a large power of 10 so that the pid is still the pid is still readable
+ // inside the mangled id.
+ return static_cast<uint32_t>(process_id) + 1000000000U;
+}
+
+} // namespace
+
+uint32_t GetUniqueIdForProcess() {
+ if (!g_have_unique_id) {
+ return MangleProcessId(GetCurrentProcId());
+ }
+
+ // Make sure we are the same process that set |g_procid|. This check may have
+ // false negatives (if a process ID was reused) but should have no false
+ // positives.
+ DCHECK_EQ(GetCurrentProcId(), g_procid);
+ return g_unique_id;
+}
+
+#if defined(OS_LINUX)
+
+void InitUniqueIdForProcessInPidNamespace(ProcessId pid_outside_of_namespace) {
+ g_unique_id = MangleProcessId(pid_outside_of_namespace);
+ g_procid = GetCurrentProcId();
+ g_have_unique_id = true;
+}
+
+#endif
+
+} // namespace base
diff --git a/chromium/base/process/process_handle.h b/chromium/base/process/process_handle.h
index 77f2c585cfc..ef7a6025525 100644
--- a/chromium/base/process/process_handle.h
+++ b/chromium/base/process/process_handle.h
@@ -5,12 +5,13 @@
#ifndef BASE_PROCESS_PROCESS_HANDLE_H_
#define BASE_PROCESS_PROCESS_HANDLE_H_
+#include <stdint.h>
+#include <sys/types.h>
+
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/files/file_path.h"
#include "build/build_config.h"
-#include <sys/types.h>
#if defined(OS_WIN)
#include <windows.h>
#endif
@@ -35,23 +36,44 @@ const ProcessId kNullProcessId = 0;
#endif // defined(OS_WIN)
// Returns the id of the current process.
+// Note that on some platforms, this is not guaranteed to be unique across
+// processes (use GetUniqueIdForProcess if uniqueness is required).
BASE_EXPORT ProcessId GetCurrentProcId();
+// Returns a unique ID for the current process. The ID will be unique across all
+// currently running processes within the chrome session, but IDs of terminated
+// processes may be reused. This returns an opaque value that is different from
+// a process's PID.
+BASE_EXPORT uint32_t GetUniqueIdForProcess();
+
+#if defined(OS_LINUX)
+// When a process is started in a different PID namespace from the browser
+// process, this function must be called with the process's PID in the browser's
+// PID namespace in order to initialize its unique ID. Not thread safe.
+// WARNING: To avoid inconsistent results from GetUniqueIdForProcess, this
+// should only be called very early after process startup - ideally as soon
+// after process creation as possible.
+BASE_EXPORT void InitUniqueIdForProcessInPidNamespace(
+ ProcessId pid_outside_of_namespace);
+#endif
+
// Returns the ProcessHandle of the current process.
BASE_EXPORT ProcessHandle GetCurrentProcessHandle();
-// 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.
+// Returns the process 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.
+// Note that on some platforms, this is not guaranteed to be unique across
+// processes.
BASE_EXPORT ProcessId GetProcId(ProcessHandle process);
+// Returns the ID for the parent of the given process.
+BASE_EXPORT ProcessId GetParentProcessId(ProcessHandle process);
+
#if defined(OS_POSIX)
// Returns the path to the executable of the given process.
BASE_EXPORT FilePath GetProcessExecutablePath(ProcessHandle process);
-
-// Returns the ID for the parent of the given process.
-BASE_EXPORT ProcessId GetParentProcessId(ProcessHandle process);
#endif
} // namespace base
diff --git a/chromium/base/process/process_handle_freebsd.cc b/chromium/base/process/process_handle_freebsd.cc
index e465a85b7e0..192d72bcc56 100644
--- a/chromium/base/process/process_handle_freebsd.cc
+++ b/chromium/base/process/process_handle_freebsd.cc
@@ -2,8 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/macros.h"
#include "base/process/process_handle.h"
+#include <limits.h>
+#include <stddef.h>
#include <sys/sysctl.h>
#include <sys/types.h>
#include <sys/user.h>
diff --git a/chromium/base/process/process_handle_mac.cc b/chromium/base/process/process_handle_mac.cc
index cbf0bc5c439..d9d22f78313 100644
--- a/chromium/base/process/process_handle_mac.cc
+++ b/chromium/base/process/process_handle_mac.cc
@@ -5,6 +5,7 @@
#include "base/process/process_handle.h"
#include <libproc.h>
+#include <stddef.h>
#include <sys/sysctl.h>
#include <sys/types.h>
diff --git a/chromium/base/process/process_handle_openbsd.cc b/chromium/base/process/process_handle_openbsd.cc
index 3508ccb04cb..045e7205dc6 100644
--- a/chromium/base/process/process_handle_openbsd.cc
+++ b/chromium/base/process/process_handle_openbsd.cc
@@ -2,8 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/macros.h"
#include "base/process/process_handle.h"
+#include <stddef.h>
#include <sys/sysctl.h>
#include <sys/types.h>
#include <unistd.h>
diff --git a/chromium/base/process/process_handle_win.cc b/chromium/base/process/process_handle_win.cc
index f2ffff8e882..7763f581645 100644
--- a/chromium/base/process/process_handle_win.cc
+++ b/chromium/base/process/process_handle_win.cc
@@ -5,6 +5,7 @@
#include "base/process/process_handle.h"
#include <windows.h>
+#include <tlhelp32.h>
#include "base/memory/scoped_ptr.h"
#include "base/win/scoped_handle.h"
@@ -25,4 +26,20 @@ ProcessId GetProcId(ProcessHandle process) {
return GetProcessId(process);
}
+ProcessId GetParentProcessId(ProcessHandle process) {
+ ProcessId child_pid = GetProcId(process);
+ PROCESSENTRY32 process_entry;
+ process_entry.dwSize = sizeof(PROCESSENTRY32);
+
+ win::ScopedHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
+ if (snapshot.IsValid() && Process32First(snapshot.Get(), &process_entry)) {
+ do {
+ if (process_entry.th32ProcessID == child_pid)
+ return process_entry.th32ParentProcessID;
+ } while (Process32Next(snapshot.Get(), &process_entry));
+ }
+
+ return 0u;
+}
+
} // namespace base
diff --git a/chromium/base/process/process_info.h b/chromium/base/process/process_info.h
index 85f204d04cf..1d76f42eb25 100644
--- a/chromium/base/process/process_info.h
+++ b/chromium/base/process/process_info.h
@@ -6,7 +6,6 @@
#define BASE_PROCESS_PROCESS_INFO_H_
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "build/build_config.h"
namespace base {
diff --git a/chromium/base/process/process_info_linux.cc b/chromium/base/process/process_info_linux.cc
index 88ae5a137d6..33c1dc1a5a8 100644
--- a/chromium/base/process/process_info_linux.cc
+++ b/chromium/base/process/process_info_linux.cc
@@ -4,7 +4,8 @@
#include "base/process/process_info.h"
-#include "base/basictypes.h"
+#include <stdint.h>
+
#include "base/logging.h"
#include "base/process/internal_linux.h"
#include "base/process/process_handle.h"
@@ -15,7 +16,7 @@ namespace base {
// static
const Time CurrentProcessInfo::CreationTime() {
ProcessHandle pid = GetCurrentProcessHandle();
- int64 start_ticks =
+ int64_t start_ticks =
internal::ReadProcStatsAndGetFieldAsInt64(pid, internal::VM_STARTTIME);
DCHECK(start_ticks);
TimeDelta start_offset = internal::ClockTicksToTimeDelta(start_ticks);
diff --git a/chromium/base/process/process_info_mac.cc b/chromium/base/process/process_info_mac.cc
index 7680d373df3..22c61a8576a 100644
--- a/chromium/base/process/process_info_mac.cc
+++ b/chromium/base/process/process_info_mac.cc
@@ -4,11 +4,12 @@
#include "base/process/process_info.h"
+#include <stddef.h>
#include <sys/sysctl.h>
#include <sys/time.h>
#include <unistd.h>
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/time/time.h"
diff --git a/chromium/base/process/process_info_win.cc b/chromium/base/process/process_info_win.cc
index 2b9c40653fd..bd9e0702c3d 100644
--- a/chromium/base/process/process_info_win.cc
+++ b/chromium/base/process/process_info_win.cc
@@ -6,7 +6,6 @@
#include <windows.h>
-#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "base/time/time.h"
#include "base/win/scoped_handle.h"
@@ -17,11 +16,13 @@ namespace base {
// static
const Time CurrentProcessInfo::CreationTime() {
FILETIME creation_time = {};
- FILETIME ignore = {};
- if (::GetProcessTimes(::GetCurrentProcess(), &creation_time, &ignore,
- &ignore, &ignore) == false)
+ FILETIME ignore1 = {};
+ FILETIME ignore2 = {};
+ FILETIME ignore3 = {};
+ if (!::GetProcessTimes(::GetCurrentProcess(), &creation_time, &ignore1,
+ &ignore2, &ignore3)) {
return Time();
-
+ }
return Time::FromFileTime(creation_time);
}
@@ -37,7 +38,7 @@ IntegrityLevel GetCurrentProcessIntegrityLevel() {
win::ScopedHandle scoped_process_token(process_token);
DWORD token_info_length = 0;
- if (::GetTokenInformation(process_token, TokenIntegrityLevel, NULL, 0,
+ if (::GetTokenInformation(process_token, TokenIntegrityLevel, nullptr, 0,
&token_info_length) ||
::GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
return INTEGRITY_UNKNOWN;
@@ -59,7 +60,8 @@ IntegrityLevel GetCurrentProcessIntegrityLevel() {
DWORD integrity_level = *::GetSidSubAuthority(
token_label->Label.Sid,
- static_cast<DWORD>(*::GetSidSubAuthorityCount(token_label->Label.Sid)-1));
+ static_cast<DWORD>(*::GetSidSubAuthorityCount(token_label->Label.Sid) -
+ 1));
if (integrity_level < SECURITY_MANDATORY_MEDIUM_RID)
return LOW_INTEGRITY;
diff --git a/chromium/base/process/process_iterator.cc b/chromium/base/process/process_iterator.cc
index b9ef047732f..94f53b60cb7 100644
--- a/chromium/base/process/process_iterator.cc
+++ b/chromium/base/process/process_iterator.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "base/process/process_iterator.h"
+#include "build/build_config.h"
namespace base {
diff --git a/chromium/base/process/process_iterator.h b/chromium/base/process/process_iterator.h
index ec6500e653c..26fe6903ce0 100644
--- a/chromium/base/process/process_iterator.h
+++ b/chromium/base/process/process_iterator.h
@@ -7,13 +7,15 @@
#ifndef BASE_PROCESS_PROCESS_ITERATOR_H_
#define BASE_PROCESS_PROCESS_ITERATOR_H_
+#include <stddef.h>
+
#include <list>
#include <string>
#include <vector>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/files/file_path.h"
+#include "base/macros.h"
#include "base/process/process.h"
#include "build/build_config.h"
diff --git a/chromium/base/process/process_iterator_freebsd.cc b/chromium/base/process/process_iterator_freebsd.cc
index 22087fdd309..4df0d90edec 100644
--- a/chromium/base/process/process_iterator_freebsd.cc
+++ b/chromium/base/process/process_iterator_freebsd.cc
@@ -4,11 +4,14 @@
#include "base/process/process_iterator.h"
+#include <errno.h>
#include <sys/types.h>
+#include <stddef.h>
#include <sys/sysctl.h>
#include <unistd.h>
#include "base/logging.h"
+#include "base/macros.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
diff --git a/chromium/base/process/process_iterator_linux.cc b/chromium/base/process/process_iterator_linux.cc
index a9d044c5382..94a35766e96 100644
--- a/chromium/base/process/process_iterator_linux.cc
+++ b/chromium/base/process/process_iterator_linux.cc
@@ -4,6 +4,8 @@
#include "base/process/process_iterator.h"
+#include <stddef.h>
+
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/process/internal_linux.h"
diff --git a/chromium/base/process/process_iterator_mac.cc b/chromium/base/process/process_iterator_mac.cc
index d9136f48b03..3d616980abd 100644
--- a/chromium/base/process/process_iterator_mac.cc
+++ b/chromium/base/process/process_iterator_mac.cc
@@ -5,11 +5,13 @@
#include "base/process/process_iterator.h"
#include <errno.h>
+#include <stddef.h>
#include <sys/sysctl.h>
#include <sys/types.h>
#include <unistd.h>
#include "base/logging.h"
+#include "base/macros.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
diff --git a/chromium/base/process/process_iterator_openbsd.cc b/chromium/base/process/process_iterator_openbsd.cc
index f864f58da4f..74306c09a00 100644
--- a/chromium/base/process/process_iterator_openbsd.cc
+++ b/chromium/base/process/process_iterator_openbsd.cc
@@ -5,9 +5,11 @@
#include "base/process/process_iterator.h"
#include <errno.h>
+#include <stddef.h>
#include <sys/sysctl.h>
#include "base/logging.h"
+#include "base/macros.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
diff --git a/chromium/base/process/process_linux.cc b/chromium/base/process/process_linux.cc
index 958ffd6dafb..2973ef3cbcc 100644
--- a/chromium/base/process/process_linux.cc
+++ b/chromium/base/process/process_linux.cc
@@ -14,6 +14,8 @@
#include "base/strings/string_split.h"
#include "base/strings/stringprintf.h"
#include "base/synchronization/lock.h"
+#include "base/threading/thread_restrictions.h"
+#include "build/build_config.h"
namespace base {
@@ -60,10 +62,10 @@ struct CGroups {
}
};
-base::LazyInstance<CGroups> cgroups = LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<CGroups> g_cgroups = LAZY_INSTANCE_INITIALIZER;
#else
const int kBackgroundPriority = 5;
-#endif
+#endif // defined(OS_CHROMEOS)
struct CheckForNicePermission {
CheckForNicePermission() : can_reraise_priority(false) {
@@ -84,9 +86,9 @@ struct CheckForNicePermission {
// static
bool Process::CanBackgroundProcesses() {
#if defined(OS_CHROMEOS)
- if (cgroups.Get().enabled)
+ if (g_cgroups.Get().enabled)
return true;
-#endif
+#endif // defined(OS_CHROMEOS)
static LazyInstance<CheckForNicePermission> check_for_nice_permission =
LAZY_INSTANCE_INITIALIZER;
@@ -97,21 +99,18 @@ bool Process::IsProcessBackgrounded() const {
DCHECK(IsValid());
#if defined(OS_CHROMEOS)
- if (cgroups.Get().enabled) {
+ if (g_cgroups.Get().enabled) {
+ // Used to allow reading the process priority from proc on thread launch.
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
std::string proc;
if (base::ReadFileToString(
- base::FilePath(StringPrintf(kProcPath, process_)),
- &proc)) {
- std::vector<std::string> proc_parts = base::SplitString(
- proc, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
- DCHECK_EQ(proc_parts.size(), 3u);
- bool ret = proc_parts[2] == std::string(kBackground);
- return ret;
- } else {
- return false;
+ base::FilePath(StringPrintf(kProcPath, process_)), &proc)) {
+ return IsProcessBackgroundedCGroup(proc);
}
+ return false;
}
-#endif
+#endif // defined(OS_CHROMEOS)
+
return GetPriority() == kBackgroundPriority;
}
@@ -119,14 +118,14 @@ bool Process::SetProcessBackgrounded(bool background) {
DCHECK(IsValid());
#if defined(OS_CHROMEOS)
- if (cgroups.Get().enabled) {
+ if (g_cgroups.Get().enabled) {
std::string pid = IntToString(process_);
const base::FilePath file =
background ?
- cgroups.Get().background_file : cgroups.Get().foreground_file;
+ g_cgroups.Get().background_file : g_cgroups.Get().foreground_file;
return base::WriteFile(file, pid.c_str(), pid.size()) > 0;
}
-#endif // OS_CHROMEOS
+#endif // defined(OS_CHROMEOS)
if (!CanBackgroundProcesses())
return false;
@@ -137,4 +136,67 @@ bool Process::SetProcessBackgrounded(bool background) {
return result == 0;
}
+#if defined(OS_CHROMEOS)
+bool IsProcessBackgroundedCGroup(const StringPiece& cgroup_contents) {
+ // The process can be part of multiple control groups, and for each cgroup
+ // hierarchy there's an entry in the file. We look for a control group
+ // named "/chrome_renderers/background" to determine if the process is
+ // backgrounded. crbug.com/548818.
+ std::vector<StringPiece> lines = SplitStringPiece(
+ cgroup_contents, "\n", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
+ for (const auto& line : lines) {
+ std::vector<StringPiece> fields =
+ SplitStringPiece(line, ":", TRIM_WHITESPACE, SPLIT_WANT_ALL);
+ if (fields.size() != 3U) {
+ NOTREACHED();
+ continue;
+ }
+ if (fields[2] == kBackground)
+ return true;
+ }
+
+ return false;
+}
+#endif // defined(OS_CHROMEOS)
+
+#if defined(OS_CHROMEOS)
+// Reads /proc/<pid>/status and returns the PID in its PID namespace.
+// If the process is not in a PID namespace or /proc/<pid>/status does not
+// report NSpid, kNullProcessId is returned.
+ProcessId Process::GetPidInNamespace() const {
+ std::string status;
+ {
+ // Synchronously reading files in /proc does not hit the disk.
+ ThreadRestrictions::ScopedAllowIO allow_io;
+ FilePath status_file =
+ FilePath("/proc").Append(IntToString(process_)).Append("status");
+ if (!ReadFileToString(status_file, &status)) {
+ return kNullProcessId;
+ }
+ }
+
+ StringPairs pairs;
+ SplitStringIntoKeyValuePairs(status, ':', '\n', &pairs);
+ for (const auto& pair : pairs) {
+ const std::string& key = pair.first;
+ const std::string& value_str = pair.second;
+ if (key == "NSpid") {
+ std::vector<StringPiece> split_value_str = SplitStringPiece(
+ value_str, "\t", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY);
+ if (split_value_str.size() <= 1) {
+ return kNullProcessId;
+ }
+ int value;
+ // The last value in the list is the PID in the namespace.
+ if (!StringToInt(split_value_str.back(), &value)) {
+ NOTREACHED();
+ return kNullProcessId;
+ }
+ return value;
+ }
+ }
+ return kNullProcessId;
+}
+#endif // defined(OS_CHROMEOS)
+
} // namespace base
diff --git a/chromium/base/process/process_metrics.cc b/chromium/base/process/process_metrics.cc
index e4863391076..a21891d9121 100644
--- a/chromium/base/process/process_metrics.cc
+++ b/chromium/base/process/process_metrics.cc
@@ -4,8 +4,11 @@
#include "base/process/process_metrics.h"
+#include <utility>
+
#include "base/logging.h"
#include "base/values.h"
+#include "build/build_config.h"
namespace base {
@@ -40,7 +43,15 @@ scoped_ptr<Value> SystemMetrics::ToValue() const {
res->Set("swapinfo", swap_info_.ToValue());
#endif
- return res.Pass();
+ return std::move(res);
+}
+
+ProcessMetrics* ProcessMetrics::CreateCurrentProcessMetrics() {
+#if !defined(OS_MACOSX) || defined(OS_IOS)
+ return CreateProcessMetrics(base::GetCurrentProcessHandle());
+#else
+ return CreateProcessMetrics(base::GetCurrentProcessHandle(), nullptr);
+#endif // !defined(OS_MACOSX) || defined(OS_IOS)
}
double ProcessMetrics::GetPlatformIndependentCPUUsage() {
@@ -53,7 +64,7 @@ double ProcessMetrics::GetPlatformIndependentCPUUsage() {
#if defined(OS_MACOSX) || defined(OS_LINUX)
int ProcessMetrics::CalculateIdleWakeupsPerSecond(
- uint64 absolute_idle_wakeups) {
+ uint64_t absolute_idle_wakeups) {
TimeTicks time = TimeTicks::Now();
if (last_absolute_idle_wakeups_ == 0) {
@@ -63,8 +74,8 @@ int ProcessMetrics::CalculateIdleWakeupsPerSecond(
return 0;
}
- int64 wakeups_delta = absolute_idle_wakeups - last_absolute_idle_wakeups_;
- int64 time_delta = (time - last_idle_wakeups_time_).InMicroseconds();
+ int64_t wakeups_delta = absolute_idle_wakeups - last_absolute_idle_wakeups_;
+ int64_t time_delta = (time - last_idle_wakeups_time_).InMicroseconds();
if (time_delta == 0) {
NOTREACHED();
return 0;
@@ -74,7 +85,7 @@ int ProcessMetrics::CalculateIdleWakeupsPerSecond(
last_absolute_idle_wakeups_ = absolute_idle_wakeups;
// Round to average wakeups per second.
- int64 wakeups_delta_for_ms = wakeups_delta * Time::kMicrosecondsPerSecond;
+ int64_t wakeups_delta_for_ms = wakeups_delta * Time::kMicrosecondsPerSecond;
return (wakeups_delta_for_ms + time_delta / 2) / time_delta;
}
#else
diff --git a/chromium/base/process/process_metrics.h b/chromium/base/process/process_metrics.h
index 327483a42e7..8d8f7fc4ea5 100644
--- a/chromium/base/process/process_metrics.h
+++ b/chromium/base/process/process_metrics.h
@@ -8,14 +8,18 @@
#ifndef BASE_PROCESS_PROCESS_METRICS_H_
#define BASE_PROCESS_PROCESS_METRICS_H_
+#include <stddef.h>
+#include <stdint.h>
+
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/gtest_prod_util.h"
+#include "base/macros.h"
#include "base/process/process_handle.h"
#include "base/time/time.h"
#include "base/values.h"
+#include "build/build_config.h"
#if defined(OS_MACOSX)
#include <mach/mach.h>
@@ -87,11 +91,12 @@ struct CommittedKBytes {
};
// Convert a POSIX timeval to microseconds.
-BASE_EXPORT int64 TimeValToMicroseconds(const struct timeval& tv);
+BASE_EXPORT int64_t TimeValToMicroseconds(const struct timeval& tv);
// Provides performance metrics for a specified process (CPU usage, memory and
-// IO counters). To use it, invoke CreateProcessMetrics() to get an instance
-// for a specific process, then access the information with the different get
+// IO counters). Use CreateCurrentProcessMetrics() to get an instance for the
+// current process, or CreateProcessMetrics() to get an instance for an
+// arbitrary process. Then, access the information with the different get
// methods.
class BASE_EXPORT ProcessMetrics {
public:
@@ -110,6 +115,11 @@ class BASE_EXPORT ProcessMetrics {
PortProvider* port_provider);
#endif // !defined(OS_MACOSX) || defined(OS_IOS)
+ // Creates a ProcessMetrics for the current process. This a cross-platform
+ // convenience wrapper for CreateProcessMetrics().
+ // The caller owns the returned object.
+ static ProcessMetrics* CreateCurrentProcessMetrics();
+
// Returns the current space allocated for the pagefile, in bytes (these pages
// may or may not be in memory). On Linux, this returns the total virtual
// memory size.
@@ -167,6 +177,12 @@ class BASE_EXPORT ProcessMetrics {
// otherwise.
bool GetIOCounters(IoCounters* io_counters) const;
+#if defined(OS_LINUX)
+ // Returns the number of file descriptors currently open by the process, or
+ // -1 on error.
+ int GetOpenFdCount() const;
+#endif // defined(OS_LINUX)
+
private:
#if !defined(OS_MACOSX) || defined(OS_IOS)
explicit ProcessMetrics(ProcessHandle process);
@@ -183,7 +199,7 @@ class BASE_EXPORT ProcessMetrics {
#endif
#if defined(OS_MACOSX) || defined(OS_LINUX)
- int CalculateIdleWakeupsPerSecond(uint64 absolute_idle_wakeups);
+ int CalculateIdleWakeupsPerSecond(uint64_t absolute_idle_wakeups);
#endif
ProcessHandle process_;
@@ -193,12 +209,12 @@ class BASE_EXPORT ProcessMetrics {
// Used to store the previous times and CPU usage counts so we can
// compute the CPU usage between calls.
TimeTicks last_cpu_time_;
- int64 last_system_time_;
+ int64_t last_system_time_;
#if defined(OS_MACOSX) || defined(OS_LINUX)
// Same thing for idle wakeups.
TimeTicks last_idle_wakeups_time_;
- uint64 last_absolute_idle_wakeups_;
+ uint64_t last_absolute_idle_wakeups_;
#endif
#if !defined(OS_IOS)
@@ -324,17 +340,17 @@ struct BASE_EXPORT SystemDiskInfo {
// Serializes the platform specific fields to value.
scoped_ptr<Value> ToValue() const;
- uint64 reads;
- uint64 reads_merged;
- uint64 sectors_read;
- uint64 read_time;
- uint64 writes;
- uint64 writes_merged;
- uint64 sectors_written;
- uint64 write_time;
- uint64 io;
- uint64 io_time;
- uint64 weighted_io_time;
+ uint64_t reads;
+ uint64_t reads_merged;
+ uint64_t sectors_read;
+ uint64_t read_time;
+ uint64_t writes;
+ uint64_t writes_merged;
+ uint64_t sectors_written;
+ uint64_t write_time;
+ uint64_t io;
+ uint64_t io_time;
+ uint64_t weighted_io_time;
};
// Checks whether the candidate string is a valid disk name, [hsv]d[a-z]+
@@ -361,11 +377,11 @@ struct BASE_EXPORT SwapInfo {
// Serializes the platform specific fields to value.
scoped_ptr<Value> ToValue() const;
- uint64 num_reads;
- uint64 num_writes;
- uint64 compr_data_size;
- uint64 orig_data_size;
- uint64 mem_used_total;
+ uint64_t num_reads;
+ uint64_t num_writes;
+ uint64_t compr_data_size;
+ uint64_t orig_data_size;
+ uint64_t mem_used_total;
};
// In ChromeOS, reads files from /sys/block/zram0 that contain ZRAM usage data.
diff --git a/chromium/base/process/process_metrics_freebsd.cc b/chromium/base/process/process_metrics_freebsd.cc
index 9d4149de2ad..5fd93cbe1c9 100644
--- a/chromium/base/process/process_metrics_freebsd.cc
+++ b/chromium/base/process/process_metrics_freebsd.cc
@@ -4,10 +4,12 @@
#include "base/process/process_metrics.h"
+#include <stddef.h>
#include <sys/sysctl.h>
#include <sys/user.h>
#include <unistd.h>
+#include "base/macros.h"
#include "base/sys_info.h"
namespace base {
diff --git a/chromium/base/process/process_metrics_ios.cc b/chromium/base/process/process_metrics_ios.cc
index 135ef43c06c..9625c22d89a 100644
--- a/chromium/base/process/process_metrics_ios.cc
+++ b/chromium/base/process/process_metrics_ios.cc
@@ -4,7 +4,9 @@
#include "base/process/process_metrics.h"
+#include <limits.h>
#include <mach/task.h>
+#include <stddef.h>
#include "base/logging.h"
diff --git a/chromium/base/process/process_metrics_linux.cc b/chromium/base/process/process_metrics_linux.cc
index adca7c5ee23..bcebcf5729f 100644
--- a/chromium/base/process/process_metrics_linux.cc
+++ b/chromium/base/process/process_metrics_linux.cc
@@ -6,11 +6,15 @@
#include <dirent.h>
#include <fcntl.h>
+#include <stddef.h>
+#include <stdint.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
+#include <utility>
+#include "base/files/dir_reader_posix.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/process/internal_linux.h"
@@ -20,6 +24,7 @@
#include "base/strings/string_util.h"
#include "base/sys_info.h"
#include "base/threading/thread_restrictions.h"
+#include "build/build_config.h"
namespace base {
@@ -35,13 +40,13 @@ void TrimKeyValuePairs(StringPairs* pairs) {
}
#if defined(OS_CHROMEOS)
-// Read a file with a single number string and return the number as a uint64.
-static uint64 ReadFileToUint64(const FilePath file) {
+// Read a file with a single number string and return the number as a uint64_t.
+static uint64_t ReadFileToUint64(const FilePath file) {
std::string file_as_string;
if (!ReadFileToString(file, &file_as_string))
return 0;
TrimWhitespaceASCII(file_as_string, TRIM_ALL, &file_as_string);
- uint64 file_as_uint64 = 0;
+ uint64_t file_as_uint64 = 0;
if (!StringToUint64(file_as_string, &file_as_uint64))
return 0;
return file_as_uint64;
@@ -91,7 +96,7 @@ size_t ReadProcStatusAndGetFieldAsSizeT(pid_t pid, const std::string& field) {
// Only works for fields in the form of "field : uint_value"
bool ReadProcSchedAndGetFieldAsUint64(pid_t pid,
const std::string& field,
- uint64* result) {
+ uint64_t* result) {
std::string sched_data;
{
// Synchronously reading files in /proc does not hit the disk.
@@ -108,7 +113,7 @@ bool ReadProcSchedAndGetFieldAsUint64(pid_t pid,
const std::string& key = pairs[i].first;
const std::string& value_str = pairs[i].second;
if (key == field) {
- uint64 value;
+ uint64_t value;
if (!StringToUint64(value_str, &value))
return false;
*result = value;
@@ -213,13 +218,14 @@ double ProcessMetrics::GetCPUUsage() {
// First call, just set the last values.
last_cpu_time_ = time;
last_cpu_ = GetProcessCPU(process_);
- return 0;
+ return 0.0;
}
- int64 time_delta = (time - last_cpu_time_).InMicroseconds();
- DCHECK_NE(time_delta, 0);
- if (time_delta == 0)
- return 0;
+ TimeDelta time_delta = time - last_cpu_time_;
+ if (time_delta.is_zero()) {
+ NOTREACHED();
+ return 0.0;
+ }
int cpu = GetProcessCPU(process_);
@@ -228,8 +234,18 @@ double ProcessMetrics::GetCPUUsage() {
// are together adding to more than one CPU's worth.
TimeDelta cpu_time = internal::ClockTicksToTimeDelta(cpu);
TimeDelta last_cpu_time = internal::ClockTicksToTimeDelta(last_cpu_);
- double percentage = 100.0 * (cpu_time - last_cpu_time).InSecondsF() /
- TimeDelta::FromMicroseconds(time_delta).InSecondsF();
+
+ // If the number of threads running in the process has decreased since the
+ // last time this function was called, |last_cpu_time| will be greater than
+ // |cpu_time| which will result in a negative value in the below percentage
+ // calculation. We prevent this by clamping to 0. crbug.com/546565.
+ // This computation is known to be shaky when threads are destroyed between
+ // "last" and "now", but for our current purposes, it's all right.
+ double percentage = 0.0;
+ if (last_cpu_time < cpu_time) {
+ percentage = 100.0 * (cpu_time - last_cpu_time).InSecondsF() /
+ time_delta.InSecondsF();
+ }
last_cpu_time_ = time;
last_cpu_ = cpu;
@@ -257,7 +273,7 @@ bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
for (size_t i = 0; i < pairs.size(); ++i) {
const std::string& key = pairs[i].first;
const std::string& value_str = pairs[i].second;
- uint64* target_counter = NULL;
+ uint64_t* target_counter = NULL;
if (key == "syscr")
target_counter = &io_counters->ReadOperationCount;
else if (key == "syscw")
@@ -274,6 +290,26 @@ bool ProcessMetrics::GetIOCounters(IoCounters* io_counters) const {
return true;
}
+#if defined(OS_LINUX)
+int ProcessMetrics::GetOpenFdCount() const {
+ // Use /proc/<pid>/fd to count the number of entries there.
+ FilePath fd_path = internal::GetProcPidDir(process_).Append("fd");
+
+ DirReaderPosix dir_reader(fd_path.value().c_str());
+ if (!dir_reader.IsValid())
+ return -1;
+
+ int total_count = 0;
+ for (; dir_reader.Next(); ) {
+ const char* name = dir_reader.name();
+ if (strcmp(name, ".") != 0 && strcmp(name, "..") != 0)
+ ++total_count;
+ }
+
+ return total_count;
+}
+#endif // defined(OS_LINUX)
+
ProcessMetrics::ProcessMetrics(ProcessHandle process)
: process_(process),
last_system_time_(0),
@@ -544,7 +580,7 @@ scoped_ptr<Value> SystemMemoryInfoKB::ToValue() const {
res->SetInteger("gem_size", gem_size);
#endif
- return res.Pass();
+ return std::move(res);
}
// exposed for testing
@@ -733,7 +769,7 @@ SystemDiskInfo::SystemDiskInfo() {
scoped_ptr<Value> SystemDiskInfo::ToValue() const {
scoped_ptr<DictionaryValue> res(new DictionaryValue());
- // Write out uint64 variables as doubles.
+ // Write out uint64_t variables as doubles.
// Note: this may discard some precision, but for JS there's no other option.
res->SetDouble("reads", static_cast<double>(reads));
res->SetDouble("reads_merged", static_cast<double>(reads_merged));
@@ -747,7 +783,7 @@ scoped_ptr<Value> SystemDiskInfo::ToValue() const {
res->SetDouble("io_time", static_cast<double>(io_time));
res->SetDouble("weighted_io_time", static_cast<double>(weighted_io_time));
- return res.Pass();
+ return std::move(res);
}
bool IsValidDiskName(const std::string& candidate) {
@@ -808,17 +844,17 @@ bool GetSystemDiskInfo(SystemDiskInfo* diskinfo) {
diskinfo->io_time = 0;
diskinfo->weighted_io_time = 0;
- uint64 reads = 0;
- uint64 reads_merged = 0;
- uint64 sectors_read = 0;
- uint64 read_time = 0;
- uint64 writes = 0;
- uint64 writes_merged = 0;
- uint64 sectors_written = 0;
- uint64 write_time = 0;
- uint64 io = 0;
- uint64 io_time = 0;
- uint64 weighted_io_time = 0;
+ uint64_t reads = 0;
+ uint64_t reads_merged = 0;
+ uint64_t sectors_read = 0;
+ uint64_t read_time = 0;
+ uint64_t writes = 0;
+ uint64_t writes_merged = 0;
+ uint64_t sectors_written = 0;
+ uint64_t write_time = 0;
+ uint64_t io = 0;
+ uint64_t io_time = 0;
+ uint64_t weighted_io_time = 0;
for (const StringPiece& line : diskinfo_lines) {
std::vector<StringPiece> disk_fields = SplitStringPiece(
@@ -859,7 +895,7 @@ bool GetSystemDiskInfo(SystemDiskInfo* diskinfo) {
scoped_ptr<Value> SwapInfo::ToValue() const {
scoped_ptr<DictionaryValue> res(new DictionaryValue());
- // Write out uint64 variables as doubles.
+ // Write out uint64_t variables as doubles.
// Note: this may discard some precision, but for JS there's no other option.
res->SetDouble("num_reads", static_cast<double>(num_reads));
res->SetDouble("num_writes", static_cast<double>(num_writes));
@@ -872,7 +908,7 @@ scoped_ptr<Value> SwapInfo::ToValue() const {
else
res->SetDouble("compression_ratio", 0);
- return res.Pass();
+ return std::move(res);
}
void GetSwapInfo(SwapInfo* swap_info) {
@@ -880,7 +916,8 @@ void GetSwapInfo(SwapInfo* swap_info) {
ThreadRestrictions::ScopedAllowIO allow_io;
FilePath zram_path("/sys/block/zram0");
- uint64 orig_data_size = ReadFileToUint64(zram_path.Append("orig_data_size"));
+ uint64_t orig_data_size =
+ ReadFileToUint64(zram_path.Append("orig_data_size"));
if (orig_data_size <= 4096) {
// A single page is compressed at startup, and has a high compression
// ratio. We ignore this as it doesn't indicate any real swapping.
@@ -903,7 +940,7 @@ void GetSwapInfo(SwapInfo* swap_info) {
#if defined(OS_LINUX)
int ProcessMetrics::GetIdleWakeupsPerSecond() {
- uint64 wake_ups;
+ uint64_t wake_ups;
const char kWakeupStat[] = "se.statistics.nr_wakeups";
return ReadProcSchedAndGetFieldAsUint64(process_, kWakeupStat, &wake_ups) ?
CalculateIdleWakeupsPerSecond(wake_ups) : 0;
diff --git a/chromium/base/process/process_metrics_mac.cc b/chromium/base/process/process_metrics_mac.cc
index a2ecd8e7185..a8957e288df 100644
--- a/chromium/base/process/process_metrics_mac.cc
+++ b/chromium/base/process/process_metrics_mac.cc
@@ -7,6 +7,8 @@
#include <mach/mach.h>
#include <mach/mach_vm.h>
#include <mach/shared_region.h>
+#include <stddef.h>
+#include <stdint.h>
#include <sys/sysctl.h>
#include "base/containers/hash_tables.h"
@@ -284,7 +286,7 @@ double ProcessMetrics::GetCPUUsage() {
timeradd(&system_timeval, &task_timeval, &task_timeval);
TimeTicks time = TimeTicks::Now();
- int64 task_time = TimeValToMicroseconds(task_timeval);
+ int64_t task_time = TimeValToMicroseconds(task_timeval);
if (last_system_time_ == 0) {
// First call, just set the last values.
@@ -293,8 +295,8 @@ double ProcessMetrics::GetCPUUsage() {
return 0;
}
- int64 system_time_delta = task_time - last_system_time_;
- int64 time_delta = (time - last_cpu_time_).InMicroseconds();
+ int64_t system_time_delta = task_time - last_system_time_;
+ int64_t time_delta = (time - last_cpu_time_).InMicroseconds();
DCHECK_NE(0U, time_delta);
if (time_delta == 0)
return 0;
@@ -352,7 +354,7 @@ size_t GetSystemCommitCharge() {
base::mac::ScopedMachSendRight host(mach_host_self());
mach_msg_type_number_t count = HOST_VM_INFO_COUNT;
vm_statistics_data_t data;
- kern_return_t kr = host_statistics(host, HOST_VM_INFO,
+ kern_return_t kr = host_statistics(host.get(), HOST_VM_INFO,
reinterpret_cast<host_info_t>(&data),
&count);
if (kr != KERN_SUCCESS) {
@@ -368,7 +370,7 @@ bool GetSystemMemoryInfo(SystemMemoryInfoKB* meminfo) {
struct host_basic_info hostinfo;
mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT;
base::mac::ScopedMachSendRight host(mach_host_self());
- int result = host_info(host, HOST_BASIC_INFO,
+ int result = host_info(host.get(), HOST_BASIC_INFO,
reinterpret_cast<host_info_t>(&hostinfo), &count);
if (result != KERN_SUCCESS)
return false;
diff --git a/chromium/base/process/process_metrics_nacl.cc b/chromium/base/process/process_metrics_nacl.cc
new file mode 100644
index 00000000000..025ffd5a414
--- /dev/null
+++ b/chromium/base/process/process_metrics_nacl.cc
@@ -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.
+
+#include "base/process/process_metrics.h"
+
+#include <stddef.h>
+#include <unistd.h>
+
+namespace base {
+
+size_t GetPageSize() {
+ return getpagesize();
+}
+
+} // namespace base
diff --git a/chromium/base/process/process_metrics_openbsd.cc b/chromium/base/process/process_metrics_openbsd.cc
index 72927a1b578..3f76cc222d9 100644
--- a/chromium/base/process/process_metrics_openbsd.cc
+++ b/chromium/base/process/process_metrics_openbsd.cc
@@ -2,8 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/macros.h"
#include "base/process/process_metrics.h"
+#include <stddef.h>
+#include <stdint.h>
#include <sys/param.h>
#include <sys/sysctl.h>
@@ -115,7 +118,7 @@ double ProcessMetrics::GetCPUUsage() {
return 0;
}
- int64 time_delta = (time - last_cpu_time_).InMicroseconds();
+ int64_t time_delta = (time - last_cpu_time_).InMicroseconds();
DCHECK_NE(time_delta, 0);
if (time_delta == 0)
diff --git a/chromium/base/process/process_metrics_posix.cc b/chromium/base/process/process_metrics_posix.cc
index 42b3f2d6655..fad581eece7 100644
--- a/chromium/base/process/process_metrics_posix.cc
+++ b/chromium/base/process/process_metrics_posix.cc
@@ -4,15 +4,20 @@
#include "base/process/process_metrics.h"
+#include <limits.h>
+#include <stddef.h>
+#include <stdint.h>
#include <sys/resource.h>
#include <sys/time.h>
+#include <unistd.h>
#include "base/logging.h"
+#include "build/build_config.h"
namespace base {
-int64 TimeValToMicroseconds(const struct timeval& tv) {
- int64 ret = tv.tv_sec; // Avoid (int * int) integer overflow.
+int64_t TimeValToMicroseconds(const struct timeval& tv) {
+ int64_t ret = tv.tv_sec; // Avoid (int * int) integer overflow.
ret *= Time::kMicrosecondsPerSecond;
ret += tv.tv_usec;
return ret;
diff --git a/chromium/base/process/process_metrics_unittest.cc b/chromium/base/process/process_metrics_unittest.cc
index 31479cefff6..96ba6ceabd9 100644
--- a/chromium/base/process/process_metrics_unittest.cc
+++ b/chromium/base/process/process_metrics_unittest.cc
@@ -4,16 +4,42 @@
#include "base/process/process_metrics.h"
+#include <stddef.h>
+#include <stdint.h>
+
#include <sstream>
#include <string>
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/files/file.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/macros.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/test/multiprocess_test.h"
#include "base/threading/thread.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
-
+#include "testing/multiprocess_func_list.h"
namespace base {
namespace debug {
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+namespace {
+
+void BusyWork(std::vector<std::string>* vec) {
+ int64_t test_value = 0;
+ for (int i = 0; i < 100000; ++i) {
+ ++test_value;
+ vec->push_back(Int64ToString(test_value));
+ }
+}
+
+} // namespace
+#endif // defined(OS_LINUX) || defined(OS_CHROMEOS)
+
// Tests for SystemMetrics.
// Exists as a class so it can be a friend of SystemMetrics.
class SystemMetricsTest : public testing::Test {
@@ -270,11 +296,56 @@ TEST_F(SystemMetricsTest, ParseVmstat) {
}
#endif // defined(OS_LINUX) || defined(OS_ANDROID)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+
+// Test that ProcessMetrics::GetCPUUsage() doesn't return negative values when
+// the number of threads running on the process decreases between two successive
+// calls to it.
+TEST_F(SystemMetricsTest, TestNoNegativeCpuUsage) {
+ ProcessHandle handle = GetCurrentProcessHandle();
+ scoped_ptr<ProcessMetrics> metrics(
+ ProcessMetrics::CreateProcessMetrics(handle));
+
+ EXPECT_GE(metrics->GetCPUUsage(), 0.0);
+ Thread thread1("thread1");
+ Thread thread2("thread2");
+ Thread thread3("thread3");
+
+ thread1.StartAndWaitForTesting();
+ thread2.StartAndWaitForTesting();
+ thread3.StartAndWaitForTesting();
+
+ ASSERT_TRUE(thread1.IsRunning());
+ ASSERT_TRUE(thread2.IsRunning());
+ ASSERT_TRUE(thread3.IsRunning());
+
+ std::vector<std::string> vec1;
+ std::vector<std::string> vec2;
+ std::vector<std::string> vec3;
+
+ thread1.task_runner()->PostTask(FROM_HERE, Bind(&BusyWork, &vec1));
+ thread2.task_runner()->PostTask(FROM_HERE, Bind(&BusyWork, &vec2));
+ thread3.task_runner()->PostTask(FROM_HERE, Bind(&BusyWork, &vec3));
+
+ EXPECT_GE(metrics->GetCPUUsage(), 0.0);
+
+ thread1.Stop();
+ EXPECT_GE(metrics->GetCPUUsage(), 0.0);
+
+ thread2.Stop();
+ EXPECT_GE(metrics->GetCPUUsage(), 0.0);
+
+ thread3.Stop();
+ EXPECT_GE(metrics->GetCPUUsage(), 0.0);
+}
+
+#endif // defined(OS_LINUX) || defined(OS_CHROMEOS)
+
#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) || \
defined(OS_LINUX) || defined(OS_ANDROID)
TEST(SystemMetrics2Test, GetSystemMemoryInfo) {
- base::SystemMemoryInfoKB info;
- EXPECT_TRUE(base::GetSystemMemoryInfo(&info));
+ SystemMemoryInfoKB info;
+ EXPECT_TRUE(GetSystemMemoryInfo(&info));
// Ensure each field received a value.
EXPECT_GT(info.total, 0);
@@ -319,7 +390,7 @@ TEST(ProcessMetricsTest, ParseProcStatCPU) {
"20 0 1 0 121946157 15077376 314 18446744073709551615 4194304 "
"4246868 140733983044336 18446744073709551615 140244213071219 "
"0 0 0 138047495 0 0 0 17 1 0 0 0 0 0";
- EXPECT_EQ(12 + 16, base::ParseProcStatCPU(kTopStat));
+ EXPECT_EQ(12 + 16, ParseProcStatCPU(kTopStat));
// cat /proc/self/stat on a random other machine I have.
const char kSelfStat[] = "5364 (cat) R 5354 5364 5354 34819 5364 "
@@ -328,7 +399,7 @@ TEST(ProcessMetricsTest, ParseProcStatCPU) {
"16 0 1 0 1676099790 2957312 114 4294967295 134512640 134528148 "
"3221224832 3221224344 3086339742 0 0 0 0 0 0 0 17 0 0 0";
- EXPECT_EQ(0, base::ParseProcStatCPU(kSelfStat));
+ EXPECT_EQ(0, ParseProcStatCPU(kSelfStat));
// Some weird long-running process with a weird name that I created for the
// purposes of this test.
@@ -339,29 +410,96 @@ TEST(ProcessMetricsTest, ParseProcStatCPU) {
"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));
+ EXPECT_EQ(5186 + 11, ParseProcStatCPU(kWeirdNameStat));
}
-#endif // defined(OS_LINUX) || defined(OS_ANDROID)
+#endif // defined(OS_LINUX) || defined(OS_ANDROID)
// Disable on Android because base_unittests runs inside a Dalvik VM that
// starts and stop threads (crbug.com/175563).
#if defined(OS_LINUX)
// http://crbug.com/396455
TEST(ProcessMetricsTest, DISABLED_GetNumberOfThreads) {
- const base::ProcessHandle current = base::GetCurrentProcessHandle();
- const int initial_threads = base::GetNumberOfThreads(current);
+ const ProcessHandle current = GetCurrentProcessHandle();
+ const int initial_threads = GetNumberOfThreads(current);
ASSERT_GT(initial_threads, 0);
const int kNumAdditionalThreads = 10;
{
- scoped_ptr<base::Thread> my_threads[kNumAdditionalThreads];
+ scoped_ptr<Thread> my_threads[kNumAdditionalThreads];
for (int i = 0; i < kNumAdditionalThreads; ++i) {
- my_threads[i].reset(new base::Thread("GetNumberOfThreadsTest"));
+ my_threads[i].reset(new Thread("GetNumberOfThreadsTest"));
my_threads[i]->Start();
- ASSERT_EQ(base::GetNumberOfThreads(current), initial_threads + 1 + i);
+ ASSERT_EQ(GetNumberOfThreads(current), initial_threads + 1 + i);
}
}
// The Thread destructor will stop them.
- ASSERT_EQ(initial_threads, base::GetNumberOfThreads(current));
+ ASSERT_EQ(initial_threads, GetNumberOfThreads(current));
+}
+#endif // defined(OS_LINUX)
+
+#if defined(OS_LINUX)
+namespace {
+
+// Keep these in sync so the GetOpenFdCount test can refer to correct test main.
+#define ChildMain ChildFdCount
+#define ChildMainString "ChildFdCount"
+
+// Command line flag name and file name used for synchronization.
+const char kTempDirFlag[] = "temp-dir";
+const char kSignalClosed[] = "closed";
+
+bool SignalEvent(const FilePath& signal_dir, const char* signal_file) {
+ File file(signal_dir.AppendASCII(signal_file),
+ File::FLAG_CREATE | File::FLAG_WRITE);
+ return file.IsValid();
+}
+
+// Check whether an event was signaled.
+bool CheckEvent(const FilePath& signal_dir, const char* signal_file) {
+ File file(signal_dir.AppendASCII(signal_file),
+ File::FLAG_OPEN | File::FLAG_READ);
+ return file.IsValid();
+}
+
+// Busy-wait for an event to be signaled.
+void WaitForEvent(const FilePath& signal_dir, const char* signal_file) {
+ while (!CheckEvent(signal_dir, signal_file))
+ PlatformThread::Sleep(TimeDelta::FromMilliseconds(10));
+}
+
+// Subprocess to test the number of open file descriptors.
+MULTIPROCESS_TEST_MAIN(ChildMain) {
+ CommandLine* command_line = CommandLine::ForCurrentProcess();
+ const FilePath temp_path = command_line->GetSwitchValuePath(kTempDirFlag);
+ CHECK(DirectoryExists(temp_path));
+
+ // Try to close all the file descriptors, so the open count goes to 0.
+ for (size_t i = 0; i < 1000; ++i)
+ close(i);
+ CHECK(SignalEvent(temp_path, kSignalClosed));
+
+ // Wait to be terminated.
+ while (true)
+ PlatformThread::Sleep(TimeDelta::FromSeconds(1));
+ return 0;
+}
+
+} // namespace
+
+TEST(ProcessMetricsTest, GetOpenFdCount) {
+ ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ const FilePath temp_path = temp_dir.path();
+ CommandLine child_command_line(GetMultiProcessTestChildBaseCommandLine());
+ child_command_line.AppendSwitchPath(kTempDirFlag, temp_path);
+ Process child = SpawnMultiProcessTestChild(
+ ChildMainString, child_command_line, LaunchOptions());
+ ASSERT_TRUE(child.IsValid());
+ WaitForEvent(temp_path, kSignalClosed);
+
+ scoped_ptr<ProcessMetrics> metrics(
+ ProcessMetrics::CreateProcessMetrics(child.Handle()));
+ EXPECT_EQ(0, metrics->GetOpenFdCount());
+ ASSERT_TRUE(child.Terminate(0, true));
}
#endif // defined(OS_LINUX)
diff --git a/chromium/base/process/process_metrics_win.cc b/chromium/base/process/process_metrics_win.cc
index c3b3e50ff61..290d918f9a6 100644
--- a/chromium/base/process/process_metrics_win.cc
+++ b/chromium/base/process/process_metrics_win.cc
@@ -6,8 +6,12 @@
#include <windows.h>
#include <psapi.h>
+#include <stddef.h>
+#include <stdint.h>
#include <winternl.h>
+#include <algorithm>
+
#include "base/logging.h"
#include "base/sys_info.h"
@@ -204,7 +208,7 @@ bool ProcessMetrics::GetWorkingSetKBytes(WorkingSetKBytes* ws_usage) const {
return true;
}
-static uint64 FileTimeToUTC(const FILETIME& ftime) {
+static uint64_t FileTimeToUTC(const FILETIME& ftime) {
LARGE_INTEGER li;
li.LowPart = ftime.dwLowDateTime;
li.HighPart = ftime.dwHighDateTime;
@@ -224,8 +228,9 @@ double ProcessMetrics::GetCPUUsage() {
// not yet received the notification.
return 0;
}
- int64 system_time = (FileTimeToUTC(kernel_time) + FileTimeToUTC(user_time)) /
- processor_count_;
+ int64_t system_time =
+ (FileTimeToUTC(kernel_time) + FileTimeToUTC(user_time)) /
+ processor_count_;
TimeTicks time = TimeTicks::Now();
if (last_system_time_ == 0) {
@@ -235,9 +240,9 @@ double ProcessMetrics::GetCPUUsage() {
return 0;
}
- int64 system_time_delta = system_time - last_system_time_;
+ int64_t system_time_delta = system_time - last_system_time_;
// FILETIME is in 100-nanosecond units, so this needs microseconds times 10.
- int64 time_delta = (time - last_cpu_time_).InMicroseconds() * 10;
+ int64_t time_delta = (time - last_cpu_time_).InMicroseconds() * 10;
DCHECK_NE(0U, time_delta);
if (time_delta == 0)
return 0;
diff --git a/chromium/base/process/process_posix.cc b/chromium/base/process/process_posix.cc
index 72e49faefca..ade82e5ce66 100644
--- a/chromium/base/process/process_posix.cc
+++ b/chromium/base/process/process_posix.cc
@@ -4,6 +4,8 @@
#include "base/process/process.h"
+#include <errno.h>
+#include <stdint.h>
#include <sys/resource.h>
#include <sys/wait.h>
@@ -12,6 +14,7 @@
#include "base/posix/eintr_wrapper.h"
#include "base/process/kill.h"
#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "build/build_config.h"
#if defined(OS_MACOSX)
#include <sys/event.h>
@@ -53,9 +56,9 @@ bool WaitpidWithTimeout(base::ProcessHandle handle,
}
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;
+ static const int64_t kMaxSleepInMicroseconds = 1 << 18; // ~256 milliseconds.
+ int64_t max_sleep_time_usecs = 1 << 10; // ~1 milliseconds.
+ int64_t double_sleep_time = 0;
// If the process hasn't exited yet, then sleep and try again.
base::TimeTicks wakeup_time = base::TimeTicks::Now() + wait;
@@ -64,7 +67,7 @@ bool WaitpidWithTimeout(base::ProcessHandle handle,
if (now > wakeup_time)
break;
// Guaranteed to be non-negative!
- int64 sleep_time_usecs = (wakeup_time - now).InMicroseconds();
+ int64_t 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;
@@ -216,16 +219,14 @@ Process::Process(ProcessHandle handle) : process_(handle) {
Process::~Process() {
}
-Process::Process(RValue other)
- : process_(other.object->process_) {
- other.object->Close();
+Process::Process(Process&& other) : process_(other.process_) {
+ other.Close();
}
-Process& Process::operator=(RValue other) {
- if (this != other.object) {
- process_ = other.object->process_;
- other.object->Close();
- }
+Process& Process::operator=(Process&& other) {
+ DCHECK_NE(this, &other);
+ process_ = other.process_;
+ other.Close();
return *this;
}
diff --git a/chromium/base/process/process_unittest.cc b/chromium/base/process/process_unittest.cc
index 9fdc2f1e028..853f1fe8fff 100644
--- a/chromium/base/process/process_unittest.cc
+++ b/chromium/base/process/process_unittest.cc
@@ -4,10 +4,13 @@
#include "base/process/process.h"
+#include <utility>
+
#include "base/process/kill.h"
#include "base/test/multiprocess_test.h"
#include "base/test/test_timeouts.h"
#include "base/threading/platform_thread.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/multiprocess_func_list.h"
@@ -49,13 +52,13 @@ TEST_F(ProcessTest, Move) {
Process process2;
EXPECT_FALSE(process2.IsValid());
- process2 = process1.Pass();
+ process2 = std::move(process1);
EXPECT_TRUE(process2.IsValid());
EXPECT_FALSE(process1.IsValid());
EXPECT_FALSE(process2.is_current());
Process process3 = Process::Current();
- process2 = process3.Pass();
+ process2 = std::move(process3);
EXPECT_TRUE(process2.is_current());
EXPECT_TRUE(process2.IsValid());
EXPECT_FALSE(process3.IsValid());
@@ -203,4 +206,20 @@ TEST_F(ProcessTest, SetProcessBackgroundedSelf) {
EXPECT_EQ(old_priority, new_priority);
}
+#if defined(OS_CHROMEOS)
+
+// Tests that the function IsProcessBackgroundedCGroup() can parse the contents
+// of the /proc/<pid>/cgroup file successfully.
+TEST_F(ProcessTest, TestIsProcessBackgroundedCGroup) {
+ const char kNotBackgrounded[] = "5:cpuacct,cpu,cpuset:/daemons\n";
+ const char kBackgrounded[] =
+ "2:freezer:/chrome_renderers/to_be_frozen\n"
+ "1:cpu:/chrome_renderers/background\n";
+
+ EXPECT_FALSE(IsProcessBackgroundedCGroup(kNotBackgrounded));
+ EXPECT_TRUE(IsProcessBackgroundedCGroup(kBackgrounded));
+}
+
+#endif // defined(OS_CHROMEOS)
+
} // namespace base
diff --git a/chromium/base/process/process_util_unittest.cc b/chromium/base/process/process_util_unittest.cc
index 08144f2a18e..5034f1f03ff 100644
--- a/chromium/base/process/process_util_unittest.cc
+++ b/chromium/base/process/process_util_unittest.cc
@@ -4,6 +4,9 @@
#define _CRT_SECURE_NO_WARNINGS
+#include <stddef.h>
+#include <stdint.h>
+
#include <limits>
#include "base/command_line.h"
@@ -13,6 +16,7 @@
#include "base/files/file_util.h"
#include "base/files/scoped_file.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/path_service.h"
#include "base/posix/eintr_wrapper.h"
@@ -278,7 +282,7 @@ TEST_F(ProcessUtilTest, MAYBE_GetTerminationStatusCrash) {
EXPECT_EQ(base::TERMINATION_STATUS_PROCESS_CRASHED, status);
#if defined(OS_WIN)
- EXPECT_EQ(0xc0000005, exit_code);
+ EXPECT_EQ(static_cast<int>(0xc0000005), exit_code);
#elif defined(OS_POSIX)
int signaled = WIFSIGNALED(exit_code);
EXPECT_NE(0, signaled);
@@ -423,7 +427,7 @@ MULTIPROCESS_TEST_MAIN(TriggerEventChildProcess) {
kEventToTriggerHandleSwitch);
CHECK(!handle_value_string.empty());
- uint64 handle_value_uint64;
+ uint64_t handle_value_uint64;
CHECK(base::StringToUint64(handle_value_string, &handle_value_uint64));
// Give ownership of the handle to |event|.
base::WaitableEvent event(base::win::ScopedHandle(
@@ -450,8 +454,9 @@ TEST_F(ProcessUtilTest, InheritSpecifiedHandles) {
options.handles_to_inherit = &handles_to_inherit;
base::CommandLine cmd_line = MakeCmdLine("TriggerEventChildProcess");
- cmd_line.AppendSwitchASCII(kEventToTriggerHandleSwitch,
- base::Uint64ToString(reinterpret_cast<uint64>(event.handle())));
+ cmd_line.AppendSwitchASCII(
+ kEventToTriggerHandleSwitch,
+ base::Uint64ToString(reinterpret_cast<uint64_t>(event.handle())));
// This functionality actually requires Vista or later. Make sure that it
// fails properly on XP.
@@ -478,9 +483,9 @@ int GetMaxFilesOpenInProcess() {
return 0;
}
- // rlim_t is a uint64 - clip to maxint. We do this since FD #s are ints
+ // rlim_t is a uint64_t - clip to maxint. We do this since FD #s are ints
// which are all 32 bits on the supported platforms.
- rlim_t max_int = static_cast<rlim_t>(std::numeric_limits<int32>::max());
+ rlim_t max_int = static_cast<rlim_t>(std::numeric_limits<int32_t>::max());
if (rlim.rlim_cur > max_int) {
return max_int;
}
diff --git a/chromium/base/process/process_win.cc b/chromium/base/process/process_win.cc
index 818864fa528..e7f35b3f4e2 100644
--- a/chromium/base/process/process_win.cc
+++ b/chromium/base/process/process_win.cc
@@ -25,21 +25,20 @@ Process::Process(ProcessHandle handle)
CHECK_NE(handle, ::GetCurrentProcess());
}
-Process::Process(RValue other)
- : is_current_process_(other.object->is_current_process_),
- process_(other.object->process_.Take()) {
- other.object->Close();
+Process::Process(Process&& other)
+ : is_current_process_(other.is_current_process_),
+ process_(other.process_.Take()) {
+ other.Close();
}
Process::~Process() {
}
-Process& Process::operator=(RValue other) {
- if (this != other.object) {
- process_.Set(other.object->process_.Take());
- is_current_process_ = other.object->is_current_process_;
- other.object->Close();
- }
+Process& Process::operator=(Process&& other) {
+ DCHECK_NE(this, &other);
+ process_.Set(other.process_.Take());
+ is_current_process_ = other.is_current_process_;
+ other.Close();
return *this;
}
diff --git a/chromium/base/profiler/OWNERS b/chromium/base/profiler/OWNERS
new file mode 100644
index 00000000000..81ff9fa5dce
--- /dev/null
+++ b/chromium/base/profiler/OWNERS
@@ -0,0 +1,5 @@
+# Stack sampling profiler
+per-file native_stack_sampler*=wittman@chromium.org
+per-file stack_sampling_profiler*=wittman@chromium.org
+per-file test_support_library*=wittman@chromium.org
+per-file win32_stack_frame_unwinder*=wittman@chromium.org
diff --git a/chromium/base/profiler/alternate_timer.cc b/chromium/base/profiler/alternate_timer.cc
index 02763cd9ef9..b2d2c703202 100644
--- a/chromium/base/profiler/alternate_timer.cc
+++ b/chromium/base/profiler/alternate_timer.cc
@@ -4,11 +4,9 @@
#include "base/profiler/alternate_timer.h"
-#include "base/basictypes.h"
-
namespace {
-tracked_objects::NowFunction* g_time_function = NULL;
+tracked_objects::NowFunction* g_time_function = nullptr;
tracked_objects::TimeSourceType g_time_source_type =
tracked_objects::TIME_SOURCE_TYPE_WALL_TIME;
diff --git a/chromium/base/profiler/native_stack_sampler.cc b/chromium/base/profiler/native_stack_sampler.cc
index 8b4731b6cce..968455f13e0 100644
--- a/chromium/base/profiler/native_stack_sampler.cc
+++ b/chromium/base/profiler/native_stack_sampler.cc
@@ -10,4 +10,8 @@ NativeStackSampler::NativeStackSampler() {}
NativeStackSampler::~NativeStackSampler() {}
+NativeStackSamplerTestDelegate::~NativeStackSamplerTestDelegate() {}
+
+NativeStackSamplerTestDelegate::NativeStackSamplerTestDelegate() {}
+
} // namespace base
diff --git a/chromium/base/profiler/native_stack_sampler.h b/chromium/base/profiler/native_stack_sampler.h
index bc170dcf933..40be5cd2973 100644
--- a/chromium/base/profiler/native_stack_sampler.h
+++ b/chromium/base/profiler/native_stack_sampler.h
@@ -5,12 +5,16 @@
#ifndef BASE_PROFILER_NATIVE_STACK_SAMPLER_H_
#define BASE_PROFILER_NATIVE_STACK_SAMPLER_H_
+#include "base/base_export.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/profiler/stack_sampling_profiler.h"
#include "base/threading/platform_thread.h"
namespace base {
+class NativeStackSamplerTestDelegate;
+
// NativeStackSampler is an implementation detail of StackSamplingProfiler. It
// abstracts the native implementation required to record a stack sample for a
// given thread.
@@ -20,7 +24,9 @@ class 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);
+ static scoped_ptr<NativeStackSampler> Create(
+ PlatformThreadId thread_id,
+ NativeStackSamplerTestDelegate* test_delegate);
// The following functions are all called on the SamplingThread (not the
// thread being sampled).
@@ -44,6 +50,23 @@ class NativeStackSampler {
DISALLOW_COPY_AND_ASSIGN(NativeStackSampler);
};
+// NativeStackSamplerTestDelegate provides seams for test code to execute during
+// stack collection.
+class BASE_EXPORT NativeStackSamplerTestDelegate {
+ public:
+ virtual ~NativeStackSamplerTestDelegate();
+
+ // Called after copying the stack and resuming the target thread, but prior to
+ // walking the stack. Invoked on the SamplingThread.
+ virtual void OnPreStackWalk() = 0;
+
+ protected:
+ NativeStackSamplerTestDelegate();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NativeStackSamplerTestDelegate);
+};
+
} // namespace base
#endif // BASE_PROFILER_NATIVE_STACK_SAMPLER_H_
diff --git a/chromium/base/profiler/native_stack_sampler_posix.cc b/chromium/base/profiler/native_stack_sampler_posix.cc
index bce37e10c3a..c67d8857a57 100644
--- a/chromium/base/profiler/native_stack_sampler_posix.cc
+++ b/chromium/base/profiler/native_stack_sampler_posix.cc
@@ -7,7 +7,8 @@
namespace base {
scoped_ptr<NativeStackSampler> NativeStackSampler::Create(
- PlatformThreadId thread_id) {
+ PlatformThreadId thread_id,
+ NativeStackSamplerTestDelegate* test_delegate) {
return scoped_ptr<NativeStackSampler>();
}
diff --git a/chromium/base/profiler/native_stack_sampler_win.cc b/chromium/base/profiler/native_stack_sampler_win.cc
index bc935c0e588..c240726124d 100644
--- a/chromium/base/profiler/native_stack_sampler_win.cc
+++ b/chromium/base/profiler/native_stack_sampler_win.cc
@@ -4,11 +4,18 @@
#include <objbase.h>
#include <windows.h>
+#include <stddef.h>
+#include <winternl.h>
+#include <cstdlib>
#include <map>
#include <utility>
+#include <vector>
+#include "base/lazy_instance.h"
#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
#include "base/profiler/native_stack_sampler.h"
#include "base/profiler/win32_stack_frame_unwinder.h"
#include "base/strings/string_util.h"
@@ -24,52 +31,139 @@ 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[],
- Win32StackFrameUnwinder* frame_unwinder) {
-#ifdef _WIN64
- int i = 0;
- for (; (i < max_stack_size) && context->Rip; ++i) {
- instruction_pointers[i] = reinterpret_cast<const void*>(context->Rip);
- if (!frame_unwinder->TryUnwind(context))
- return i + 1;
+// The thread environment block internal type.
+struct TEB {
+ NT_TIB Tib;
+ // Rest of struct is ignored.
+};
+
+// Returns the thread environment block pointer for |thread_handle|.
+const TEB* GetThreadEnvironmentBlock(HANDLE thread_handle) {
+ // Define the internal types we need to invoke NtQueryInformationThread.
+ enum THREAD_INFORMATION_CLASS { ThreadBasicInformation };
+
+ struct CLIENT_ID {
+ HANDLE UniqueProcess;
+ HANDLE UniqueThread;
+ };
+
+ struct THREAD_BASIC_INFORMATION {
+ NTSTATUS ExitStatus;
+ TEB* Teb;
+ CLIENT_ID ClientId;
+ KAFFINITY AffinityMask;
+ LONG Priority;
+ LONG BasePriority;
+ };
+
+ using NtQueryInformationThreadFunction =
+ NTSTATUS (WINAPI*)(HANDLE, THREAD_INFORMATION_CLASS, PVOID, ULONG,
+ PULONG);
+
+ const NtQueryInformationThreadFunction nt_query_information_thread =
+ reinterpret_cast<NtQueryInformationThreadFunction>(
+ ::GetProcAddress(::GetModuleHandle(L"ntdll.dll"),
+ "NtQueryInformationThread"));
+ if (!nt_query_information_thread)
+ return nullptr;
+
+ THREAD_BASIC_INFORMATION basic_info = {0};
+ NTSTATUS status =
+ nt_query_information_thread(thread_handle, ThreadBasicInformation,
+ &basic_info, sizeof(THREAD_BASIC_INFORMATION),
+ nullptr);
+ if (status != 0)
+ return nullptr;
+
+ return basic_info.Teb;
+}
+
+#if defined(_WIN64)
+// If the value at |pointer| points to the original stack, rewrite it to point
+// to the corresponding location in the copied stack.
+void RewritePointerIfInOriginalStack(uintptr_t top, uintptr_t bottom,
+ void* stack_copy, const void** pointer) {
+ const uintptr_t value = reinterpret_cast<uintptr_t>(*pointer);
+ if (value >= bottom && value < top) {
+ *pointer = reinterpret_cast<const void*>(
+ static_cast<unsigned char*>(stack_copy) + (value - bottom));
}
- return i;
-#else
- return 0;
-#endif
}
+#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) {
- for (int i = 0; i < stack_depth; ++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;
- }
+// Rewrites possible pointers to locations within the stack to point to the
+// corresponding locations in the copy, and rewrites the non-volatile registers
+// in |context| likewise. This is necessary to handle stack frames with dynamic
+// stack allocation, where a pointer to the beginning of the dynamic allocation
+// area is stored on the stack and/or in a non-volatile register.
+//
+// Eager rewriting of anything that looks like a pointer to the stack, as done
+// in this function, does not adversely affect the stack unwinding. The only
+// other values on the stack the unwinding depends on are return addresses,
+// which should not point within the stack memory. The rewriting is guaranteed
+// to catch all pointers because the stacks are guaranteed by the ABI to be
+// sizeof(void*) aligned.
+//
+// Note: this function must not access memory in the original stack as it may
+// have been changed or deallocated by this point. This is why |top| and
+// |bottom| are passed as uintptr_t.
+void RewritePointersToStackMemory(uintptr_t top, uintptr_t bottom,
+ CONTEXT* context, void* stack_copy) {
+#if defined(_WIN64)
+ DWORD64 CONTEXT::* const nonvolatile_registers[] = {
+ &CONTEXT::R12,
+ &CONTEXT::R13,
+ &CONTEXT::R14,
+ &CONTEXT::R15,
+ &CONTEXT::Rdi,
+ &CONTEXT::Rsi,
+ &CONTEXT::Rbx,
+ &CONTEXT::Rbp,
+ &CONTEXT::Rsp
+ };
+
+ // Rewrite pointers in the context.
+ for (size_t i = 0; i < arraysize(nonvolatile_registers); ++i) {
+ DWORD64* const reg = &(context->*nonvolatile_registers[i]);
+ RewritePointerIfInOriginalStack(top, bottom, stack_copy,
+ reinterpret_cast<const void**>(reg));
}
+
+ // Rewrite pointers on the stack.
+ const void** start = reinterpret_cast<const void**>(stack_copy);
+ const void** end = reinterpret_cast<const void**>(
+ reinterpret_cast<char*>(stack_copy) + (top - bottom));
+ for (const void** loc = start; loc < end; ++loc)
+ RewritePointerIfInOriginalStack(top, bottom, stack_copy, loc);
+#endif
}
-// 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]);
+// Walks the stack represented by |context| from the current frame downwards,
+// recording the instruction pointers for each frame in |instruction_pointers|
+// and associated modules in |modules|.
+void RecordStack(CONTEXT* context,
+ std::vector<const void*>* instruction_pointers,
+ std::vector<ScopedModuleHandle>* modules) {
+#ifdef _WIN64
+ DCHECK(instruction_pointers->empty());
+ DCHECK(modules->empty());
+
+ // Reserve enough memory for most stacks, to avoid repeated
+ // allocations. Approximately 99.5% of recorded stacks are 64 frames or fewer.
+ instruction_pointers->reserve(64);
+ modules->reserve(64);
+
+ Win32StackFrameUnwinder frame_unwinder;
+ while (context->Rip) {
+ const void* instruction_pointer =
+ reinterpret_cast<const void*>(context->Rip);
+ ScopedModuleHandle module;
+ if (!frame_unwinder.TryUnwind(context, &module))
+ return;
+ instruction_pointers->push_back(instruction_pointer);
+ modules->push_back(std::move(module));
}
+#endif
}
// Gets the unique build ID for a module. Windows build IDs are created by a
@@ -133,29 +227,31 @@ ScopedDisablePriorityBoost::~ScopedDisablePriorityBoost() {
::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[]) {
- Win32StackFrameUnwinder frame_unwinder;
+// ScopedSuspendThread --------------------------------------------------------
- if (::SuspendThread(thread_handle) == -1)
- return 0;
+// Suspends a thread for the lifetime of the object.
+class ScopedSuspendThread {
+ public:
+ ScopedSuspendThread(HANDLE thread_handle);
+ ~ScopedSuspendThread();
- 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, &frame_unwinder);
- }
+ bool was_successful() const { return was_successful_; }
+
+ private:
+ HANDLE thread_handle_;
+ bool was_successful_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedSuspendThread);
+};
+
+ScopedSuspendThread::ScopedSuspendThread(HANDLE thread_handle)
+ : thread_handle_(thread_handle),
+ was_successful_(::SuspendThread(thread_handle) !=
+ static_cast<DWORD>(-1)) {}
+
+ScopedSuspendThread::~ScopedSuspendThread() {
+ if (!was_successful_)
+ return;
// Disable the priority boost that the thread would otherwise receive on
// resume. We do this to avoid artificially altering the dynamics of the
@@ -167,18 +263,74 @@ int SuspendThreadAndRecordStack(HANDLE thread_handle, int max_stack_size,
// 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;
+ ScopedDisablePriorityBoost disable_priority_boost(thread_handle_);
+ bool resume_thread_succeeded =
+ ::ResumeThread(thread_handle_) != static_cast<DWORD>(-1);
CHECK(resume_thread_succeeded) << "ResumeThread failed: " << GetLastError();
+}
+
+// Suspends the thread with |thread_handle|, copies its stack and resumes the
+// thread, then records the stack into |instruction_pointers| and associated
+// modules into |modules|.
+//
+// IMPORTANT NOTE: No allocations from the default heap may occur in the
+// ScopedSuspendThread scope, including indirectly via use of DCHECK/CHECK or
+// other logging statements. Otherwise this code can deadlock on heap locks in
+// the default heap acquired by the target thread before it was suspended.
+void SuspendThreadAndRecordStack(
+ HANDLE thread_handle,
+ const void* base_address,
+ void* stack_copy_buffer,
+ size_t stack_copy_buffer_size,
+ std::vector<const void*>* instruction_pointers,
+ std::vector<ScopedModuleHandle>* modules,
+ NativeStackSamplerTestDelegate* test_delegate) {
+ DCHECK(instruction_pointers->empty());
+ DCHECK(modules->empty());
+
+ CONTEXT thread_context = {0};
+ thread_context.ContextFlags = CONTEXT_FULL;
+ // The stack bounds are saved to uintptr_ts for use outside
+ // ScopedSuspendThread, as the thread's memory is not safe to dereference
+ // beyond that point.
+ const uintptr_t top = reinterpret_cast<uintptr_t>(base_address);
+ uintptr_t bottom = 0u;
+
+ {
+ ScopedSuspendThread suspend_thread(thread_handle);
+
+ if (!suspend_thread.was_successful())
+ return;
+
+ if (!::GetThreadContext(thread_handle, &thread_context))
+ return;
+#if defined(_WIN64)
+ bottom = thread_context.Rsp;
+#else
+ bottom = thread_context.Esp;
+#endif
- return stack_depth;
+ if ((top - bottom) > stack_copy_buffer_size)
+ return;
+
+ std::memcpy(stack_copy_buffer, reinterpret_cast<const void*>(bottom),
+ top - bottom);
+ }
+
+ if (test_delegate)
+ test_delegate->OnPreStackWalk();
+
+ RewritePointersToStackMemory(top, bottom, &thread_context, stack_copy_buffer);
+
+ RecordStack(&thread_context, instruction_pointers, modules);
}
// NativeStackSamplerWin ------------------------------------------------------
class NativeStackSamplerWin : public NativeStackSampler {
public:
- explicit NativeStackSamplerWin(win::ScopedHandle thread_handle);
+ NativeStackSamplerWin(win::ScopedHandle thread_handle,
+ NativeStackSamplerTestDelegate* test_delegate);
~NativeStackSamplerWin() override;
// StackSamplingProfiler::NativeStackSampler:
@@ -188,6 +340,15 @@ class NativeStackSamplerWin : public NativeStackSampler {
void ProfileRecordingStopped() override;
private:
+ enum {
+ // Intended to hold the largest stack used by Chrome. The default Win32
+ // reserved stack size is 1 MB and Chrome Windows threads currently always
+ // use the default, but this allows for expansion if it occurs. The size
+ // beyond the actual stack size consists of unallocated virtual memory pages
+ // so carries little cost (just a bit of wated address space).
+ kStackCopyBufferSize = 2 * 1024 * 1024
+ };
+
// 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,
@@ -202,16 +363,26 @@ class NativeStackSamplerWin : public NativeStackSampler {
// 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,
+ void CopyToSample(const std::vector<const void*>& instruction_pointers,
+ const std::vector<ScopedModuleHandle>& module_handles,
StackSamplingProfiler::Sample* sample,
std::vector<StackSamplingProfiler::Module>* modules);
win::ScopedHandle thread_handle_;
+
+ NativeStackSamplerTestDelegate* const test_delegate_;
+
+ // The stack base address corresponding to |thread_handle_|.
+ const void* const thread_stack_base_address_;
+
+ // Buffer to use for copies of the stack. We use the same buffer for all the
+ // samples to avoid the overhead of multiple allocations and frees.
+ const scoped_ptr<unsigned char[]> stack_copy_buffer_;
+
// 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_;
@@ -219,8 +390,13 @@ class NativeStackSamplerWin : public NativeStackSampler {
DISALLOW_COPY_AND_ASSIGN(NativeStackSamplerWin);
};
-NativeStackSamplerWin::NativeStackSamplerWin(win::ScopedHandle thread_handle)
- : thread_handle_(thread_handle.Take()) {
+NativeStackSamplerWin::NativeStackSamplerWin(
+ win::ScopedHandle thread_handle,
+ NativeStackSamplerTestDelegate* test_delegate)
+ : thread_handle_(thread_handle.Take()), test_delegate_(test_delegate),
+ thread_stack_base_address_(
+ GetThreadEnvironmentBlock(thread_handle_.Get())->Tib.StackBase),
+ stack_copy_buffer_(new unsigned char[kStackCopyBufferSize]) {
}
NativeStackSamplerWin::~NativeStackSamplerWin() {
@@ -236,18 +412,15 @@ 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};
-
- int stack_depth = SuspendThreadAndRecordStack(thread_handle_.Get(),
- max_stack_size,
- instruction_pointers);
- FindModuleHandlesForAddresses(instruction_pointers, module_handles,
- stack_depth);
- CopyToSample(instruction_pointers, module_handles, stack_depth, sample,
- current_modules_);
- FreeModuleHandles(stack_depth, module_handles);
+ if (!stack_copy_buffer_)
+ return;
+
+ std::vector<const void*> instruction_pointers;
+ std::vector<ScopedModuleHandle> modules;
+ SuspendThreadAndRecordStack(thread_handle_.Get(), thread_stack_base_address_,
+ stack_copy_buffer_.get(), kStackCopyBufferSize,
+ &instruction_pointers, &modules, test_delegate_);
+ CopyToSample(instruction_pointers, modules, sample, current_modules_);
}
void NativeStackSamplerWin::ProfileRecordingStopped() {
@@ -295,25 +468,26 @@ size_t NativeStackSamplerWin::GetModuleIndex(
}
void NativeStackSamplerWin::CopyToSample(
- const void* const instruction_pointers[],
- const HMODULE module_handles[],
- int stack_depth,
+ const std::vector<const void*>& instruction_pointers,
+ const std::vector<ScopedModuleHandle>& module_handles,
StackSamplingProfiler::Sample* sample,
- std::vector<StackSamplingProfiler::Module>* module) {
+ std::vector<StackSamplingProfiler::Module>* modules) {
+ DCHECK_EQ(instruction_pointers.size(), module_handles.size());
sample->clear();
- sample->reserve(stack_depth);
+ sample->reserve(instruction_pointers.size());
- for (int i = 0; i < stack_depth; ++i) {
+ for (size_t i = 0; i < instruction_pointers.size(); ++i) {
sample->push_back(StackSamplingProfiler::Frame(
reinterpret_cast<uintptr_t>(instruction_pointers[i]),
- GetModuleIndex(module_handles[i], module)));
+ GetModuleIndex(module_handles[i].Get(), modules)));
}
}
} // namespace
scoped_ptr<NativeStackSampler> NativeStackSampler::Create(
- PlatformThreadId thread_id) {
+ PlatformThreadId thread_id,
+ NativeStackSamplerTestDelegate* test_delegate) {
#if _WIN64
// Get the thread's handle.
HANDLE thread_handle = ::OpenThread(
@@ -323,7 +497,8 @@ scoped_ptr<NativeStackSampler> NativeStackSampler::Create(
if (thread_handle) {
return scoped_ptr<NativeStackSampler>(new NativeStackSamplerWin(
- win::ScopedHandle(thread_handle)));
+ win::ScopedHandle(thread_handle),
+ test_delegate));
}
#endif
return scoped_ptr<NativeStackSampler>();
diff --git a/chromium/base/profiler/scoped_profile.h b/chromium/base/profiler/scoped_profile.h
index 2c4105d24aa..657150a0f18 100644
--- a/chromium/base/profiler/scoped_profile.h
+++ b/chromium/base/profiler/scoped_profile.h
@@ -14,6 +14,7 @@
#include "base/base_export.h"
#include "base/location.h"
+#include "base/macros.h"
#include "base/profiler/tracked_time.h"
#include "base/tracked_objects.h"
diff --git a/chromium/base/profiler/scoped_tracker.h b/chromium/base/profiler/scoped_tracker.h
index 23e2f07b61f..a61de9115cf 100644
--- a/chromium/base/profiler/scoped_tracker.h
+++ b/chromium/base/profiler/scoped_tracker.h
@@ -13,6 +13,7 @@
#include "base/bind.h"
#include "base/callback_forward.h"
#include "base/location.h"
+#include "base/macros.h"
#include "base/profiler/scoped_profile.h"
namespace tracked_objects {
diff --git a/chromium/base/profiler/stack_sampling_profiler.cc b/chromium/base/profiler/stack_sampling_profiler.cc
index a197d844093..e89d0527e2c 100644
--- a/chromium/base/profiler/stack_sampling_profiler.cc
+++ b/chromium/base/profiler/stack_sampling_profiler.cc
@@ -5,12 +5,14 @@
#include "base/profiler/stack_sampling_profiler.h"
#include <algorithm>
+#include <utility>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/lazy_instance.h"
#include "base/location.h"
+#include "base/macros.h"
#include "base/profiler/native_stack_sampler.h"
#include "base/synchronization/lock.h"
#include "base/thread_task_runner_handle.h"
@@ -113,11 +115,10 @@ StackSamplingProfiler::SamplingThread::SamplingThread(
scoped_ptr<NativeStackSampler> native_sampler,
const SamplingParams& params,
const CompletedCallback& completed_callback)
- : native_sampler_(native_sampler.Pass()),
+ : native_sampler_(std::move(native_sampler)),
params_(params),
stop_event_(false, false),
- completed_callback_(completed_callback) {
-}
+ completed_callback_(completed_callback) {}
StackSamplingProfiler::SamplingThread::~SamplingThread() {}
@@ -217,10 +218,20 @@ StackSamplingProfiler::SamplingParams::SamplingParams()
sampling_interval(TimeDelta::FromMilliseconds(100)) {
}
-StackSamplingProfiler::StackSamplingProfiler(PlatformThreadId thread_id,
- const SamplingParams& params,
- const CompletedCallback& callback)
- : thread_id_(thread_id), params_(params), completed_callback_(callback) {}
+StackSamplingProfiler::StackSamplingProfiler(
+ PlatformThreadId thread_id,
+ const SamplingParams& params,
+ const CompletedCallback& callback)
+ : StackSamplingProfiler(thread_id, params, callback, nullptr) {}
+
+StackSamplingProfiler::StackSamplingProfiler(
+ PlatformThreadId thread_id,
+ const SamplingParams& params,
+ const CompletedCallback& callback,
+ NativeStackSamplerTestDelegate* test_delegate)
+ : thread_id_(thread_id), params_(params), completed_callback_(callback),
+ test_delegate_(test_delegate) {
+}
StackSamplingProfiler::~StackSamplingProfiler() {
Stop();
@@ -242,12 +253,12 @@ void StackSamplingProfiler::Start() {
return;
scoped_ptr<NativeStackSampler> native_sampler =
- NativeStackSampler::Create(thread_id_);
+ NativeStackSampler::Create(thread_id_, test_delegate_);
if (!native_sampler)
return;
- sampling_thread_.reset(
- new SamplingThread(native_sampler.Pass(), params_, completed_callback_));
+ sampling_thread_.reset(new SamplingThread(std::move(native_sampler), params_,
+ completed_callback_));
if (!PlatformThread::Create(0, sampling_thread_.get(),
&sampling_thread_handle_))
sampling_thread_.reset();
diff --git a/chromium/base/profiler/stack_sampling_profiler.h b/chromium/base/profiler/stack_sampling_profiler.h
index 9aa9c31d67a..ae252bb1c8e 100644
--- a/chromium/base/profiler/stack_sampling_profiler.h
+++ b/chromium/base/profiler/stack_sampling_profiler.h
@@ -5,12 +5,15 @@
#ifndef BASE_PROFILER_STACK_SAMPLING_PROFILER_H_
#define BASE_PROFILER_STACK_SAMPLING_PROFILER_H_
+#include <stddef.h>
+
#include <string>
#include <vector>
#include "base/base_export.h"
#include "base/callback.h"
#include "base/files/file_path.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/string16.h"
#include "base/synchronization/waitable_event.h"
@@ -20,6 +23,7 @@
namespace base {
class NativeStackSampler;
+class NativeStackSamplerTestDelegate;
// StackSamplingProfiler periodically stops a thread to sample its stack, for
// the purpose of collecting information about which code paths are
@@ -156,10 +160,15 @@ class BASE_EXPORT StackSamplingProfiler {
// thread-safe callback implementation.
using CompletedCallback = Callback<void(const CallStackProfiles&)>;
- // Creates a profiler that sends completed profiles to |callback|.
+ // Creates a profiler that sends completed profiles to |callback|. The second
+ // constructor is for test purposes.
StackSamplingProfiler(PlatformThreadId thread_id,
const SamplingParams& params,
const CompletedCallback& callback);
+ StackSamplingProfiler(PlatformThreadId thread_id,
+ const SamplingParams& params,
+ const CompletedCallback& callback,
+ NativeStackSamplerTestDelegate* test_delegate);
// Stops any profiling currently taking place before destroying the profiler.
~StackSamplingProfiler();
@@ -231,6 +240,9 @@ class BASE_EXPORT StackSamplingProfiler {
const CompletedCallback completed_callback_;
+ // Stored until it can be passed to the NativeStackSampler created in Start().
+ NativeStackSamplerTestDelegate* const test_delegate_;
+
DISALLOW_COPY_AND_ASSIGN(StackSamplingProfiler);
};
diff --git a/chromium/base/profiler/stack_sampling_profiler_unittest.cc b/chromium/base/profiler/stack_sampling_profiler_unittest.cc
index 3fceed49ade..fad25a59293 100644
--- a/chromium/base/profiler/stack_sampling_profiler_unittest.cc
+++ b/chromium/base/profiler/stack_sampling_profiler_unittest.cc
@@ -2,25 +2,48 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
+#include <stdint.h>
+
+#include <cstdlib>
+
#include "base/bind.h"
#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "base/memory/scoped_vector.h"
#include "base/message_loop/message_loop.h"
+#include "base/native_library.h"
#include "base/path_service.h"
+#include "base/profiler/native_stack_sampler.h"
#include "base/profiler/stack_sampling_profiler.h"
#include "base/run_loop.h"
+#include "base/scoped_native_library.h"
#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/platform_thread.h"
#include "base/time/time.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
+#if defined(OS_WIN)
+#include <intrin.h>
+#include <malloc.h>
+#include <windows.h>
+#else
+#include <alloca.h>
+#endif
+
// STACK_SAMPLING_PROFILER_SUPPORTED is used to conditionally enable the tests
// below for supported platforms (currently Win x64).
#if defined(_WIN64)
#define STACK_SAMPLING_PROFILER_SUPPORTED 1
#endif
+#if defined(OS_WIN)
+#pragma intrinsic(_ReturnAddress)
+#endif
+
namespace base {
using SamplingParams = StackSamplingProfiler::SamplingParams;
@@ -32,11 +55,37 @@ using CallStackProfiles = StackSamplingProfiler::CallStackProfiles;
namespace {
+// Configuration for the frames that appear on the stack.
+struct StackConfiguration {
+ enum Config { NORMAL, WITH_ALLOCA, WITH_OTHER_LIBRARY };
+
+ explicit StackConfiguration(Config config)
+ : StackConfiguration(config, nullptr) {
+ EXPECT_NE(config, WITH_OTHER_LIBRARY);
+ }
+
+ StackConfiguration(Config config, NativeLibrary library)
+ : config(config), library(library) {
+ EXPECT_TRUE(config != WITH_OTHER_LIBRARY || library);
+ }
+
+ Config config;
+
+ // Only used if config == WITH_OTHER_LIBRARY.
+ NativeLibrary library;
+};
+
+// Signature for a target function that is expected to appear in the stack. See
+// SignalAndWaitUntilSignaled() below. The return value should be a program
+// counter pointer near the end of the function.
+using TargetFunction = const void*(*)(WaitableEvent*, WaitableEvent*,
+ const StackConfiguration*);
+
// 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();
+ TargetThread(const StackConfiguration& stack_config);
// PlatformThread::Delegate:
void ThreadMain() override;
@@ -50,30 +99,76 @@ class TargetThread : public PlatformThread::Delegate {
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);
+ // WaitForThreadStart() and SignalThreadToFinish() when invoked with
+ // |thread_started_event_| and |finish_event_|. Returns a program counter
+ // value near the end of the function. May be invoked with null WaitableEvents
+ // to just return the program counter.
+ //
+ // 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 const void* SignalAndWaitUntilSignaled(
+ WaitableEvent* thread_started_event,
+ WaitableEvent* finish_event,
+ const StackConfiguration* stack_config);
+
+ // Calls into SignalAndWaitUntilSignaled() after allocating memory on the
+ // stack with alloca.
+ static const void* CallWithAlloca(WaitableEvent* thread_started_event,
+ WaitableEvent* finish_event,
+ const StackConfiguration* stack_config);
+
+ // Calls into SignalAndWaitUntilSignaled() via a function in
+ // base_profiler_test_support_library.
+ static const void* CallThroughOtherLibrary(
+ WaitableEvent* thread_started_event,
+ WaitableEvent* finish_event,
+ const StackConfiguration* stack_config);
PlatformThreadId id() const { return id_; }
private:
+ struct TargetFunctionArgs {
+ WaitableEvent* thread_started_event;
+ WaitableEvent* finish_event;
+ const StackConfiguration* stack_config;
+ };
+
+ // Callback function to be provided when calling through the other library.
+ static void OtherLibraryCallback(void *arg);
+
+ // Returns the current program counter, or a value very close to it.
+ static const void* GetProgramCounter();
+
WaitableEvent thread_started_event_;
WaitableEvent finish_event_;
PlatformThreadId id_;
+ const StackConfiguration stack_config_;
DISALLOW_COPY_AND_ASSIGN(TargetThread);
};
-TargetThread::TargetThread()
+TargetThread::TargetThread(const StackConfiguration& stack_config)
: thread_started_event_(false, false), finish_event_(false, false),
- id_(0) {}
+ id_(0), stack_config_(stack_config) {}
void TargetThread::ThreadMain() {
id_ = PlatformThread::CurrentId();
- SignalAndWaitUntilSignaled(&thread_started_event_, &finish_event_);
+ switch (stack_config_.config) {
+ case StackConfiguration::NORMAL:
+ SignalAndWaitUntilSignaled(&thread_started_event_, &finish_event_,
+ &stack_config_);
+ break;
+
+ case StackConfiguration::WITH_ALLOCA:
+ CallWithAlloca(&thread_started_event_, &finish_event_, &stack_config_);
+ break;
+
+ case StackConfiguration::WITH_OTHER_LIBRARY:
+ CallThroughOtherLibrary(&thread_started_event_, &finish_event_,
+ &stack_config_);
+ break;
+ }
}
void TargetThread::WaitForThreadStart() {
@@ -86,14 +181,127 @@ void TargetThread::SignalThreadToFinish() {
// static
// Disable inlining for this function so that it gets its own stack frame.
-NOINLINE void TargetThread::SignalAndWaitUntilSignaled(
+NOINLINE const void* TargetThread::SignalAndWaitUntilSignaled(
+ WaitableEvent* thread_started_event,
+ WaitableEvent* finish_event,
+ const StackConfiguration* stack_config) {
+ if (thread_started_event && finish_event) {
+ thread_started_event->Signal();
+ finish_event->Wait();
+ }
+
+ // Volatile to prevent a tail call to GetProgramCounter().
+ const void* volatile program_counter = GetProgramCounter();
+ return program_counter;
+}
+
+// static
+// Disable inlining for this function so that it gets its own stack frame.
+NOINLINE const void* TargetThread::CallWithAlloca(
+ WaitableEvent* thread_started_event,
+ WaitableEvent* finish_event,
+ const StackConfiguration* stack_config) {
+ const size_t alloca_size = 100;
+ // Memset to 0 to generate a clean failure.
+ std::memset(alloca(alloca_size), 0, alloca_size);
+
+ SignalAndWaitUntilSignaled(thread_started_event, finish_event, stack_config);
+
+ // Volatile to prevent a tail call to GetProgramCounter().
+ const void* volatile program_counter = GetProgramCounter();
+ return program_counter;
+}
+
+// static
+NOINLINE const void* TargetThread::CallThroughOtherLibrary(
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);
+ WaitableEvent* finish_event,
+ const StackConfiguration* stack_config) {
+ if (stack_config) {
+ // A function whose arguments are a function accepting void*, and a void*.
+ using InvokeCallbackFunction = void(*)(void (*)(void*), void*);
+ EXPECT_TRUE(stack_config->library);
+ InvokeCallbackFunction function = reinterpret_cast<InvokeCallbackFunction>(
+ GetFunctionPointerFromNativeLibrary(stack_config->library,
+ "InvokeCallbackFunction"));
+ EXPECT_TRUE(function);
+
+ TargetFunctionArgs args = {
+ thread_started_event,
+ finish_event,
+ stack_config
+ };
+ (*function)(&OtherLibraryCallback, &args);
+ }
+
+ // Volatile to prevent a tail call to GetProgramCounter().
+ const void* volatile program_counter = GetProgramCounter();
+ return program_counter;
+}
+
+// static
+void TargetThread::OtherLibraryCallback(void *arg) {
+ const TargetFunctionArgs* args = static_cast<TargetFunctionArgs*>(arg);
+ SignalAndWaitUntilSignaled(args->thread_started_event, args->finish_event,
+ args->stack_config);
+ // Prevent tail call.
+ volatile int i = 0;
+ ALLOW_UNUSED_LOCAL(i);
+}
+
+// static
+// Disable inlining for this function so that it gets its own stack frame.
+NOINLINE const void* TargetThread::GetProgramCounter() {
+#if defined(OS_WIN)
+ return _ReturnAddress();
+#else
+ return __builtin_return_address(0);
+#endif
+}
+
+// Loads the other library, which defines a function to be called in the
+// WITH_OTHER_LIBRARY configuration.
+NativeLibrary LoadOtherLibrary() {
+ // The lambda gymnastics works around the fact that we can't use ASSERT_*
+ // macros in a function returning non-null.
+ const auto load = [](NativeLibrary* library) {
+ FilePath other_library_path;
+ ASSERT_TRUE(PathService::Get(DIR_EXE, &other_library_path));
+ other_library_path = other_library_path.Append(FilePath::FromUTF16Unsafe(
+ GetNativeLibraryName(ASCIIToUTF16(
+ "base_profiler_test_support_library"))));
+ NativeLibraryLoadError load_error;
+ *library = LoadNativeLibrary(other_library_path, &load_error);
+ ASSERT_TRUE(*library) << "error loading " << other_library_path.value()
+ << ": " << load_error.ToString();
+ };
+
+ NativeLibrary library = nullptr;
+ load(&library);
+ return library;
+}
+
+// Unloads |library| and returns when it has completed unloading. Unloading a
+// library is asynchronous on Windows, so simply calling UnloadNativeLibrary()
+// is insufficient to ensure it's been unloaded.
+void SynchronousUnloadNativeLibrary(NativeLibrary library) {
+ UnloadNativeLibrary(library);
+#if defined(OS_WIN)
+ // NativeLibrary is a typedef for HMODULE, which is actually the base address
+ // of the module.
+ uintptr_t module_base_address = reinterpret_cast<uintptr_t>(library);
+ HMODULE module_handle;
+ // Keep trying to get the module handle until the call fails.
+ while (::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
+ GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
+ reinterpret_cast<LPCTSTR>(module_base_address),
+ &module_handle) ||
+ ::GetLastError() != ERROR_MOD_NOT_FOUND) {
+ PlatformThread::Sleep(TimeDelta::FromMilliseconds(1));
+ }
+#else
+ NOTIMPLEMENTED();
+#endif
}
// Called on the profiler thread when complete, to collect profiles.
@@ -116,8 +324,9 @@ void SaveProfilesAndSignalEvent(CallStackProfiles* profiles,
// SignalAndWaitUntilSignaled(). Performs all necessary target thread startup
// and shutdown work before and afterward.
template <class Function>
-void WithTargetThread(Function function) {
- TargetThread target_thread;
+void WithTargetThread(Function function,
+ const StackConfiguration& stack_config) {
+ TargetThread target_thread(stack_config);
PlatformThreadHandle target_thread_handle;
EXPECT_TRUE(PlatformThread::Create(0, &target_thread, &target_thread_handle));
@@ -130,6 +339,11 @@ void WithTargetThread(Function function) {
PlatformThread::Join(target_thread_handle);
}
+template <class Function>
+void WithTargetThread(Function function) {
+ WithTargetThread(function, StackConfiguration(StackConfiguration::NORMAL));
+}
+
// 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.
@@ -164,7 +378,7 @@ const void* MaybeFixupFunctionAddressForILT(const void* 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 int32_t* offset = reinterpret_cast<const int32_t*>(opcode + 1);
const unsigned char* next_instruction =
reinterpret_cast<const unsigned char*>(offset + 1);
return next_instruction + *offset;
@@ -174,19 +388,19 @@ const void* MaybeFixupFunctionAddressForILT(const void* 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.
+// frame that has an instruction pointer within |target_function|. 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);
+ TargetFunction target_function) {
+ uintptr_t function_start = reinterpret_cast<uintptr_t>(
+ MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>(
+ target_function)));
+ uintptr_t function_end =
+ reinterpret_cast<uintptr_t>(target_function(nullptr, nullptr, nullptr));
for (auto it = sample.begin(); it != sample.end(); ++it) {
- if ((reinterpret_cast<const void*>(it->instruction_pointer) >=
- function_address) &&
- (reinterpret_cast<const void*>(it->instruction_pointer) <
- (static_cast<const unsigned char*>(function_address) + function_size)))
+ if ((it->instruction_pointer >= function_start) &&
+ (it->instruction_pointer <= function_end))
return it;
}
return sample.end();
@@ -209,6 +423,149 @@ std::string FormatSampleForDiagnosticOutput(
// TimeDelta::Max() but https://crbug.com/465948.
TimeDelta AVeryLongTimeDelta() { return TimeDelta::FromDays(1); }
+// Tests the scenario where the library is unloaded after copying the stack, but
+// before walking it. If |wait_until_unloaded| is true, ensures that the
+// asynchronous library loading has completed before walking the stack. If
+// false, the unloading may still be occurring during the stack walk.
+void TestLibraryUnload(bool wait_until_unloaded) {
+ // Test delegate that supports intervening between the copying of the stack
+ // and the walking of the stack.
+ class StackCopiedSignaler : public NativeStackSamplerTestDelegate {
+ public:
+ StackCopiedSignaler(WaitableEvent* stack_copied,
+ WaitableEvent* start_stack_walk,
+ bool wait_to_walk_stack)
+ : stack_copied_(stack_copied), start_stack_walk_(start_stack_walk),
+ wait_to_walk_stack_(wait_to_walk_stack) {
+ }
+
+ void OnPreStackWalk() override {
+ stack_copied_->Signal();
+ if (wait_to_walk_stack_)
+ start_stack_walk_->Wait();
+ }
+
+ private:
+ WaitableEvent* const stack_copied_;
+ WaitableEvent* const start_stack_walk_;
+ const bool wait_to_walk_stack_;
+ };
+
+ SamplingParams params;
+ params.sampling_interval = TimeDelta::FromMilliseconds(0);
+ params.samples_per_burst = 1;
+
+ NativeLibrary other_library = LoadOtherLibrary();
+ TargetThread target_thread(StackConfiguration(
+ StackConfiguration::WITH_OTHER_LIBRARY,
+ other_library));
+
+ PlatformThreadHandle target_thread_handle;
+ EXPECT_TRUE(PlatformThread::Create(0, &target_thread, &target_thread_handle));
+
+ target_thread.WaitForThreadStart();
+
+ WaitableEvent sampling_thread_completed(true, false);
+ std::vector<CallStackProfile> profiles;
+ const StackSamplingProfiler::CompletedCallback callback =
+ Bind(&SaveProfilesAndSignalEvent, Unretained(&profiles),
+ Unretained(&sampling_thread_completed));
+ WaitableEvent stack_copied(true, false);
+ WaitableEvent start_stack_walk(true, false);
+ StackCopiedSignaler test_delegate(&stack_copied, &start_stack_walk,
+ wait_until_unloaded);
+ StackSamplingProfiler profiler(target_thread.id(), params, callback,
+ &test_delegate);
+
+ profiler.Start();
+
+ // Wait for the stack to be copied and the target thread to be resumed.
+ stack_copied.Wait();
+
+ // Cause the target thread to finish, so that it's no longer executing code in
+ // the library we're about to unload.
+ target_thread.SignalThreadToFinish();
+ PlatformThread::Join(target_thread_handle);
+
+ // Unload the library now that it's not being used.
+ if (wait_until_unloaded)
+ SynchronousUnloadNativeLibrary(other_library);
+ else
+ UnloadNativeLibrary(other_library);
+
+ // Let the stack walk commence after unloading the library, if we're waiting
+ // on that event.
+ start_stack_walk.Signal();
+
+ // Wait for the sampling thread to complete and fill out |profiles|.
+ sampling_thread_completed.Wait();
+
+ // Look up the sample.
+ ASSERT_EQ(1u, profiles.size());
+ const CallStackProfile& profile = profiles[0];
+ ASSERT_EQ(1u, profile.samples.size());
+ const Sample& sample = profile.samples[0];
+
+ // Check that the stack contains a frame for
+ // TargetThread::SignalAndWaitUntilSignaled().
+ Sample::const_iterator end_frame = FindFirstFrameWithinFunction(
+ sample,
+ &TargetThread::SignalAndWaitUntilSignaled);
+ ASSERT_TRUE(end_frame != sample.end())
+ << "Function at "
+ << MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>(
+ &TargetThread::SignalAndWaitUntilSignaled))
+ << " was not found in stack:\n"
+ << FormatSampleForDiagnosticOutput(sample, profile.modules);
+
+ if (wait_until_unloaded) {
+ // The stack should look like this, resulting one frame after
+ // SignalAndWaitUntilSignaled. The frame in the now-unloaded library is not
+ // recorded since we can't get module information.
+ //
+ // ... WaitableEvent and system frames ...
+ // TargetThread::SignalAndWaitUntilSignaled
+ // TargetThread::OtherLibraryCallback
+ EXPECT_EQ(2, sample.end() - end_frame)
+ << "Stack:\n"
+ << FormatSampleForDiagnosticOutput(sample, profile.modules);
+ } else {
+ // We didn't wait for the asynchonous unloading to complete, so the results
+ // are non-deterministic: if the library finished unloading we should have
+ // the same stack as |wait_until_unloaded|, if not we should have the full
+ // stack. The important thing is that we should not crash.
+
+ if ((sample.end() - 1) - end_frame == 2) {
+ // This is the same case as |wait_until_unloaded|.
+ return;
+ }
+
+ // Check that the stack contains a frame for
+ // TargetThread::CallThroughOtherLibrary().
+ Sample::const_iterator other_library_frame = FindFirstFrameWithinFunction(
+ sample,
+ &TargetThread::CallThroughOtherLibrary);
+ ASSERT_TRUE(other_library_frame != sample.end())
+ << "Function at "
+ << MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>(
+ &TargetThread::CallThroughOtherLibrary))
+ << " was not found in stack:\n"
+ << FormatSampleForDiagnosticOutput(sample, profile.modules);
+
+ // The stack should look like this, resulting in three frames between
+ // SignalAndWaitUntilSignaled and CallThroughOtherLibrary:
+ //
+ // ... WaitableEvent and system frames ...
+ // TargetThread::SignalAndWaitUntilSignaled
+ // TargetThread::OtherLibraryCallback
+ // InvokeCallbackFunction (in other library)
+ // TargetThread::CallThroughOtherLibrary
+ EXPECT_EQ(3, other_library_frame - end_frame)
+ << "Stack:\n"
+ << FormatSampleForDiagnosticOutput(sample, profile.modules);
+ }
+}
+
} // namespace
// Checks that the basic expected information is present in a sampled call stack
@@ -241,18 +598,13 @@ TEST(StackSamplingProfilerTest, MAYBE_Basic) {
// 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);
+ &TargetThread::SignalAndWaitUntilSignaled);
ASSERT_TRUE(loc != sample.end())
<< "Function at "
- << MaybeFixupFunctionAddressForILT(
- reinterpret_cast<const void*>(
- &TargetThread::SignalAndWaitUntilSignaled))
+ << MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>(
+ &TargetThread::SignalAndWaitUntilSignaled))
<< " was not found in stack:\n"
<< FormatSampleForDiagnosticOutput(sample, profile.modules);
FilePath executable_path;
@@ -260,6 +612,65 @@ TEST(StackSamplingProfilerTest, MAYBE_Basic) {
EXPECT_EQ(executable_path, profile.modules[loc->module_index].filename);
}
+// Checks that the profiler handles stacks containing dynamically-allocated
+// stack memory.
+#if defined(STACK_SAMPLING_PROFILER_SUPPORTED)
+#define MAYBE_Alloca Alloca
+#else
+#define MAYBE_Alloca DISABLED_Alloca
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_Alloca) {
+ SamplingParams params;
+ params.sampling_interval = TimeDelta::FromMilliseconds(0);
+ params.samples_per_burst = 1;
+
+ std::vector<CallStackProfile> profiles;
+ WithTargetThread([&params, &profiles](
+ 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.Wait();
+ }, StackConfiguration(StackConfiguration::WITH_ALLOCA));
+
+ // Look up the sample.
+ ASSERT_EQ(1u, profiles.size());
+ const CallStackProfile& profile = profiles[0];
+ ASSERT_EQ(1u, profile.samples.size());
+ const Sample& sample = profile.samples[0];
+
+ // Check that the stack contains a frame for
+ // TargetThread::SignalAndWaitUntilSignaled().
+ Sample::const_iterator end_frame = FindFirstFrameWithinFunction(
+ sample,
+ &TargetThread::SignalAndWaitUntilSignaled);
+ ASSERT_TRUE(end_frame != sample.end())
+ << "Function at "
+ << MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>(
+ &TargetThread::SignalAndWaitUntilSignaled))
+ << " was not found in stack:\n"
+ << FormatSampleForDiagnosticOutput(sample, profile.modules);
+
+ // Check that the stack contains a frame for TargetThread::CallWithAlloca().
+ Sample::const_iterator alloca_frame = FindFirstFrameWithinFunction(
+ sample,
+ &TargetThread::CallWithAlloca);
+ ASSERT_TRUE(alloca_frame != sample.end())
+ << "Function at "
+ << MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>(
+ &TargetThread::CallWithAlloca))
+ << " was not found in stack:\n"
+ << FormatSampleForDiagnosticOutput(sample, profile.modules);
+
+ // These frames should be adjacent on the stack.
+ EXPECT_EQ(1, alloca_frame - end_frame)
+ << "Stack:\n"
+ << FormatSampleForDiagnosticOutput(sample, profile.modules);
+}
+
// Checks that the fire-and-forget interface works.
#if defined(STACK_SAMPLING_PROFILER_SUPPORTED)
#define MAYBE_StartAndRunAsync StartAndRunAsync
@@ -443,19 +854,113 @@ TEST(StackSamplingProfilerTest, MAYBE_ConcurrentProfiling) {
profiler[0]->Start();
profiler[1]->Start();
- // Wait for the first profiler to finish.
- sampling_completed[0]->Wait();
- EXPECT_EQ(1u, profiles[0].size());
+ // Wait for one profiler to finish.
+ size_t completed_profiler =
+ WaitableEvent::WaitMany(&sampling_completed[0], 2);
+ EXPECT_EQ(1u, profiles[completed_profiler].size());
- // Give the second profiler a chance to run and observe that it hasn't.
- EXPECT_FALSE(
- sampling_completed[1]->TimedWait(TimeDelta::FromMilliseconds(25)));
+ size_t other_profiler = 1 - completed_profiler;
+ // Give the other profiler a chance to run and observe that it hasn't.
+ EXPECT_FALSE(sampling_completed[other_profiler]->TimedWait(
+ TimeDelta::FromMilliseconds(25)));
- // Start the second profiler again and it should run.
- profiler[1]->Start();
- sampling_completed[1]->Wait();
- EXPECT_EQ(1u, profiles[1].size());
+ // Start the other profiler again and it should run.
+ profiler[other_profiler]->Start();
+ sampling_completed[other_profiler]->Wait();
+ EXPECT_EQ(1u, profiles[other_profiler].size());
});
}
+// Checks that a stack that runs through another library produces a stack with
+// the expected functions.
+#if defined(STACK_SAMPLING_PROFILER_SUPPORTED)
+#define MAYBE_OtherLibrary OtherLibrary
+#else
+#define MAYBE_OtherLibrary DISABLED_OtherLibrary
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_OtherLibrary) {
+ SamplingParams params;
+ params.sampling_interval = TimeDelta::FromMilliseconds(0);
+ params.samples_per_burst = 1;
+
+ std::vector<CallStackProfile> profiles;
+ {
+ ScopedNativeLibrary other_library(LoadOtherLibrary());
+ WithTargetThread([&params, &profiles](
+ 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.Wait();
+ }, StackConfiguration(StackConfiguration::WITH_OTHER_LIBRARY,
+ other_library.get()));
+ }
+
+ // Look up the sample.
+ ASSERT_EQ(1u, profiles.size());
+ const CallStackProfile& profile = profiles[0];
+ ASSERT_EQ(1u, profile.samples.size());
+ const Sample& sample = profile.samples[0];
+
+ // Check that the stack contains a frame for
+ // TargetThread::CallThroughOtherLibrary().
+ Sample::const_iterator other_library_frame = FindFirstFrameWithinFunction(
+ sample,
+ &TargetThread::CallThroughOtherLibrary);
+ ASSERT_TRUE(other_library_frame != sample.end())
+ << "Function at "
+ << MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>(
+ &TargetThread::CallThroughOtherLibrary))
+ << " was not found in stack:\n"
+ << FormatSampleForDiagnosticOutput(sample, profile.modules);
+
+ // Check that the stack contains a frame for
+ // TargetThread::SignalAndWaitUntilSignaled().
+ Sample::const_iterator end_frame = FindFirstFrameWithinFunction(
+ sample,
+ &TargetThread::SignalAndWaitUntilSignaled);
+ ASSERT_TRUE(end_frame != sample.end())
+ << "Function at "
+ << MaybeFixupFunctionAddressForILT(reinterpret_cast<const void*>(
+ &TargetThread::SignalAndWaitUntilSignaled))
+ << " was not found in stack:\n"
+ << FormatSampleForDiagnosticOutput(sample, profile.modules);
+
+ // The stack should look like this, resulting in three frames between
+ // SignalAndWaitUntilSignaled and CallThroughOtherLibrary:
+ //
+ // ... WaitableEvent and system frames ...
+ // TargetThread::SignalAndWaitUntilSignaled
+ // TargetThread::OtherLibraryCallback
+ // InvokeCallbackFunction (in other library)
+ // TargetThread::CallThroughOtherLibrary
+ EXPECT_EQ(3, other_library_frame - end_frame)
+ << "Stack:\n" << FormatSampleForDiagnosticOutput(sample, profile.modules);
+}
+
+// Checks that a stack that runs through a library that is unloading produces a
+// stack, and doesn't crash.
+#if defined(STACK_SAMPLING_PROFILER_SUPPORTED)
+#define MAYBE_UnloadingLibrary UnloadingLibrary
+#else
+#define MAYBE_UnloadingLibrary DISABLED_UnloadingLibrary
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_UnloadingLibrary) {
+ TestLibraryUnload(false);
+}
+
+// Checks that a stack that runs through a library that has been unloaded
+// produces a stack, and doesn't crash.
+#if defined(STACK_SAMPLING_PROFILER_SUPPORTED)
+#define MAYBE_UnloadedLibrary UnloadedLibrary
+#else
+#define MAYBE_UnloadedLibrary DISABLED_UnloadedLibrary
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_UnloadedLibrary) {
+ TestLibraryUnload(true);
+}
+
} // namespace base
diff --git a/chromium/base/profiler/test_support_library.cc b/chromium/base/profiler/test_support_library.cc
new file mode 100644
index 00000000000..035f8f70c05
--- /dev/null
+++ b/chromium/base/profiler/test_support_library.cc
@@ -0,0 +1,30 @@
+// 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.
+
+// Note: there is intentionally no header file associated with this library so
+// we don't risk implicitly demand loading it by accessing a symbol.
+
+#if defined(WIN32)
+#define BASE_PROFILER_TEST_SUPPORT_LIBRARY_EXPORT __declspec(dllexport)
+#else // defined(WIN32)
+#define BASE_PROFILER_TEST_SUPPORT_LIBRARY_EXPORT __attribute__((visibility("default")))
+#endif
+
+namespace base {
+
+// Must be defined in an extern "C" block so we can look up the unmangled name.
+extern "C" {
+
+BASE_PROFILER_TEST_SUPPORT_LIBRARY_EXPORT void InvokeCallbackFunction(
+ void (*function)(void*),
+ void* arg) {
+ function(arg);
+ // Prevent tail call.
+ volatile int i = 0;
+ i = 1;
+}
+
+} // extern "C"
+
+} // namespace base
diff --git a/chromium/base/profiler/tracked_time.cc b/chromium/base/profiler/tracked_time.cc
index e5da68f5221..7e0040c03c8 100644
--- a/chromium/base/profiler/tracked_time.cc
+++ b/chromium/base/profiler/tracked_time.cc
@@ -13,7 +13,7 @@
namespace tracked_objects {
Duration::Duration() : ms_(0) {}
-Duration::Duration(int32 duration) : ms_(duration) {}
+Duration::Duration(int32_t duration) : ms_(duration) {}
Duration& Duration::operator+=(const Duration& other) {
ms_ += other.ms_;
@@ -39,15 +39,16 @@ bool Duration::operator>(const Duration& other) const {
// static
Duration Duration::FromMilliseconds(int ms) { return Duration(ms); }
-int32 Duration::InMilliseconds() const { return ms_; }
+int32_t Duration::InMilliseconds() const {
+ return ms_;
+}
//------------------------------------------------------------------------------
TrackedTime::TrackedTime() : ms_(0) {}
-TrackedTime::TrackedTime(int32 ms) : ms_(ms) {}
+TrackedTime::TrackedTime(int32_t ms) : ms_(ms) {}
TrackedTime::TrackedTime(const base::TimeTicks& time)
- : ms_(static_cast<int32>((time - base::TimeTicks()).InMilliseconds())) {
-}
+ : ms_(static_cast<int32_t>((time - base::TimeTicks()).InMilliseconds())) {}
// static
TrackedTime TrackedTime::Now() {
diff --git a/chromium/base/profiler/tracked_time.h b/chromium/base/profiler/tracked_time.h
index 23632749a00..b32f41b39cb 100644
--- a/chromium/base/profiler/tracked_time.h
+++ b/chromium/base/profiler/tracked_time.h
@@ -5,9 +5,9 @@
#ifndef BASE_PROFILER_TRACKED_TIME_H_
#define BASE_PROFILER_TRACKED_TIME_H_
+#include <stdint.h>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/time/time.h"
namespace tracked_objects {
@@ -36,14 +36,14 @@ class BASE_EXPORT Duration { // Similar to base::TimeDelta.
static Duration FromMilliseconds(int ms);
- int32 InMilliseconds() const;
+ int32_t InMilliseconds() const;
private:
friend class TrackedTime;
- explicit Duration(int32 duration);
+ explicit Duration(int32_t duration);
// Internal time is stored directly in milliseconds.
- int32 ms_;
+ int32_t ms_;
};
class BASE_EXPORT TrackedTime { // Similar to base::TimeTicks.
@@ -56,14 +56,14 @@ class BASE_EXPORT TrackedTime { // Similar to base::TimeTicks.
TrackedTime operator+(const Duration& other) const;
bool is_null() const;
- static TrackedTime FromMilliseconds(int32 ms) { return TrackedTime(ms); }
+ static TrackedTime FromMilliseconds(int32_t ms) { return TrackedTime(ms); }
private:
friend class Duration;
- explicit TrackedTime(int32 ms);
+ explicit TrackedTime(int32_t ms);
// Internal duration is stored directly in milliseconds.
- uint32 ms_;
+ uint32_t ms_;
};
} // namespace tracked_objects
diff --git a/chromium/base/profiler/tracked_time_unittest.cc b/chromium/base/profiler/tracked_time_unittest.cc
index c105688b31d..f6d35baab39 100644
--- a/chromium/base/profiler/tracked_time_unittest.cc
+++ b/chromium/base/profiler/tracked_time_unittest.cc
@@ -4,6 +4,8 @@
// Test of classes in tracked_time.cc
+#include <stdint.h>
+
#include "base/profiler/tracked_time.h"
#include "base/time/time.h"
#include "base/tracked_objects.h"
@@ -14,8 +16,8 @@ namespace tracked_objects {
TEST(TrackedTimeTest, TrackedTimerMilliseconds) {
// First make sure we basicallly transfer simple milliseconds values as
// expected. Most critically, things should not become null.
- int32 kSomeMilliseconds = 243; // Some example times.
- int64 kReallyBigMilliseconds = (1LL << 35) + kSomeMilliseconds;
+ int32_t kSomeMilliseconds = 243; // Some example times.
+ int64_t kReallyBigMilliseconds = (1LL << 35) + kSomeMilliseconds;
TrackedTime some = TrackedTime() +
Duration::FromMilliseconds(kSomeMilliseconds);
diff --git a/chromium/base/profiler/win32_stack_frame_unwinder.cc b/chromium/base/profiler/win32_stack_frame_unwinder.cc
index 4ab3a3e1048..472f4f15ffd 100644
--- a/chromium/base/profiler/win32_stack_frame_unwinder.cc
+++ b/chromium/base/profiler/win32_stack_frame_unwinder.cc
@@ -2,81 +2,67 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/macros.h"
#include "base/profiler/win32_stack_frame_unwinder.h"
-#include "base/containers/hash_tables.h"
-#include "base/memory/singleton.h"
-#include "base/stl_util.h"
+#include <windows.h>
+#include <utility>
namespace base {
-// LeafUnwindBlacklist --------------------------------------------------------
+// Win32UnwindFunctions -------------------------------------------------------
-namespace {
-
-// Records modules that are known to have functions that violate the Microsoft
-// x64 calling convention and would be dangerous to manually unwind if
-// encountered as the last frame on the call stack. Functions like these have
-// been observed in injected third party modules that either do not provide
-// function unwind information, or do not provide the required function prologue
-// and epilogue. The former case was observed in several AV products and the
-// latter in a WndProc function associated with Actual Window
-// Manager/aimemb64.dll. See https://crbug.com/476422.
-class LeafUnwindBlacklist {
- public:
- static LeafUnwindBlacklist* GetInstance();
-
- // This function does not allocate memory and is safe to call between
- // SuspendThread and ResumeThread.
- bool IsBlacklisted(const void* module) const;
-
- // Allocates memory. Must be invoked only after ResumeThread, otherwise we
- // risk deadlocking on a heap lock held by a suspended thread.
- void AddModuleToBlacklist(const void* module);
-
- private:
- friend struct DefaultSingletonTraits<LeafUnwindBlacklist>;
-
- LeafUnwindBlacklist();
- ~LeafUnwindBlacklist();
-
- // The set of modules known to have functions that violate the Microsoft x64
- // calling convention.
- base::hash_set<const void*> blacklisted_modules_;
-
- DISALLOW_COPY_AND_ASSIGN(LeafUnwindBlacklist);
-};
+const HMODULE ModuleHandleTraits::kNonNullModuleForTesting =
+ reinterpret_cast<HMODULE>(static_cast<uintptr_t>(-1));
// static
-LeafUnwindBlacklist* LeafUnwindBlacklist::GetInstance() {
- // Leaky for shutdown performance.
- return Singleton<LeafUnwindBlacklist,
- LeakySingletonTraits<LeafUnwindBlacklist>>::get();
+bool ModuleHandleTraits::CloseHandle(HMODULE handle) {
+ if (handle == kNonNullModuleForTesting)
+ return true;
+
+ return ::FreeLibrary(handle) != 0;
}
-bool LeafUnwindBlacklist::IsBlacklisted(const void* module) const {
- return ContainsKey(blacklisted_modules_, module);
+// static
+bool ModuleHandleTraits::IsHandleValid(HMODULE handle) {
+ return handle != nullptr;
}
-void LeafUnwindBlacklist::AddModuleToBlacklist(const void* module) {
- CHECK(module);
- blacklisted_modules_.insert(module);
+// static
+HMODULE ModuleHandleTraits::NullHandle() {
+ return nullptr;
}
-LeafUnwindBlacklist::LeafUnwindBlacklist() {}
-LeafUnwindBlacklist::~LeafUnwindBlacklist() {}
+namespace {
-} // namespace
+// Implements the UnwindFunctions interface for the corresponding Win32
+// functions.
+class Win32UnwindFunctions : public Win32StackFrameUnwinder::UnwindFunctions {
+public:
+ Win32UnwindFunctions();
+ ~Win32UnwindFunctions() override;
-// Win32StackFrameUnwinder ----------------------------------------------------
+ PRUNTIME_FUNCTION LookupFunctionEntry(DWORD64 program_counter,
+ PDWORD64 image_base) override;
-Win32StackFrameUnwinder::UnwindFunctions::~UnwindFunctions() {}
-Win32StackFrameUnwinder::UnwindFunctions::UnwindFunctions() {}
+ void VirtualUnwind(DWORD64 image_base,
+ DWORD64 program_counter,
+ PRUNTIME_FUNCTION runtime_function,
+ CONTEXT* context) override;
+
+ ScopedModuleHandle GetModuleForProgramCounter(
+ DWORD64 program_counter) override;
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(Win32UnwindFunctions);
+};
-Win32StackFrameUnwinder::Win32UnwindFunctions::Win32UnwindFunctions() {}
+Win32UnwindFunctions::Win32UnwindFunctions() {}
+Win32UnwindFunctions::~Win32UnwindFunctions() {}
-PRUNTIME_FUNCTION Win32StackFrameUnwinder::Win32UnwindFunctions::
-LookupFunctionEntry(DWORD64 program_counter, PDWORD64 image_base) {
+PRUNTIME_FUNCTION Win32UnwindFunctions::LookupFunctionEntry(
+ DWORD64 program_counter,
+ PDWORD64 image_base) {
#ifdef _WIN64
return RtlLookupFunctionEntry(program_counter, image_base, nullptr);
#else
@@ -85,38 +71,70 @@ LookupFunctionEntry(DWORD64 program_counter, PDWORD64 image_base) {
#endif
}
-void Win32StackFrameUnwinder::Win32UnwindFunctions::VirtualUnwind(
- DWORD64 image_base,
- DWORD64 program_counter,
- PRUNTIME_FUNCTION runtime_function,
- CONTEXT* context) {
+void Win32UnwindFunctions::VirtualUnwind(DWORD64 image_base,
+ DWORD64 program_counter,
+ PRUNTIME_FUNCTION runtime_function,
+ CONTEXT* context) {
#ifdef _WIN64
void* handler_data;
ULONG64 establisher_frame;
KNONVOLATILE_CONTEXT_POINTERS nvcontext = {};
- RtlVirtualUnwind(0, image_base, program_counter, runtime_function,
- context, &handler_data, &establisher_frame, &nvcontext);
+ RtlVirtualUnwind(UNW_FLAG_NHANDLER, image_base, program_counter,
+ runtime_function, context, &handler_data,
+ &establisher_frame, &nvcontext);
#else
NOTREACHED();
#endif
}
+ScopedModuleHandle Win32UnwindFunctions::GetModuleForProgramCounter(
+ DWORD64 program_counter) {
+ HMODULE module_handle = nullptr;
+ // GetModuleHandleEx() increments the module reference count, which is then
+ // managed and ultimately decremented by ScopedModuleHandle.
+ if (!::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
+ reinterpret_cast<LPCTSTR>(program_counter),
+ &module_handle)) {
+ const DWORD error = ::GetLastError();
+ DCHECK_EQ(ERROR_MOD_NOT_FOUND, static_cast<int>(error));
+ }
+ return ScopedModuleHandle(module_handle);
+}
+
+} // namespace
+
+// Win32StackFrameUnwinder ----------------------------------------------------
+
+Win32StackFrameUnwinder::UnwindFunctions::~UnwindFunctions() {}
+Win32StackFrameUnwinder::UnwindFunctions::UnwindFunctions() {}
Win32StackFrameUnwinder::Win32StackFrameUnwinder()
- : Win32StackFrameUnwinder(&win32_unwind_functions_) {
+ : Win32StackFrameUnwinder(make_scoped_ptr(new Win32UnwindFunctions)) {
}
-Win32StackFrameUnwinder::~Win32StackFrameUnwinder() {
- if (pending_blacklisted_module_) {
- LeafUnwindBlacklist::GetInstance()->AddModuleToBlacklist(
- pending_blacklisted_module_);
- }
-}
+Win32StackFrameUnwinder::~Win32StackFrameUnwinder() {}
-bool Win32StackFrameUnwinder::TryUnwind(CONTEXT* context) {
+bool Win32StackFrameUnwinder::TryUnwind(CONTEXT* context,
+ ScopedModuleHandle* module) {
#ifdef _WIN64
- CHECK(!at_top_frame_ || unwind_info_present_for_all_frames_);
- CHECK(!pending_blacklisted_module_);
+ ScopedModuleHandle frame_module =
+ unwind_functions_->GetModuleForProgramCounter(context->Rip);
+ if (!frame_module.IsValid()) {
+ // There's no loaded module containing the instruction pointer. This can be
+ // due to executing code that is not in a module. In particular,
+ // runtime-generated code associated with third-party injected DLLs
+ // typically is not in a module. It can also be due to the the module having
+ // been unloaded since we recorded the stack. In the latter case the
+ // function unwind information was part of the unloaded module, so it's not
+ // possible to unwind further.
+ //
+ // If a module was found, it's still theoretically possible for the detected
+ // module module to be different than the one that was loaded when the stack
+ // was copied (i.e. if the module was unloaded and a different module loaded
+ // in overlapping memory). This likely would cause a crash, but has not been
+ // observed in practice.
+ return false;
+ }
ULONG64 image_base;
// Try to look up unwind metadata for the current function.
@@ -128,72 +146,30 @@ bool Win32StackFrameUnwinder::TryUnwind(CONTEXT* context) {
context);
at_top_frame_ = false;
} else {
- // RtlLookupFunctionEntry didn't find unwind information. This could mean
- // the code at the instruction pointer is in:
- //
- // 1. a true leaf function (i.e. a function that neither calls a function,
- // nor allocates any stack space itself) in which case the return
- // address is at RSP, or
- //
- // 2. a function that doesn't adhere to the Microsoft x64 calling
- // convention, either by not providing the required unwind information,
- // or by not having the prologue or epilogue required for unwinding;
- // this case has been observed in crash data in injected third party
- // DLLs.
- //
- // In valid code, case 1 can only occur (by definition) as the last frame
- // on the stack. This happens in about 5% of observed stacks and can
- // easily be unwound by popping RSP and using it as the next frame's
- // instruction pointer.
- //
- // Case 2 can occur anywhere on the stack, and attempting to unwind the
- // stack will result in treating whatever value happens to be on the stack
- // at RSP as the next frame's instruction pointer. This is certainly wrong
- // and very likely to lead to crashing by deferencing invalid pointers in
- // the next RtlVirtualUnwind call.
- //
- // If we see case 2 at a location not the last frame, and all the previous
- // frame had valid unwind information, then this is definitely bad code.
- // We blacklist the module as untrustable for unwinding if we encounter a
- // function in it that doesn't have unwind information.
-
if (at_top_frame_) {
at_top_frame_ = false;
- // We are at the end of the stack. It's very likely that we're in case 1
- // since the vast majority of code adheres to the Microsoft x64 calling
- // convention. But there's a small chance we might be unlucky and be in
- // case 2. If this module is known to have bad code according to the
- // leaf unwind blacklist, stop here, otherwise manually unwind.
- if (LeafUnwindBlacklist::GetInstance()->IsBlacklisted(
- reinterpret_cast<const void*>(image_base))) {
- return false;
- }
-
- context->Rip = context->Rsp;
+ // This is a leaf function (i.e. a function that neither calls a function,
+ // nor allocates any stack space itself) so the return address is at RSP.
+ context->Rip = *reinterpret_cast<DWORD64*>(context->Rsp);
context->Rsp += 8;
- unwind_info_present_for_all_frames_ = false;
} else {
- // We're not at the end of the stack. This frame is untrustworthy and we
- // can't safely unwind from here.
- if (unwind_info_present_for_all_frames_) {
- // Unwind information was present for all previous frames, so we can
- // be confident this is case 2. Record the module to be blacklisted.
- pending_blacklisted_module_ =
- reinterpret_cast<const void *>(image_base);
- } else {
- // We started off on a function without unwind information. It's very
- // likely that all frames up to this point have been good, and this
- // frame is case 2. But it's possible that the initial frame was case
- // 2 but hadn't been blacklisted yet, and we've started to go off into
- // the weeds. Since we can't be sure, just bail out without
- // blacklisting the module; chances are we'll later encounter the same
- // function on a stack with full unwind information.
- }
+ // In theory we shouldn't get here, as it means we've encountered a
+ // function without unwind information below the top of the stack, which
+ // is forbidden by the Microsoft x64 calling convention.
+ //
+ // The one known case in Chrome code that executes this path occurs
+ // because of BoringSSL unwind information inconsistent with the actual
+ // function code. See https://crbug.com/542919.
+ //
+ // Note that dodgy third-party generated code that otherwise would enter
+ // this path should be caught by the module check above, since the code
+ // typically is located outside of a module.
return false;
}
}
+ module->Set(frame_module.Take());
return true;
#else
NOTREACHED();
@@ -202,11 +178,8 @@ bool Win32StackFrameUnwinder::TryUnwind(CONTEXT* context) {
}
Win32StackFrameUnwinder::Win32StackFrameUnwinder(
- UnwindFunctions* unwind_functions)
+ scoped_ptr<UnwindFunctions> unwind_functions)
: at_top_frame_(true),
- unwind_info_present_for_all_frames_(true),
- pending_blacklisted_module_(nullptr),
- unwind_functions_(unwind_functions) {
-}
+ unwind_functions_(std::move(unwind_functions)) {}
} // namespace base
diff --git a/chromium/base/profiler/win32_stack_frame_unwinder.h b/chromium/base/profiler/win32_stack_frame_unwinder.h
index a45d5778097..18cd9d6e2bd 100644
--- a/chromium/base/profiler/win32_stack_frame_unwinder.h
+++ b/chromium/base/profiler/win32_stack_frame_unwinder.h
@@ -9,17 +9,44 @@
#include "base/base_export.h"
#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/win/scoped_handle.h"
namespace base {
#if !defined(_WIN64)
// Allows code to compile for x86. Actual support for x86 will require either
// refactoring these interfaces or separate architecture-specific interfaces.
-using PRUNTIME_FUNCTION = void*;
+struct RUNTIME_FUNCTION {
+ DWORD BeginAddress;
+ DWORD EndAddress;
+};
+using PRUNTIME_FUNCTION = RUNTIME_FUNCTION*;
#endif // !defined(_WIN64)
+// Traits class to adapt GenericScopedHandle for HMODULES.
+class ModuleHandleTraits : public win::HandleTraits {
+ public:
+ using Handle = HMODULE;
+
+ static bool BASE_EXPORT CloseHandle(HMODULE handle);
+ static bool BASE_EXPORT IsHandleValid(HMODULE handle);
+ static HMODULE BASE_EXPORT NullHandle();
+
+ BASE_EXPORT static const HMODULE kNonNullModuleForTesting;
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ModuleHandleTraits);
+};
+
+// HMODULE is not really a handle, and has reference count semantics, so the
+// standard VerifierTraits does not apply.
+using ScopedModuleHandle =
+ win::GenericScopedHandle<ModuleHandleTraits, win::DummyVerifierTraits>;
+
// Instances of this class are expected to be created and destroyed for each
-// stack unwinding, outside of SuspendThread/ResumeThread.
+// stack unwinding. This class is not used while the target thread is suspended,
+// so may allocate from the default heap.
class BASE_EXPORT Win32StackFrameUnwinder {
public:
// Interface for Win32 unwind-related functionality this class depends
@@ -34,6 +61,12 @@ class BASE_EXPORT Win32StackFrameUnwinder {
DWORD64 program_counter,
PRUNTIME_FUNCTION runtime_function,
CONTEXT* context) = 0;
+
+ // Returns the module containing |program_counter|. Can return null if the
+ // module has been unloaded.
+ virtual ScopedModuleHandle GetModuleForProgramCounter(
+ DWORD64 program_counter) = 0;
+
protected:
UnwindFunctions();
@@ -41,39 +74,24 @@ class BASE_EXPORT Win32StackFrameUnwinder {
DISALLOW_COPY_AND_ASSIGN(UnwindFunctions);
};
- class BASE_EXPORT Win32UnwindFunctions : public UnwindFunctions {
- public:
- Win32UnwindFunctions();
-
- PRUNTIME_FUNCTION LookupFunctionEntry(DWORD64 program_counter,
- PDWORD64 image_base) override;
-
- void VirtualUnwind(DWORD64 image_base,
- DWORD64 program_counter,
- PRUNTIME_FUNCTION runtime_function,
- CONTEXT* context) override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(Win32UnwindFunctions);
- };
-
Win32StackFrameUnwinder();
~Win32StackFrameUnwinder();
- bool TryUnwind(CONTEXT* context);
+ // Attempts to unwind the frame represented by the stack and instruction
+ // pointers in |context|. If successful, updates |context| and provides the
+ // module associated with the frame in |module|.
+ bool TryUnwind(CONTEXT* context, ScopedModuleHandle* module);
private:
- // This function is for test purposes only.
- Win32StackFrameUnwinder(UnwindFunctions* unwind_functions);
+ // This function is for internal and test purposes only.
+ Win32StackFrameUnwinder(scoped_ptr<UnwindFunctions> unwind_functions);
friend class Win32StackFrameUnwinderTest;
// State associated with each stack unwinding.
bool at_top_frame_;
bool unwind_info_present_for_all_frames_;
- const void* pending_blacklisted_module_;
- Win32UnwindFunctions win32_unwind_functions_;
- UnwindFunctions* const unwind_functions_;
+ scoped_ptr<UnwindFunctions> unwind_functions_;
DISALLOW_COPY_AND_ASSIGN(Win32StackFrameUnwinder);
};
diff --git a/chromium/base/profiler/win32_stack_frame_unwinder_unittest.cc b/chromium/base/profiler/win32_stack_frame_unwinder_unittest.cc
index a27379322f2..264ddf3ec96 100644
--- a/chromium/base/profiler/win32_stack_frame_unwinder_unittest.cc
+++ b/chromium/base/profiler/win32_stack_frame_unwinder_unittest.cc
@@ -2,9 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/profiler/win32_stack_frame_unwinder.h"
+
+#include <utility>
+#include <vector>
+
#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
-#include "base/profiler/win32_stack_frame_unwinder.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
@@ -21,70 +26,96 @@ class TestUnwindFunctions : public Win32StackFrameUnwinder::UnwindFunctions {
DWORD64 program_counter,
PRUNTIME_FUNCTION runtime_function,
CONTEXT* context) override;
+ ScopedModuleHandle GetModuleForProgramCounter(
+ DWORD64 program_counter) override;
- void SetNoUnwindInfoForNextFrame();
- void SetImageBaseForNextFrame(DWORD64 image_base);
+ // Instructs GetModuleForProgramCounter to return null on the next call.
+ void SetUnloadedModule();
+
+ // These functions set whether the next frame will have a RUNTIME_FUNCTION.
+ void SetHasRuntimeFunction(CONTEXT* context);
+ void SetNoRuntimeFunction(CONTEXT* context);
private:
- enum { kRuntimeFunctionPointerIncrement = 1, kImageBaseIncrement = 1 << 20 };
+ enum { kImageBaseIncrement = 1 << 20 };
- static const PRUNTIME_FUNCTION kNonNullRuntimeFunctionPointer;
+ static RUNTIME_FUNCTION* const kInvalidRuntimeFunction;
- DWORD64 supplied_program_counter_;
- DWORD64 custom_image_base_;
+ bool module_is_loaded_;
+ DWORD64 expected_program_counter_;
DWORD64 next_image_base_;
- bool next_lookup_returns_null_;
+ DWORD64 expected_image_base_;
+ RUNTIME_FUNCTION* next_runtime_function_;
+ std::vector<RUNTIME_FUNCTION> runtime_functions_;
DISALLOW_COPY_AND_ASSIGN(TestUnwindFunctions);
};
-// This value is opaque to Win32StackFrameUnwinder.
-const PRUNTIME_FUNCTION TestUnwindFunctions::kNonNullRuntimeFunctionPointer =
- reinterpret_cast<PRUNTIME_FUNCTION>(8);
+RUNTIME_FUNCTION* const TestUnwindFunctions::kInvalidRuntimeFunction =
+ reinterpret_cast<RUNTIME_FUNCTION*>(static_cast<uintptr_t>(-1));
TestUnwindFunctions::TestUnwindFunctions()
- : supplied_program_counter_(0),
- custom_image_base_(0),
+ : module_is_loaded_(true),
+ expected_program_counter_(0),
next_image_base_(kImageBaseIncrement),
- next_lookup_returns_null_(false) {
+ expected_image_base_(0),
+ next_runtime_function_(kInvalidRuntimeFunction) {
}
PRUNTIME_FUNCTION TestUnwindFunctions::LookupFunctionEntry(
DWORD64 program_counter,
PDWORD64 image_base) {
- supplied_program_counter_ = program_counter;
- if (custom_image_base_) {
- *image_base = custom_image_base_;
- custom_image_base_ = 0;
- } else {
- *image_base = next_image_base_;
- next_image_base_ += kImageBaseIncrement;
- }
- if (next_lookup_returns_null_) {
- next_lookup_returns_null_ = false;
- return nullptr;
- }
-
- return kNonNullRuntimeFunctionPointer;
+ EXPECT_EQ(expected_program_counter_, program_counter);
+ *image_base = expected_image_base_ = next_image_base_;
+ next_image_base_ += kImageBaseIncrement;
+ RUNTIME_FUNCTION* return_value = next_runtime_function_;
+ next_runtime_function_ = kInvalidRuntimeFunction;
+ return return_value;
}
void TestUnwindFunctions::VirtualUnwind(DWORD64 image_base,
DWORD64 program_counter,
PRUNTIME_FUNCTION runtime_function,
CONTEXT* context) {
- EXPECT_EQ(next_image_base_ - kImageBaseIncrement, image_base);
- EXPECT_EQ(supplied_program_counter_, program_counter);
- // This function should only be called when LookupFunctionEntry returns a
- // non-null value.
- EXPECT_EQ(kNonNullRuntimeFunctionPointer, runtime_function);
+ ASSERT_NE(kInvalidRuntimeFunction, runtime_function)
+ << "expected call to SetHasRuntimeFunction() or SetNoRuntimeFunction() "
+ << "before invoking TryUnwind()";
+ EXPECT_EQ(expected_image_base_, image_base);
+ expected_image_base_ = 0;
+ EXPECT_EQ(expected_program_counter_, program_counter);
+ expected_program_counter_ = 0;
+ // This function should only be called when LookupFunctionEntry returns
+ // a RUNTIME_FUNCTION.
+ EXPECT_EQ(&runtime_functions_.back(), runtime_function);
+}
+
+ScopedModuleHandle TestUnwindFunctions::GetModuleForProgramCounter(
+ DWORD64 program_counter) {
+ bool return_non_null_value = module_is_loaded_;
+ module_is_loaded_ = true;
+ return ScopedModuleHandle(return_non_null_value ?
+ ModuleHandleTraits::kNonNullModuleForTesting :
+ nullptr);
}
-void TestUnwindFunctions::SetNoUnwindInfoForNextFrame() {
- next_lookup_returns_null_ = true;
+void TestUnwindFunctions::SetUnloadedModule() {
+ module_is_loaded_ = false;
}
-void TestUnwindFunctions::SetImageBaseForNextFrame(DWORD64 image_base) {
- next_image_base_ = image_base;
+void TestUnwindFunctions::SetHasRuntimeFunction(CONTEXT* context) {
+ RUNTIME_FUNCTION runtime_function = {};
+ runtime_function.BeginAddress = 16;
+ runtime_function.EndAddress = runtime_function.BeginAddress + 256;
+ runtime_functions_.push_back(runtime_function);
+ next_runtime_function_ = &runtime_functions_.back();
+
+ expected_program_counter_ = context->Rip =
+ next_image_base_ + runtime_function.BeginAddress + 8;
+}
+
+void TestUnwindFunctions::SetNoRuntimeFunction(CONTEXT* context) {
+ expected_program_counter_ = context->Rip = 100;
+ next_runtime_function_ = nullptr;
}
} // namespace
@@ -97,7 +128,8 @@ class Win32StackFrameUnwinderTest : public testing::Test {
// with a single friend declaration of this test fixture.
scoped_ptr<Win32StackFrameUnwinder> CreateUnwinder();
- TestUnwindFunctions unwind_functions_;
+ // Weak pointer to the unwind functions used by last created unwinder.
+ TestUnwindFunctions* unwind_functions_;
private:
DISALLOW_COPY_AND_ASSIGN(Win32StackFrameUnwinderTest);
@@ -105,16 +137,41 @@ class Win32StackFrameUnwinderTest : public testing::Test {
scoped_ptr<Win32StackFrameUnwinder>
Win32StackFrameUnwinderTest::CreateUnwinder() {
- return make_scoped_ptr(new Win32StackFrameUnwinder(&unwind_functions_));
+ scoped_ptr<TestUnwindFunctions> unwind_functions(new TestUnwindFunctions);
+ unwind_functions_ = unwind_functions.get();
+ return make_scoped_ptr(
+ new Win32StackFrameUnwinder(std::move(unwind_functions)));
}
// Checks the case where all frames have unwind information.
TEST_F(Win32StackFrameUnwinderTest, FramesWithUnwindInfo) {
scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder();
CONTEXT context = {0};
- EXPECT_TRUE(unwinder->TryUnwind(&context));
- EXPECT_TRUE(unwinder->TryUnwind(&context));
- EXPECT_TRUE(unwinder->TryUnwind(&context));
+ ScopedModuleHandle module;
+
+ unwind_functions_->SetHasRuntimeFunction(&context);
+ EXPECT_TRUE(unwinder->TryUnwind(&context, &module));
+ EXPECT_TRUE(module.IsValid());
+
+ unwind_functions_->SetHasRuntimeFunction(&context);
+ module.Set(nullptr);
+ EXPECT_TRUE(unwinder->TryUnwind(&context, &module));
+ EXPECT_TRUE(module.IsValid());
+
+ unwind_functions_->SetHasRuntimeFunction(&context);
+ module.Set(nullptr);
+ EXPECT_TRUE(unwinder->TryUnwind(&context, &module));
+ EXPECT_TRUE(module.IsValid());
+}
+
+// Checks that an instruction pointer in an unloaded module fails to unwind.
+TEST_F(Win32StackFrameUnwinderTest, UnloadedModule) {
+ scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder();
+ CONTEXT context = {0};
+ ScopedModuleHandle module;
+
+ unwind_functions_->SetUnloadedModule();
+ EXPECT_FALSE(unwinder->TryUnwind(&context, &module));
}
// Checks that the CONTEXT's stack pointer gets popped when the top frame has no
@@ -122,109 +179,42 @@ TEST_F(Win32StackFrameUnwinderTest, FramesWithUnwindInfo) {
TEST_F(Win32StackFrameUnwinderTest, FrameAtTopWithoutUnwindInfo) {
scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder();
CONTEXT context = {0};
- const DWORD64 original_rsp = 128;
+ ScopedModuleHandle module;
+ DWORD64 next_ip = 0x0123456789abcdef;
+ DWORD64 original_rsp = reinterpret_cast<DWORD64>(&next_ip);
context.Rsp = original_rsp;
- unwind_functions_.SetNoUnwindInfoForNextFrame();
- EXPECT_TRUE(unwinder->TryUnwind(&context));
- EXPECT_EQ(original_rsp, context.Rip);
+
+ unwind_functions_->SetNoRuntimeFunction(&context);
+ EXPECT_TRUE(unwinder->TryUnwind(&context, &module));
+ EXPECT_EQ(next_ip, context.Rip);
EXPECT_EQ(original_rsp + 8, context.Rsp);
+ EXPECT_TRUE(module.IsValid());
+
+ unwind_functions_->SetHasRuntimeFunction(&context);
+ module.Set(nullptr);
+ EXPECT_TRUE(unwinder->TryUnwind(&context, &module));
+ EXPECT_TRUE(module.IsValid());
- EXPECT_TRUE(unwinder->TryUnwind(&context));
- EXPECT_TRUE(unwinder->TryUnwind(&context));
+ unwind_functions_->SetHasRuntimeFunction(&context);
+ module.Set(nullptr);
+ EXPECT_TRUE(unwinder->TryUnwind(&context, &module));
+ EXPECT_TRUE(module.IsValid());
}
// Checks that a frame below the top of the stack with missing unwind info
-// results in blacklisting the module.
-TEST_F(Win32StackFrameUnwinderTest, BlacklistedModule) {
- const DWORD64 image_base_for_module_with_bad_function = 1024;
+// terminates the unwinding.
+TEST_F(Win32StackFrameUnwinderTest, FrameBelowTopWithoutUnwindInfo) {
{
// First stack, with a bad function below the top of the stack.
scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder();
CONTEXT context = {0};
- EXPECT_TRUE(unwinder->TryUnwind(&context));
-
- unwind_functions_.SetNoUnwindInfoForNextFrame();
- unwind_functions_.SetImageBaseForNextFrame(
- image_base_for_module_with_bad_function);
- EXPECT_FALSE(unwinder->TryUnwind(&context));
- }
-
- {
- // Second stack; check that a function at the top of the stack without
- // unwind info from the previously-seen module is blacklisted.
- scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder();
- CONTEXT context = {0};
- unwind_functions_.SetNoUnwindInfoForNextFrame();
- unwind_functions_.SetImageBaseForNextFrame(
- image_base_for_module_with_bad_function);
- EXPECT_FALSE(unwinder->TryUnwind(&context));
- }
-
- {
- // Third stack; check that a function at the top of the stack *with* unwind
- // info from the previously-seen module is not blacklisted. Then check that
- // functions below the top of the stack with unwind info are not
- // blacklisted, regardless of whether they are in the previously-seen
- // module.
- scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder();
- CONTEXT context = {0};
- unwind_functions_.SetImageBaseForNextFrame(
- image_base_for_module_with_bad_function);
- EXPECT_TRUE(unwinder->TryUnwind(&context));
-
- EXPECT_TRUE(unwinder->TryUnwind(&context));
-
- unwind_functions_.SetImageBaseForNextFrame(
- image_base_for_module_with_bad_function);
- EXPECT_TRUE(unwinder->TryUnwind(&context));
- }
-
- {
- // Fourth stack; check that a function at the top of the stack without
- // unwind info and not from the previously-seen module is not
- // blacklisted. Then check that functions below the top of the stack with
- // unwind info are not blacklisted, regardless of whether they are in the
- // previously-seen module.
- scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder();
- CONTEXT context = {0};
- unwind_functions_.SetNoUnwindInfoForNextFrame();
- EXPECT_TRUE(unwinder->TryUnwind(&context));
+ ScopedModuleHandle module;
+ unwind_functions_->SetHasRuntimeFunction(&context);
+ EXPECT_TRUE(unwinder->TryUnwind(&context, &module));
+ EXPECT_TRUE(module.IsValid());
- EXPECT_TRUE(unwinder->TryUnwind(&context));
-
- unwind_functions_.SetImageBaseForNextFrame(
- image_base_for_module_with_bad_function);
- EXPECT_TRUE(unwinder->TryUnwind(&context));
- }
-}
-
-// Checks that a frame below the top of the stack with missing unwind info does
-// not result in blacklisting the module if the first frame also was missing
-// unwind info. This ensures we don't blacklist an innocent module because the
-// first frame was bad but we didn't know it at the time.
-TEST_F(Win32StackFrameUnwinderTest, ModuleFromQuestionableFrameNotBlacklisted) {
- const DWORD64 image_base_for_questionable_module = 2048;
- {
- // First stack, with both the first and second frames missing unwind info.
- scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder();
- CONTEXT context = {0};
- unwind_functions_.SetNoUnwindInfoForNextFrame();
- EXPECT_TRUE(unwinder->TryUnwind(&context));
-
- unwind_functions_.SetNoUnwindInfoForNextFrame();
- unwind_functions_.SetImageBaseForNextFrame(
- image_base_for_questionable_module);
- EXPECT_FALSE(unwinder->TryUnwind(&context));
- }
-
- {
- // Second stack; check that the questionable module was not blacklisted.
- scoped_ptr<Win32StackFrameUnwinder> unwinder = CreateUnwinder();
- CONTEXT context = {0};
- unwind_functions_.SetNoUnwindInfoForNextFrame();
- unwind_functions_.SetImageBaseForNextFrame(
- image_base_for_questionable_module);
- EXPECT_TRUE(unwinder->TryUnwind(&context));
+ unwind_functions_->SetNoRuntimeFunction(&context);
+ EXPECT_FALSE(unwinder->TryUnwind(&context, &module));
}
}
diff --git a/chromium/base/rand_util.cc b/chromium/base/rand_util.cc
index 931eb4e943e..fab6c6613c2 100644
--- a/chromium/base/rand_util.cc
+++ b/chromium/base/rand_util.cc
@@ -4,13 +4,13 @@
#include "base/rand_util.h"
+#include <limits.h>
#include <math.h>
#include <stdint.h>
#include <algorithm>
#include <limits>
-#include "base/basictypes.h"
#include "base/logging.h"
#include "base/strings/string_util.h"
@@ -19,8 +19,11 @@ namespace base {
int RandInt(int min, int max) {
DCHECK_LE(min, max);
- uint64 range = static_cast<uint64>(max) - min + 1;
- int result = min + static_cast<int>(base::RandGenerator(range));
+ uint64_t range = static_cast<uint64_t>(max) - min + 1;
+ // |range| is at most UINT_MAX + 1, so the result of RandGenerator(range)
+ // is at most UINT_MAX. Hence it's safe to cast it from uint64_t to int64_t.
+ int result =
+ static_cast<int>(min + static_cast<int64_t>(base::RandGenerator(range)));
DCHECK_GE(result, min);
DCHECK_LE(result, max);
return result;
@@ -30,31 +33,32 @@ double RandDouble() {
return BitsToOpenEndedUnitInterval(base::RandUint64());
}
-double BitsToOpenEndedUnitInterval(uint64 bits) {
+double BitsToOpenEndedUnitInterval(uint64_t bits) {
// We try to get maximum precision by masking out as many bits as will fit
// in the target type's mantissa, and raising it to an appropriate power to
// produce output in the range [0, 1). For IEEE 754 doubles, the mantissa
// is expected to accommodate 53 bits.
- COMPILE_ASSERT(std::numeric_limits<double>::radix == 2, otherwise_use_scalbn);
+ static_assert(std::numeric_limits<double>::radix == 2,
+ "otherwise use scalbn");
static const int kBits = std::numeric_limits<double>::digits;
- uint64 random_bits = bits & ((UINT64_C(1) << kBits) - 1);
+ uint64_t random_bits = bits & ((UINT64_C(1) << kBits) - 1);
double result = ldexp(static_cast<double>(random_bits), -1 * kBits);
DCHECK_GE(result, 0.0);
DCHECK_LT(result, 1.0);
return result;
}
-uint64 RandGenerator(uint64 range) {
+uint64_t RandGenerator(uint64_t range) {
DCHECK_GT(range, 0u);
// We must discard random results above this number, as they would
// make the random generator non-uniform (consider e.g. if
// MAX_UINT64 was 7 and |range| was 5, then a result of 1 would be twice
// as likely as a result of 3 or 4).
- uint64 max_acceptable_value =
- (std::numeric_limits<uint64>::max() / range) * range - 1;
+ uint64_t max_acceptable_value =
+ (std::numeric_limits<uint64_t>::max() / range) * range - 1;
- uint64 value;
+ uint64_t value;
do {
value = base::RandUint64();
} while (value > max_acceptable_value);
diff --git a/chromium/base/rand_util.h b/chromium/base/rand_util.h
index 6130c129b7f..881dbd50bb1 100644
--- a/chromium/base/rand_util.h
+++ b/chromium/base/rand_util.h
@@ -5,15 +5,18 @@
#ifndef BASE_RAND_UTIL_H_
#define BASE_RAND_UTIL_H_
+#include <stddef.h>
+#include <stdint.h>
+
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "build/build_config.h"
namespace base {
-// Returns a random number in range [0, kuint64max]. Thread-safe.
-BASE_EXPORT uint64 RandUint64();
+// Returns a random number in range [0, UINT64_MAX]. Thread-safe.
+BASE_EXPORT uint64_t RandUint64();
// Returns a random number between min and max (inclusive). Thread-safe.
BASE_EXPORT int RandInt(int min, int max);
@@ -23,14 +26,14 @@ BASE_EXPORT int RandInt(int min, int max);
// Note that this can be used as an adapter for std::random_shuffle():
// Given a pre-populated |std::vector<int> myvector|, shuffle it as
// std::random_shuffle(myvector.begin(), myvector.end(), base::RandGenerator);
-BASE_EXPORT uint64 RandGenerator(uint64 range);
+BASE_EXPORT uint64_t RandGenerator(uint64_t range);
// Returns a random double in range [0, 1). Thread-safe.
BASE_EXPORT double RandDouble();
// Given input |bits|, convert with maximum precision to a double in
// the range [0, 1). Thread-safe.
-BASE_EXPORT double BitsToOpenEndedUnitInterval(uint64 bits);
+BASE_EXPORT double BitsToOpenEndedUnitInterval(uint64_t bits);
// Fills |output_length| bytes of |output| with random data.
//
diff --git a/chromium/base/rand_util_nacl.cc b/chromium/base/rand_util_nacl.cc
index b771dc44547..35b4b26c68d 100644
--- a/chromium/base/rand_util_nacl.cc
+++ b/chromium/base/rand_util_nacl.cc
@@ -5,8 +5,9 @@
#include "base/rand_util.h"
#include <nacl/nacl_random.h>
+#include <stddef.h>
+#include <stdint.h>
-#include "base/basictypes.h"
#include "base/logging.h"
namespace {
@@ -28,8 +29,8 @@ void GetRandomBytes(void* output, size_t num_bytes) {
namespace base {
// NOTE: This function must be cryptographically secure. http://crbug.com/140076
-uint64 RandUint64() {
- uint64 result;
+uint64_t RandUint64() {
+ uint64_t result;
GetRandomBytes(&result, sizeof(result));
return result;
}
diff --git a/chromium/base/rand_util_posix.cc b/chromium/base/rand_util_posix.cc
index fe73b960f94..6a6e05ada81 100644
--- a/chromium/base/rand_util_posix.cc
+++ b/chromium/base/rand_util_posix.cc
@@ -6,6 +6,8 @@
#include <errno.h>
#include <fcntl.h>
+#include <stddef.h>
+#include <stdint.h>
#include <unistd.h>
#include "base/files/file_util.h"
@@ -39,8 +41,8 @@ base::LazyInstance<URandomFd>::Leaky g_urandom_fd = LAZY_INSTANCE_INITIALIZER;
namespace base {
// NOTE: This function must be cryptographically secure. http://crbug.com/140076
-uint64 RandUint64() {
- uint64 number;
+uint64_t RandUint64() {
+ uint64_t number;
RandBytes(&number, sizeof(number));
return number;
}
diff --git a/chromium/base/rand_util_unittest.cc b/chromium/base/rand_util_unittest.cc
index 90690ec2dbb..ea803ee73f4 100644
--- a/chromium/base/rand_util_unittest.cc
+++ b/chromium/base/rand_util_unittest.cc
@@ -4,6 +4,9 @@
#include "base/rand_util.h"
+#include <stddef.h>
+#include <stdint.h>
+
#include <algorithm>
#include <limits>
@@ -19,10 +22,16 @@ const int kIntMax = std::numeric_limits<int>::max();
} // namespace
-TEST(RandUtilTest, SameMinAndMax) {
+TEST(RandUtilTest, RandInt) {
EXPECT_EQ(base::RandInt(0, 0), 0);
EXPECT_EQ(base::RandInt(kIntMin, kIntMin), kIntMin);
EXPECT_EQ(base::RandInt(kIntMax, kIntMax), kIntMax);
+
+ // Check that the DCHECKS in RandInt() don't fire due to internal overflow.
+ // There was a 50% chance of that happening, so calling it 40 times means
+ // the chances of this passing by accident are tiny (9e-13).
+ for (int i = 0; i < 40; ++i)
+ base::RandInt(kIntMin, kIntMax);
}
TEST(RandUtilTest, RandDouble) {
@@ -61,7 +70,7 @@ TEST(RandUtilTest, RandBytesAsString) {
TEST(RandUtilTest, RandGeneratorForRandomShuffle) {
EXPECT_EQ(base::RandGenerator(1), 0U);
EXPECT_LE(std::numeric_limits<ptrdiff_t>::max(),
- std::numeric_limits<int64>::max());
+ std::numeric_limits<int64_t>::max());
}
TEST(RandUtilTest, RandGeneratorIsUniform) {
@@ -77,16 +86,17 @@ TEST(RandUtilTest, RandGeneratorIsUniform) {
// top half. A bit of calculus care of jar@ shows that the largest
// measurable delta is when the top of the range is 3/4ths of the
// way, so that's what we use in the test.
- const uint64 kTopOfRange = (std::numeric_limits<uint64>::max() / 4ULL) * 3ULL;
- const uint64 kExpectedAverage = kTopOfRange / 2ULL;
- const uint64 kAllowedVariance = kExpectedAverage / 50ULL; // +/- 2%
+ const uint64_t kTopOfRange =
+ (std::numeric_limits<uint64_t>::max() / 4ULL) * 3ULL;
+ const uint64_t kExpectedAverage = kTopOfRange / 2ULL;
+ const uint64_t kAllowedVariance = kExpectedAverage / 50ULL; // +/- 2%
const int kMinAttempts = 1000;
const int kMaxAttempts = 1000000;
double cumulative_average = 0.0;
int count = 0;
while (count < kMaxAttempts) {
- uint64 value = base::RandGenerator(kTopOfRange);
+ uint64_t value = base::RandGenerator(kTopOfRange);
cumulative_average = (count * cumulative_average + value) / (count + 1);
// Don't quit too quickly for things to start converging, or we may have
@@ -107,13 +117,13 @@ TEST(RandUtilTest, RandGeneratorIsUniform) {
TEST(RandUtilTest, RandUint64ProducesBothValuesOfAllBits) {
// This tests to see that our underlying random generator is good
// enough, for some value of good enough.
- uint64 kAllZeros = 0ULL;
- uint64 kAllOnes = ~kAllZeros;
- uint64 found_ones = kAllZeros;
- uint64 found_zeros = kAllOnes;
+ uint64_t kAllZeros = 0ULL;
+ uint64_t kAllOnes = ~kAllZeros;
+ uint64_t found_ones = kAllZeros;
+ uint64_t found_zeros = kAllOnes;
for (size_t i = 0; i < 1000; ++i) {
- uint64 value = base::RandUint64();
+ uint64_t value = base::RandUint64();
found_ones |= value;
found_zeros &= value;
@@ -133,7 +143,7 @@ TEST(RandUtilTest, DISABLED_RandBytesPerf) {
const int kTestIterations = 10;
const size_t kTestBufferSize = 1 * 1024 * 1024;
- scoped_ptr<uint8[]> buffer(new uint8[kTestBufferSize]);
+ scoped_ptr<uint8_t[]> buffer(new uint8_t[kTestBufferSize]);
const base::TimeTicks now = base::TimeTicks::Now();
for (int i = 0; i < kTestIterations; ++i)
base::RandBytes(buffer.get(), kTestBufferSize);
diff --git a/chromium/base/rand_util_win.cc b/chromium/base/rand_util_win.cc
index 8573b6b601b..22fdd4da72c 100644
--- a/chromium/base/rand_util_win.cc
+++ b/chromium/base/rand_util_win.cc
@@ -5,6 +5,8 @@
#include "base/rand_util.h"
#include <windows.h>
+#include <stddef.h>
+#include <stdint.h>
// #define needed to link in RtlGenRandom(), a.k.a. SystemFunction036. See the
// "Community Additions" comment on MSDN here:
@@ -21,8 +23,8 @@
namespace base {
// NOTE: This function must be cryptographically secure. http://crbug.com/140076
-uint64 RandUint64() {
- uint64 number;
+uint64_t RandUint64() {
+ uint64_t number;
RandBytes(&number, sizeof(number));
return number;
}
diff --git a/chromium/base/run_loop.cc b/chromium/base/run_loop.cc
index 2aa4def9570..b8558db4874 100644
--- a/chromium/base/run_loop.cc
+++ b/chromium/base/run_loop.cc
@@ -6,6 +6,7 @@
#include "base/bind.h"
#include "base/tracked_objects.h"
+#include "build/build_config.h"
#if defined(OS_WIN)
#include "base/message_loop/message_pump_dispatcher.h"
diff --git a/chromium/base/run_loop.h b/chromium/base/run_loop.h
index 002410892f6..e23d0730775 100644
--- a/chromium/base/run_loop.h
+++ b/chromium/base/run_loop.h
@@ -7,8 +7,10 @@
#include "base/base_export.h"
#include "base/callback.h"
+#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
+#include "build/build_config.h"
namespace base {
#if defined(OS_ANDROID)
@@ -38,8 +40,8 @@ class BASE_EXPORT RunLoop {
// Run the current MessageLoop. This blocks until Quit is called. Before
// calling Run, be sure to grab an AsWeakPtr or the QuitClosure in order to
- // stop the MessageLoop asynchronously. MessageLoop::Quit and QuitNow will
- // also trigger a return from Run, but those are deprecated.
+ // stop the MessageLoop asynchronously. MessageLoop::QuitWhenIdle and QuitNow
+ // will also trigger a return from Run, but those are deprecated.
void Run();
// Run the current MessageLoop until it doesn't find any tasks or messages in
diff --git a/chromium/base/scoped_clear_errno.h b/chromium/base/scoped_clear_errno.h
index 7b972fc85ac..585f6f768f1 100644
--- a/chromium/base/scoped_clear_errno.h
+++ b/chromium/base/scoped_clear_errno.h
@@ -7,7 +7,7 @@
#include <errno.h>
-#include "base/basictypes.h"
+#include "base/macros.h"
namespace base {
diff --git a/chromium/base/scoped_generic.h b/chromium/base/scoped_generic.h
index f6807e2b58f..d41f19512ce 100644
--- a/chromium/base/scoped_generic.h
+++ b/chromium/base/scoped_generic.h
@@ -10,6 +10,7 @@
#include <algorithm>
#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "base/move.h"
namespace base {
@@ -53,7 +54,7 @@ namespace base {
// typedef ScopedGeneric<int, FooScopedTraits> ScopedFoo;
template<typename T, typename Traits>
class ScopedGeneric {
- MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(ScopedGeneric)
+ DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND(ScopedGeneric)
private:
// This must be first since it's used inline below.
diff --git a/chromium/base/scoped_generic_unittest.cc b/chromium/base/scoped_generic_unittest.cc
index b28e154372e..5a6abfb3c4b 100644
--- a/chromium/base/scoped_generic_unittest.cc
+++ b/chromium/base/scoped_generic_unittest.cc
@@ -2,9 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/scoped_generic.h"
+
+#include <utility>
#include <vector>
-#include "base/scoped_generic.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
@@ -85,10 +87,10 @@ TEST(ScopedGenericTest, ScopedGeneric) {
EXPECT_EQ(kSecond, values_freed[1]);
values_freed.clear();
- // Pass constructor.
+ // Move constructor.
{
ScopedInt a(kFirst, traits);
- ScopedInt b(a.Pass());
+ ScopedInt b(std::move(a));
EXPECT_TRUE(values_freed.empty()); // Nothing should be freed.
ASSERT_EQ(IntTraits::InvalidValue(), a.get());
ASSERT_EQ(kFirst, b.get());
@@ -98,11 +100,11 @@ TEST(ScopedGenericTest, ScopedGeneric) {
ASSERT_EQ(kFirst, values_freed[0]);
values_freed.clear();
- // Pass assign.
+ // Move assign.
{
ScopedInt a(kFirst, traits);
ScopedInt b(kSecond, traits);
- b = a.Pass();
+ b = std::move(a);
ASSERT_EQ(1u, values_freed.size());
EXPECT_EQ(kSecond, values_freed[0]);
ASSERT_EQ(IntTraits::InvalidValue(), a.get());
diff --git a/chromium/base/scoped_native_library.h b/chromium/base/scoped_native_library.h
index c0e93f37212..e58297b27c1 100644
--- a/chromium/base/scoped_native_library.h
+++ b/chromium/base/scoped_native_library.h
@@ -6,6 +6,7 @@
#define BASE_SCOPED_NATIVE_LIBRARY_H_
#include "base/base_export.h"
+#include "base/macros.h"
#include "base/native_library.h"
namespace base {
@@ -31,6 +32,8 @@ class BASE_EXPORT ScopedNativeLibrary {
// Returns true if there's a valid library loaded.
bool is_valid() const { return !!library_; }
+ NativeLibrary get() const { return library_; }
+
void* GetFunctionPointer(const char* function_name) const;
// Takes ownership of the given library handle. Any existing handle will
diff --git a/chromium/base/scoped_native_library_unittest.cc b/chromium/base/scoped_native_library_unittest.cc
index 035faa03f74..204aadb983e 100644
--- a/chromium/base/scoped_native_library_unittest.cc
+++ b/chromium/base/scoped_native_library_unittest.cc
@@ -3,12 +3,14 @@
// found in the LICENSE file.
#include "base/scoped_native_library.h"
+
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
#if defined(OS_WIN)
#include "base/files/file_path.h"
#endif
-#include "testing/gtest/include/gtest/gtest.h"
-
namespace base {
// Tests whether or not a function pointer retrieved via ScopedNativeLibrary
@@ -28,6 +30,8 @@ TEST(ScopedNativeLibrary, Basic) {
FilePath path(GetNativeLibraryName(L"ddraw"));
native_library = LoadNativeLibrary(path, NULL);
ScopedNativeLibrary library(native_library);
+ EXPECT_TRUE(library.is_valid());
+ EXPECT_EQ(native_library, library.get());
FARPROC test_function =
reinterpret_cast<FARPROC>(library.GetFunctionPointer(kFunctionName));
EXPECT_EQ(0, IsBadCodePtr(test_function));
diff --git a/chromium/base/scoped_observer.h b/chromium/base/scoped_observer.h
index 422701bc219..13d7ca8bb1e 100644
--- a/chromium/base/scoped_observer.h
+++ b/chromium/base/scoped_observer.h
@@ -5,11 +5,14 @@
#ifndef BASE_SCOPED_OBSERVER_H_
#define BASE_SCOPED_OBSERVER_H_
+#include <stddef.h>
+
#include <algorithm>
#include <vector>
-#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/macros.h"
+#include "base/stl_util.h"
// ScopedObserver is used to keep track of the set of sources an object has
// attached itself to as an observer. When ScopedObserver is destroyed it
@@ -44,8 +47,7 @@ class ScopedObserver {
}
bool IsObserving(Source* source) const {
- return std::find(sources_.begin(), sources_.end(), source) !=
- sources_.end();
+ return ContainsValue(sources_, source);
}
bool IsObservingSources() const { return !sources_.empty(); }
diff --git a/chromium/base/security_unittest.cc b/chromium/base/security_unittest.cc
index a9c73f7c592..eebe6e0f994 100644
--- a/chromium/base/security_unittest.cc
+++ b/chromium/base/security_unittest.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include <fcntl.h>
+#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -85,7 +86,7 @@ void OverflowTestsSoftExpectTrue(bool overflow_detected) {
}
}
-#if defined(OS_IOS) || defined(OS_WIN) || defined(THREAD_SANITIZER) || defined(OS_MACOSX)
+#if defined(OS_IOS) || defined(OS_WIN) || defined(OS_MACOSX)
#define MAYBE_NewOverflow DISABLED_NewOverflow
#else
#define MAYBE_NewOverflow NewOverflow
diff --git a/chromium/base/sequence_checker_impl.h b/chromium/base/sequence_checker_impl.h
index 741aafee645..e3c5fed508c 100644
--- a/chromium/base/sequence_checker_impl.h
+++ b/chromium/base/sequence_checker_impl.h
@@ -6,7 +6,7 @@
#define BASE_SEQUENCE_CHECKER_IMPL_H_
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/synchronization/lock.h"
#include "base/threading/sequenced_worker_pool.h"
#include "base/threading/thread_checker_impl.h"
diff --git a/chromium/base/sequence_checker_unittest.cc b/chromium/base/sequence_checker_unittest.cc
index 0aa0f9cdbb7..e261b04d721 100644
--- a/chromium/base/sequence_checker_unittest.cc
+++ b/chromium/base/sequence_checker_unittest.cc
@@ -2,14 +2,19 @@
// 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/sequence_checker.h"
+
+#include <stddef.h>
+
+#include <utility>
+
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/location.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.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"
@@ -63,7 +68,6 @@ class SequenceCheckerTest : public testing::Test {
void TearDown() override {
other_thread_.Stop();
- pool()->Shutdown();
}
protected:
@@ -130,7 +134,7 @@ TEST_F(SequenceCheckerTest, DestructorAllowedOnDifferentThread) {
new SequenceCheckedObject);
// Verify the destructor doesn't assert when called on a different thread.
- PostDeleteToOtherThread(sequence_checked_object.Pass());
+ PostDeleteToOtherThread(std::move(sequence_checked_object));
other_thread()->Stop();
}
@@ -157,7 +161,7 @@ TEST_F(SequenceCheckerTest, SameSequenceTokenValid) {
PostDoStuffToWorkerPool(sequence_checked_object.get(), "A");
pool()->FlushForTesting();
- PostDeleteToOtherThread(sequence_checked_object.Pass());
+ PostDeleteToOtherThread(std::move(sequence_checked_object));
other_thread()->Stop();
}
@@ -175,7 +179,7 @@ TEST_F(SequenceCheckerTest, DetachSequenceTokenValid) {
PostDoStuffToWorkerPool(sequence_checked_object.get(), "B");
pool()->FlushForTesting();
- PostDeleteToOtherThread(sequence_checked_object.Pass());
+ PostDeleteToOtherThread(std::move(sequence_checked_object));
other_thread()->Stop();
}
@@ -245,7 +249,7 @@ void SequenceCheckerTest::DifferentSequenceTokensDeathTest() {
PostDoStuffToWorkerPool(sequence_checked_object.get(), "B");
pool()->FlushForTesting();
- PostDeleteToOtherThread(sequence_checked_object.Pass());
+ PostDeleteToOtherThread(std::move(sequence_checked_object));
other_thread()->Stop();
}
@@ -306,7 +310,6 @@ void SequenceCheckerTest::TwoDifferentWorkerPoolsDeathTest() {
base::Bind(&SequenceCheckedObject::DoStuff,
base::Unretained(sequence_checked_object.get())));
second_pool_owner.pool()->FlushForTesting();
- second_pool_owner.pool()->Shutdown();
}
#if ENABLE_SEQUENCE_CHECKER
diff --git a/chromium/base/sequenced_task_runner_helpers.h b/chromium/base/sequenced_task_runner_helpers.h
index da519bf9189..7980b46b6ce 100644
--- a/chromium/base/sequenced_task_runner_helpers.h
+++ b/chromium/base/sequenced_task_runner_helpers.h
@@ -5,8 +5,8 @@
#ifndef BASE_SEQUENCED_TASK_RUNNER_HELPERS_H_
#define BASE_SEQUENCED_TASK_RUNNER_HELPERS_H_
-#include "base/basictypes.h"
#include "base/debug/alias.h"
+#include "base/macros.h"
// TODO(akalin): Investigate whether it's possible to just have
// SequencedTaskRunner use these helpers (instead of MessageLoop).
diff --git a/chromium/base/sha1.h b/chromium/base/sha1.h
index 998cccba8d4..902e3013318 100644
--- a/chromium/base/sha1.h
+++ b/chromium/base/sha1.h
@@ -5,6 +5,8 @@
#ifndef BASE_SHA1_H_
#define BASE_SHA1_H_
+#include <stddef.h>
+
#include <string>
#include "base/base_export.h"
diff --git a/chromium/base/sha1_portable.cc b/chromium/base/sha1_portable.cc
index 0b9df830797..dd2ab6fe177 100644
--- a/chromium/base/sha1_portable.cc
+++ b/chromium/base/sha1_portable.cc
@@ -4,9 +4,10 @@
#include "base/sha1.h"
+#include <stddef.h>
+#include <stdint.h>
#include <string.h>
-#include "base/basictypes.h"
namespace base {
@@ -50,20 +51,20 @@ class SecureHashAlgorithm {
void Pad();
void Process();
- uint32 A, B, C, D, E;
+ uint32_t A, B, C, D, E;
- uint32 H[5];
+ uint32_t H[5];
union {
- uint32 W[80];
- uint8 M[64];
+ uint32_t W[80];
+ uint8_t M[64];
};
- uint32 cursor;
- uint64 l;
+ uint32_t cursor;
+ uint64_t l;
};
-static inline uint32 f(uint32 t, uint32 B, uint32 C, uint32 D) {
+static inline uint32_t f(uint32_t t, uint32_t B, uint32_t C, uint32_t D) {
if (t < 20) {
return (B & C) | ((~B) & D);
} else if (t < 40) {
@@ -75,11 +76,11 @@ static inline uint32 f(uint32 t, uint32 B, uint32 C, uint32 D) {
}
}
-static inline uint32 S(uint32 n, uint32 X) {
+static inline uint32_t S(uint32_t n, uint32_t X) {
return (X << n) | (X >> (32-n));
}
-static inline uint32 K(uint32 t) {
+static inline uint32_t K(uint32_t t) {
if (t < 20) {
return 0x5a827999;
} else if (t < 40) {
@@ -91,7 +92,7 @@ static inline uint32 K(uint32 t) {
}
}
-static inline void swapends(uint32* t) {
+static inline void swapends(uint32_t* t) {
*t = (*t >> 24) | ((*t >> 8) & 0xff00) | ((*t & 0xff00) << 8) | (*t << 24);
}
@@ -121,7 +122,7 @@ void SecureHashAlgorithm::Final() {
}
void SecureHashAlgorithm::Update(const void* data, size_t nbytes) {
- const uint8* d = reinterpret_cast<const uint8*>(data);
+ const uint8_t* d = reinterpret_cast<const uint8_t*>(data);
while (nbytes--) {
M[cursor++] = *d++;
if (cursor >= 64)
@@ -155,7 +156,7 @@ void SecureHashAlgorithm::Pad() {
}
void SecureHashAlgorithm::Process() {
- uint32 t;
+ uint32_t t;
// Each a...e corresponds to a section in the FIPS 180-3 algorithm.
@@ -179,7 +180,7 @@ void SecureHashAlgorithm::Process() {
// d.
for (t = 0; t < 80; ++t) {
- uint32 TEMP = S(5, A) + f(t, B, C, D) + E + W[t] + K(t);
+ uint32_t TEMP = S(5, A) + f(t, B, C, D) + E + W[t] + K(t);
E = D;
D = C;
C = S(30, B);
diff --git a/chromium/base/sha1_unittest.cc b/chromium/base/sha1_unittest.cc
index b29fe4662ae..ea9cf634a58 100644
--- a/chromium/base/sha1_unittest.cc
+++ b/chromium/base/sha1_unittest.cc
@@ -4,9 +4,10 @@
#include "base/sha1.h"
+#include <stddef.h>
+
#include <string>
-#include "base/basictypes.h"
#include "testing/gtest/include/gtest/gtest.h"
TEST(SHA1Test, Test1) {
diff --git a/chromium/base/stl_util.h b/chromium/base/stl_util.h
index e937d2f3ed9..12e226a9db9 100644
--- a/chromium/base/stl_util.h
+++ b/chromium/base/stl_util.h
@@ -98,19 +98,6 @@ 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.
-template<typename T>
-inline T* vector_as_array(std::vector<T>* v) {
- return v->empty() ? NULL : &*v->begin();
-}
-
-template<typename T>
-inline const T* vector_as_array(const std::vector<T>* v) {
- return v->empty() ? NULL : &*v->begin();
-}
-
// Return a mutable char* pointing to a string's internal buffer,
// which may not be null-terminated. Writing through this pointer will
// modify the string.
diff --git a/chromium/base/strings/latin1_string_conversions.h b/chromium/base/strings/latin1_string_conversions.h
index 387cb65a528..42113ef6120 100644
--- a/chromium/base/strings/latin1_string_conversions.h
+++ b/chromium/base/strings/latin1_string_conversions.h
@@ -5,6 +5,8 @@
#ifndef BASE_STRINGS_LATIN1_STRING_CONVERSIONS_H_
#define BASE_STRINGS_LATIN1_STRING_CONVERSIONS_H_
+#include <stddef.h>
+
#include <string>
#include "base/base_export.h"
diff --git a/chromium/base/strings/safe_sprintf.cc b/chromium/base/strings/safe_sprintf.cc
index b1fcf45b24f..a51c778271e 100644
--- a/chromium/base/strings/safe_sprintf.cc
+++ b/chromium/base/strings/safe_sprintf.cc
@@ -4,8 +4,14 @@
#include "base/strings/safe_sprintf.h"
+#include <errno.h>
+#include <string.h>
+
#include <limits>
+#include "base/macros.h"
+#include "build/build_config.h"
+
#if !defined(NDEBUG)
// In debug builds, we use RAW_CHECK() to print useful error messages, if
// SafeSPrintf() is called with broken arguments.
@@ -69,7 +75,7 @@ const char kDownCaseHexDigits[] = "0123456789abcdef";
#if defined(NDEBUG)
// We would like to define kSSizeMax as std::numeric_limits<ssize_t>::max(),
// but C++ doesn't allow us to do that for constants. Instead, we have to
-// use careful casting and shifting. We later use a COMPILE_ASSERT to
+// use careful casting and shifting. We later use a static_assert to
// verify that this worked correctly.
namespace {
const size_t kSSizeMax = kSSizeMaxConst;
@@ -107,18 +113,13 @@ class Buffer {
: buffer_(buffer),
size_(size - 1), // Account for trailing NUL byte
count_(0) {
-// The following assertion does not build on Mac and Android. This is because
-// static_assert only works with compile-time constants, but mac uses
-// libstdc++4.2 and android uses stlport, which both don't mark
-// numeric_limits::max() as constexp. Likewise, MSVS2013's standard library
-// also doesn't mark max() as constexpr yet. cl.exe supports static_cast but
-// doesn't really implement constexpr yet so it doesn't complain, but clang
-// does.
-#if __cplusplus >= 201103 && !defined(OS_ANDROID) && !defined(OS_MACOSX) && \
- !defined(OS_IOS) && !(defined(__clang__) && defined(OS_WIN))
- COMPILE_ASSERT(kSSizeMaxConst == \
- static_cast<size_t>(std::numeric_limits<ssize_t>::max()),
- kSSizeMax_is_the_max_value_of_an_ssize_t);
+// MSVS2013's standard library doesn't mark max() as constexpr yet. cl.exe
+// supports static_cast but doesn't really implement constexpr yet so it doesn't
+// complain, but clang does.
+#if __cplusplus >= 201103 && !(defined(__clang__) && defined(OS_WIN))
+ static_assert(kSSizeMaxConst ==
+ static_cast<size_t>(std::numeric_limits<ssize_t>::max()),
+ "kSSizeMaxConst should be the max value of an ssize_t");
#endif
DEBUG_CHECK(size > 0);
DEBUG_CHECK(size <= kSSizeMax);
diff --git a/chromium/base/strings/safe_sprintf.h b/chromium/base/strings/safe_sprintf.h
index 2d173202d3e..65524a50c3a 100644
--- a/chromium/base/strings/safe_sprintf.h
+++ b/chromium/base/strings/safe_sprintf.h
@@ -17,7 +17,6 @@
#endif
#include "base/base_export.h"
-#include "base/basictypes.h"
namespace base {
namespace strings {
diff --git a/chromium/base/strings/safe_sprintf_unittest.cc b/chromium/base/strings/safe_sprintf_unittest.cc
index ff05c6e2990..931ace8b124 100644
--- a/chromium/base/strings/safe_sprintf_unittest.cc
+++ b/chromium/base/strings/safe_sprintf_unittest.cc
@@ -4,13 +4,17 @@
#include "base/strings/safe_sprintf.h"
+#include <stddef.h>
+#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <limits>
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
// Death tests on Android are currently very flaky. No need to add more flaky
diff --git a/chromium/base/strings/string16.h b/chromium/base/strings/string16.h
index 1a01a9613e7..e47669c1b56 100644
--- a/chromium/base/strings/string16.h
+++ b/chromium/base/strings/string16.h
@@ -26,11 +26,13 @@
// libc functions with custom, 2-byte-char compatible routines. It is capable
// of carrying UTF-16-encoded data.
+#include <stddef.h>
+#include <stdint.h>
#include <stdio.h>
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "build/build_config.h"
#if defined(WCHAR_T_IS_UTF16)
@@ -46,7 +48,7 @@ typedef std::char_traits<wchar_t> string16_char_traits;
namespace base {
-typedef uint16 char16;
+typedef uint16_t char16;
// char16 versions of the functions required by string16_char_traits; these
// are based on the wide character functions of similar names ("w" or "wcs"
@@ -64,7 +66,8 @@ struct string16_char_traits {
// int_type needs to be able to hold each possible value of char_type, and in
// addition, the distinct value of eof().
- COMPILE_ASSERT(sizeof(int_type) > sizeof(char_type), unexpected_type_width);
+ static_assert(sizeof(int_type) > sizeof(char_type),
+ "int must be larger than 16 bits wide");
typedef std::streamoff off_type;
typedef mbstate_t state_type;
diff --git a/chromium/base/strings/string_number_conversions.cc b/chromium/base/strings/string_number_conversions.cc
index 0f4f3813321..07248501e31 100644
--- a/chromium/base/strings/string_number_conversions.cc
+++ b/chromium/base/strings/string_number_conversions.cc
@@ -63,9 +63,9 @@ template<typename CHAR, int BASE, bool BASE_LTE_10> class BaseCharToDigit {
// Faster specialization for bases <= 10
template<typename CHAR, int BASE> class BaseCharToDigit<CHAR, BASE, true> {
public:
- static bool Convert(CHAR c, uint8* digit) {
+ static bool Convert(CHAR c, uint8_t* digit) {
if (c >= '0' && c < '0' + BASE) {
- *digit = static_cast<uint8>(c - '0');
+ *digit = static_cast<uint8_t>(c - '0');
return true;
}
return false;
@@ -75,7 +75,7 @@ template<typename CHAR, int BASE> class BaseCharToDigit<CHAR, BASE, true> {
// Specialization for bases where 10 < base <= 36
template<typename CHAR, int BASE> class BaseCharToDigit<CHAR, BASE, false> {
public:
- static bool Convert(CHAR c, uint8* digit) {
+ static bool Convert(CHAR c, uint8_t* digit) {
if (c >= '0' && c <= '9') {
*digit = c - '0';
} else if (c >= 'a' && c < 'a' + BASE - 10) {
@@ -89,7 +89,8 @@ template<typename CHAR, int BASE> class BaseCharToDigit<CHAR, BASE, false> {
}
};
-template<int BASE, typename CHAR> bool CharToDigit(CHAR c, uint8* digit) {
+template <int BASE, typename CHAR>
+bool CharToDigit(CHAR c, uint8_t* digit) {
return BaseCharToDigit<CHAR, BASE, BASE <= 10>::Convert(c, digit);
}
@@ -186,7 +187,7 @@ class IteratorRangeToNumber {
}
for (const_iterator current = begin; current != end; ++current) {
- uint8 new_digit = 0;
+ uint8_t new_digit = 0;
if (!CharToDigit<traits::kBase>(*current, &new_digit)) {
return false;
@@ -207,7 +208,7 @@ class IteratorRangeToNumber {
class Positive : public Base<Positive> {
public:
- static bool CheckBounds(value_type* output, uint8 new_digit) {
+ static bool CheckBounds(value_type* output, uint8_t new_digit) {
if (*output > static_cast<value_type>(traits::max() / traits::kBase) ||
(*output == static_cast<value_type>(traits::max() / traits::kBase) &&
new_digit > traits::max() % traits::kBase)) {
@@ -216,14 +217,14 @@ class IteratorRangeToNumber {
}
return true;
}
- static void Increment(uint8 increment, value_type* output) {
+ static void Increment(uint8_t increment, value_type* output) {
*output += increment;
}
};
class Negative : public Base<Negative> {
public:
- static bool CheckBounds(value_type* output, uint8 new_digit) {
+ static bool CheckBounds(value_type* output, uint8_t new_digit) {
if (*output < traits::min() / traits::kBase ||
(*output == traits::min() / traits::kBase &&
new_digit > 0 - traits::min() % traits::kBase)) {
@@ -232,7 +233,7 @@ class IteratorRangeToNumber {
}
return true;
}
- static void Increment(uint8 increment, value_type* output) {
+ static void Increment(uint8_t increment, value_type* output) {
*output -= increment;
}
};
@@ -257,20 +258,17 @@ class BaseHexIteratorRangeToIntTraits
: public BaseIteratorRangeToNumberTraits<ITERATOR, int, 16> {
};
-template<typename ITERATOR>
+template <typename ITERATOR>
class BaseHexIteratorRangeToUIntTraits
- : public BaseIteratorRangeToNumberTraits<ITERATOR, uint32, 16> {
-};
+ : public BaseIteratorRangeToNumberTraits<ITERATOR, uint32_t, 16> {};
-template<typename ITERATOR>
+template <typename ITERATOR>
class BaseHexIteratorRangeToInt64Traits
- : public BaseIteratorRangeToNumberTraits<ITERATOR, int64, 16> {
-};
+ : public BaseIteratorRangeToNumberTraits<ITERATOR, int64_t, 16> {};
-template<typename ITERATOR>
+template <typename ITERATOR>
class BaseHexIteratorRangeToUInt64Traits
- : public BaseIteratorRangeToNumberTraits<ITERATOR, uint64, 16> {
-};
+ : public BaseIteratorRangeToNumberTraits<ITERATOR, uint64_t, 16> {};
typedef BaseHexIteratorRangeToIntTraits<StringPiece::const_iterator>
HexIteratorRangeToIntTraits;
@@ -284,15 +282,15 @@ typedef BaseHexIteratorRangeToInt64Traits<StringPiece::const_iterator>
typedef BaseHexIteratorRangeToUInt64Traits<StringPiece::const_iterator>
HexIteratorRangeToUInt64Traits;
-template<typename STR>
-bool HexStringToBytesT(const STR& input, std::vector<uint8>* output) {
+template <typename STR>
+bool HexStringToBytesT(const STR& input, std::vector<uint8_t>* output) {
DCHECK_EQ(output->size(), 0u);
size_t count = input.size();
if (count == 0 || (count % 2) != 0)
return false;
for (uintptr_t i = 0; i < count / 2; ++i) {
- uint8 msb = 0; // most significant 4 bits
- uint8 lsb = 0; // least significant 4 bits
+ uint8_t msb = 0; // most significant 4 bits
+ uint8_t lsb = 0; // least significant 4 bits
if (!CharToDigit<16>(input[i * 2], &msb) ||
!CharToDigit<16>(input[i * 2 + 1], &lsb))
return false;
@@ -345,20 +343,20 @@ string16 UintToString16(unsigned int value) {
return IntToStringT<string16, unsigned int>::IntToString(value);
}
-std::string Int64ToString(int64 value) {
- return IntToStringT<std::string, int64>::IntToString(value);
+std::string Int64ToString(int64_t value) {
+ return IntToStringT<std::string, int64_t>::IntToString(value);
}
-string16 Int64ToString16(int64 value) {
- return IntToStringT<string16, int64>::IntToString(value);
+string16 Int64ToString16(int64_t value) {
+ return IntToStringT<string16, int64_t>::IntToString(value);
}
-std::string Uint64ToString(uint64 value) {
- return IntToStringT<std::string, uint64>::IntToString(value);
+std::string Uint64ToString(uint64_t value) {
+ return IntToStringT<std::string, uint64_t>::IntToString(value);
}
-string16 Uint64ToString16(uint64 value) {
- return IntToStringT<string16, uint64>::IntToString(value);
+string16 Uint64ToString16(uint64_t value) {
+ return IntToStringT<string16, uint64_t>::IntToString(value);
}
std::string SizeTToString(size_t value) {
@@ -392,19 +390,19 @@ bool StringToUint(const StringPiece16& input, unsigned* output) {
return String16ToIntImpl(input, output);
}
-bool StringToInt64(const StringPiece& input, int64* output) {
+bool StringToInt64(const StringPiece& input, int64_t* output) {
return StringToIntImpl(input, output);
}
-bool StringToInt64(const StringPiece16& input, int64* output) {
+bool StringToInt64(const StringPiece16& input, int64_t* output) {
return String16ToIntImpl(input, output);
}
-bool StringToUint64(const StringPiece& input, uint64* output) {
+bool StringToUint64(const StringPiece& input, uint64_t* output) {
return StringToIntImpl(input, output);
}
-bool StringToUint64(const StringPiece16& input, uint64* output) {
+bool StringToUint64(const StringPiece16& input, uint64_t* output) {
return String16ToIntImpl(input, output);
}
@@ -465,22 +463,22 @@ bool HexStringToInt(const StringPiece& input, int* output) {
input.begin(), input.end(), output);
}
-bool HexStringToUInt(const StringPiece& input, uint32* output) {
+bool HexStringToUInt(const StringPiece& input, uint32_t* output) {
return IteratorRangeToNumber<HexIteratorRangeToUIntTraits>::Invoke(
input.begin(), input.end(), output);
}
-bool HexStringToInt64(const StringPiece& input, int64* output) {
+bool HexStringToInt64(const StringPiece& input, int64_t* output) {
return IteratorRangeToNumber<HexIteratorRangeToInt64Traits>::Invoke(
input.begin(), input.end(), output);
}
-bool HexStringToUInt64(const StringPiece& input, uint64* output) {
+bool HexStringToUInt64(const StringPiece& input, uint64_t* output) {
return IteratorRangeToNumber<HexIteratorRangeToUInt64Traits>::Invoke(
input.begin(), input.end(), output);
}
-bool HexStringToBytes(const std::string& input, std::vector<uint8>* output) {
+bool HexStringToBytes(const std::string& input, std::vector<uint8_t>* output) {
return HexStringToBytesT(input, output);
}
diff --git a/chromium/base/strings/string_number_conversions.h b/chromium/base/strings/string_number_conversions.h
index cf1c3b467dd..1265f0dcba3 100644
--- a/chromium/base/strings/string_number_conversions.h
+++ b/chromium/base/strings/string_number_conversions.h
@@ -5,11 +5,13 @@
#ifndef BASE_STRINGS_STRING_NUMBER_CONVERSIONS_H_
#define BASE_STRINGS_STRING_NUMBER_CONVERSIONS_H_
+#include <stddef.h>
+#include <stdint.h>
+
#include <string>
#include <vector>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/strings/string16.h"
#include "base/strings/string_piece.h"
@@ -35,11 +37,11 @@ BASE_EXPORT string16 IntToString16(int value);
BASE_EXPORT std::string UintToString(unsigned value);
BASE_EXPORT string16 UintToString16(unsigned value);
-BASE_EXPORT std::string Int64ToString(int64 value);
-BASE_EXPORT string16 Int64ToString16(int64 value);
+BASE_EXPORT std::string Int64ToString(int64_t value);
+BASE_EXPORT string16 Int64ToString16(int64_t value);
-BASE_EXPORT std::string Uint64ToString(uint64 value);
-BASE_EXPORT string16 Uint64ToString16(uint64 value);
+BASE_EXPORT std::string Uint64ToString(uint64_t value);
+BASE_EXPORT string16 Uint64ToString16(uint64_t value);
BASE_EXPORT std::string SizeTToString(size_t value);
BASE_EXPORT string16 SizeTToString16(size_t value);
@@ -72,11 +74,11 @@ BASE_EXPORT bool StringToInt(const StringPiece16& input, int* output);
BASE_EXPORT bool StringToUint(const StringPiece& input, unsigned* output);
BASE_EXPORT bool StringToUint(const StringPiece16& input, unsigned* output);
-BASE_EXPORT bool StringToInt64(const StringPiece& input, int64* output);
-BASE_EXPORT bool StringToInt64(const StringPiece16& input, int64* output);
+BASE_EXPORT bool StringToInt64(const StringPiece& input, int64_t* output);
+BASE_EXPORT bool StringToInt64(const StringPiece16& input, int64_t* output);
-BASE_EXPORT bool StringToUint64(const StringPiece& input, uint64* output);
-BASE_EXPORT bool StringToUint64(const StringPiece16& input, uint64* output);
+BASE_EXPORT bool StringToUint64(const StringPiece& input, uint64_t* output);
+BASE_EXPORT bool StringToUint64(const StringPiece16& input, uint64_t* output);
BASE_EXPORT bool StringToSizeT(const StringPiece& input, size_t* output);
BASE_EXPORT bool StringToSizeT(const StringPiece16& input, size_t* output);
@@ -110,25 +112,25 @@ BASE_EXPORT bool HexStringToInt(const StringPiece& input, int* output);
// Will only successful parse hex values that will fit into |output|, i.e.
// 0x00000000 < |input| < 0xFFFFFFFF.
// The string is not required to start with 0x.
-BASE_EXPORT bool HexStringToUInt(const StringPiece& input, uint32* output);
+BASE_EXPORT bool HexStringToUInt(const StringPiece& input, uint32_t* output);
// Best effort conversion, see StringToInt above for restrictions.
// Will only successful parse hex values that will fit into |output|, i.e.
// -0x8000000000000000 < |input| < 0x7FFFFFFFFFFFFFFF.
-BASE_EXPORT bool HexStringToInt64(const StringPiece& input, int64* output);
+BASE_EXPORT bool HexStringToInt64(const StringPiece& input, int64_t* output);
// Best effort conversion, see StringToInt above for restrictions.
// Will only successful parse hex values that will fit into |output|, i.e.
// 0x0000000000000000 < |input| < 0xFFFFFFFFFFFFFFFF.
// The string is not required to start with 0x.
-BASE_EXPORT bool HexStringToUInt64(const StringPiece& input, uint64* output);
+BASE_EXPORT bool HexStringToUInt64(const StringPiece& input, uint64_t* output);
// Similar to the previous functions, except that output is a vector of bytes.
// |*output| will contain as many bytes as were successfully parsed prior to the
// error. There is no overflow, but input.size() must be evenly divisible by 2.
// Leading 0x or +/- are not allowed.
BASE_EXPORT bool HexStringToBytes(const std::string& input,
- std::vector<uint8>* output);
+ std::vector<uint8_t>* output);
} // namespace base
diff --git a/chromium/base/strings/string_number_conversions_unittest.cc b/chromium/base/strings/string_number_conversions_unittest.cc
index 0bc72f17ca1..907227ea2d7 100644
--- a/chromium/base/strings/string_number_conversions_unittest.cc
+++ b/chromium/base/strings/string_number_conversions_unittest.cc
@@ -5,6 +5,8 @@
#include "base/strings/string_number_conversions.h"
#include <errno.h>
+#include <limits.h>
+#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
@@ -12,6 +14,7 @@
#include <limits>
#include "base/format_macros.h"
+#include "base/macros.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -36,15 +39,15 @@ TEST(StringNumberConversionsTest, IntToString) {
{ std::numeric_limits<int>::max(), "2147483647", "2147483647" },
{ std::numeric_limits<int>::min(), "-2147483648", "2147483648" },
};
- static const IntToStringTest<int64> int64_tests[] = {
- { 0, "0", "0" },
- { -1, "-1", "18446744073709551615" },
- { std::numeric_limits<int64>::max(),
- "9223372036854775807",
- "9223372036854775807", },
- { std::numeric_limits<int64>::min(),
- "-9223372036854775808",
- "9223372036854775808" },
+ static const IntToStringTest<int64_t> int64_tests[] = {
+ {0, "0", "0"},
+ {-1, "-1", "18446744073709551615"},
+ {
+ std::numeric_limits<int64_t>::max(), "9223372036854775807",
+ "9223372036854775807",
+ },
+ {std::numeric_limits<int64_t>::min(), "-9223372036854775808",
+ "9223372036854775808"},
};
for (size_t i = 0; i < arraysize(int_tests); ++i) {
@@ -55,7 +58,7 @@ TEST(StringNumberConversionsTest, IntToString) {
EXPECT_EQ(UintToString16(test->num), UTF8ToUTF16(test->uexpected));
}
for (size_t i = 0; i < arraysize(int64_tests); ++i) {
- const IntToStringTest<int64>* test = &int64_tests[i];
+ const IntToStringTest<int64_t>* test = &int64_tests[i];
EXPECT_EQ(Int64ToString(test->num), test->sexpected);
EXPECT_EQ(Int64ToString16(test->num), UTF8ToUTF16(test->sexpected));
EXPECT_EQ(Uint64ToString(test->num), test->uexpected);
@@ -65,13 +68,13 @@ TEST(StringNumberConversionsTest, IntToString) {
TEST(StringNumberConversionsTest, Uint64ToString) {
static const struct {
- uint64 input;
+ uint64_t input;
std::string output;
} cases[] = {
- {0, "0"},
- {42, "42"},
- {INT_MAX, "2147483647"},
- {kuint64max, "18446744073709551615"},
+ {0, "0"},
+ {42, "42"},
+ {INT_MAX, "2147483647"},
+ {std::numeric_limits<uint64_t>::max(), "18446744073709551615"},
};
for (size_t i = 0; i < arraysize(cases); ++i)
@@ -231,44 +234,44 @@ TEST(StringNumberConversionsTest, StringToUint) {
TEST(StringNumberConversionsTest, StringToInt64) {
static const struct {
std::string input;
- int64 output;
+ int64_t output;
bool success;
} cases[] = {
- {"0", 0, true},
- {"42", 42, true},
- {"-2147483648", INT_MIN, true},
- {"2147483647", INT_MAX, true},
- {"-2147483649", INT64_C(-2147483649), true},
- {"-99999999999", INT64_C(-99999999999), true},
- {"2147483648", INT64_C(2147483648), true},
- {"99999999999", INT64_C(99999999999), true},
- {"9223372036854775807", kint64max, true},
- {"-9223372036854775808", kint64min, true},
- {"09", 9, true},
- {"-09", -9, true},
- {"", 0, false},
- {" 42", 42, false},
- {"42 ", 42, false},
- {"0x42", 0, false},
- {"\t\n\v\f\r 42", 42, false},
- {"blah42", 0, false},
- {"42blah", 42, false},
- {"blah42blah", 0, false},
- {"-273.15", -273, false},
- {"+98.6", 98, false},
- {"--123", 0, false},
- {"++123", 0, false},
- {"-+123", 0, false},
- {"+-123", 0, false},
- {"-", 0, false},
- {"-9223372036854775809", kint64min, false},
- {"-99999999999999999999", kint64min, false},
- {"9223372036854775808", kint64max, false},
- {"99999999999999999999", kint64max, false},
+ {"0", 0, true},
+ {"42", 42, true},
+ {"-2147483648", INT_MIN, true},
+ {"2147483647", INT_MAX, true},
+ {"-2147483649", INT64_C(-2147483649), true},
+ {"-99999999999", INT64_C(-99999999999), true},
+ {"2147483648", INT64_C(2147483648), true},
+ {"99999999999", INT64_C(99999999999), true},
+ {"9223372036854775807", std::numeric_limits<int64_t>::max(), true},
+ {"-9223372036854775808", std::numeric_limits<int64_t>::min(), true},
+ {"09", 9, true},
+ {"-09", -9, true},
+ {"", 0, false},
+ {" 42", 42, false},
+ {"42 ", 42, false},
+ {"0x42", 0, false},
+ {"\t\n\v\f\r 42", 42, false},
+ {"blah42", 0, false},
+ {"42blah", 42, false},
+ {"blah42blah", 0, false},
+ {"-273.15", -273, false},
+ {"+98.6", 98, false},
+ {"--123", 0, false},
+ {"++123", 0, false},
+ {"-+123", 0, false},
+ {"+-123", 0, false},
+ {"-", 0, false},
+ {"-9223372036854775809", std::numeric_limits<int64_t>::min(), false},
+ {"-99999999999999999999", std::numeric_limits<int64_t>::min(), false},
+ {"9223372036854775808", std::numeric_limits<int64_t>::max(), false},
+ {"99999999999999999999", std::numeric_limits<int64_t>::max(), false},
};
for (size_t i = 0; i < arraysize(cases); ++i) {
- int64 output = 0;
+ int64_t output = 0;
EXPECT_EQ(cases[i].success, StringToInt64(cases[i].input, &output));
EXPECT_EQ(cases[i].output, output);
@@ -283,7 +286,7 @@ TEST(StringNumberConversionsTest, StringToInt64) {
// interpreted as junk after the number.
const char input[] = "6\06";
std::string input_string(input, arraysize(input) - 1);
- int64 output;
+ int64_t output;
EXPECT_FALSE(StringToInt64(input_string, &output));
EXPECT_EQ(6, output);
@@ -296,46 +299,46 @@ TEST(StringNumberConversionsTest, StringToInt64) {
TEST(StringNumberConversionsTest, StringToUint64) {
static const struct {
std::string input;
- uint64 output;
+ uint64_t output;
bool success;
} cases[] = {
- {"0", 0, true},
- {"42", 42, true},
- {"-2147483648", 0, false},
- {"2147483647", INT_MAX, true},
- {"-2147483649", 0, false},
- {"-99999999999", 0, false},
- {"2147483648", UINT64_C(2147483648), true},
- {"99999999999", UINT64_C(99999999999), true},
- {"9223372036854775807", kint64max, true},
- {"-9223372036854775808", 0, false},
- {"09", 9, true},
- {"-09", 0, false},
- {"", 0, false},
- {" 42", 42, false},
- {"42 ", 42, false},
- {"0x42", 0, false},
- {"\t\n\v\f\r 42", 42, false},
- {"blah42", 0, false},
- {"42blah", 42, false},
- {"blah42blah", 0, false},
- {"-273.15", 0, false},
- {"+98.6", 98, false},
- {"--123", 0, false},
- {"++123", 0, false},
- {"-+123", 0, false},
- {"+-123", 0, false},
- {"-", 0, false},
- {"-9223372036854775809", 0, false},
- {"-99999999999999999999", 0, false},
- {"9223372036854775808", UINT64_C(9223372036854775808), true},
- {"99999999999999999999", kuint64max, false},
- {"18446744073709551615", kuint64max, true},
- {"18446744073709551616", kuint64max, false},
+ {"0", 0, true},
+ {"42", 42, true},
+ {"-2147483648", 0, false},
+ {"2147483647", INT_MAX, true},
+ {"-2147483649", 0, false},
+ {"-99999999999", 0, false},
+ {"2147483648", UINT64_C(2147483648), true},
+ {"99999999999", UINT64_C(99999999999), true},
+ {"9223372036854775807", std::numeric_limits<int64_t>::max(), true},
+ {"-9223372036854775808", 0, false},
+ {"09", 9, true},
+ {"-09", 0, false},
+ {"", 0, false},
+ {" 42", 42, false},
+ {"42 ", 42, false},
+ {"0x42", 0, false},
+ {"\t\n\v\f\r 42", 42, false},
+ {"blah42", 0, false},
+ {"42blah", 42, false},
+ {"blah42blah", 0, false},
+ {"-273.15", 0, false},
+ {"+98.6", 98, false},
+ {"--123", 0, false},
+ {"++123", 0, false},
+ {"-+123", 0, false},
+ {"+-123", 0, false},
+ {"-", 0, false},
+ {"-9223372036854775809", 0, false},
+ {"-99999999999999999999", 0, false},
+ {"9223372036854775808", UINT64_C(9223372036854775808), true},
+ {"99999999999999999999", std::numeric_limits<uint64_t>::max(), false},
+ {"18446744073709551615", std::numeric_limits<uint64_t>::max(), true},
+ {"18446744073709551616", std::numeric_limits<uint64_t>::max(), false},
};
for (size_t i = 0; i < arraysize(cases); ++i) {
- uint64 output = 0;
+ uint64_t output = 0;
EXPECT_EQ(cases[i].success, StringToUint64(cases[i].input, &output));
EXPECT_EQ(cases[i].output, output);
@@ -350,7 +353,7 @@ TEST(StringNumberConversionsTest, StringToUint64) {
// interpreted as junk after the number.
const char input[] = "6\06";
std::string input_string(input, arraysize(input) - 1);
- uint64 output;
+ uint64_t output;
EXPECT_FALSE(StringToUint64(input_string, &output));
EXPECT_EQ(6U, output);
@@ -432,7 +435,7 @@ TEST(StringNumberConversionsTest, StringToSizeT) {
TEST(StringNumberConversionsTest, HexStringToInt) {
static const struct {
std::string input;
- int64 output;
+ int64_t output;
bool success;
} cases[] = {
{"0", 0, true},
@@ -484,50 +487,55 @@ TEST(StringNumberConversionsTest, HexStringToInt) {
TEST(StringNumberConversionsTest, HexStringToUInt) {
static const struct {
std::string input;
- uint32 output;
+ uint32_t output;
bool success;
} cases[] = {
- {"0", 0, true},
- {"42", 0x42, true},
- {"-42", 0, false},
- {"+42", 0x42, true},
- {"7fffffff", INT_MAX, true},
- {"-80000000", 0, false},
- {"ffffffff", 0xffffffff, true},
- {"DeadBeef", 0xdeadbeef, true},
- {"0x42", 0x42, true},
- {"-0x42", 0, false},
- {"+0x42", 0x42, true},
- {"0x7fffffff", INT_MAX, true},
- {"-0x80000000", 0, false},
- {"0xffffffff", kuint32max, true},
- {"0XDeadBeef", 0xdeadbeef, true},
- {"0x7fffffffffffffff", kuint32max, false}, // Overflow test.
- {"-0x8000000000000000", 0, false},
- {"0x8000000000000000", kuint32max, false}, // Overflow test.
- {"-0x8000000000000001", 0, false},
- {"0xFFFFFFFFFFFFFFFF", kuint32max, false}, // Overflow test.
- {"FFFFFFFFFFFFFFFF", kuint32max, false}, // Overflow test.
- {"0x0000000000000000", 0, true},
- {"0000000000000000", 0, true},
- {"1FFFFFFFFFFFFFFFF", kuint32max, false}, // Overflow test.
- {"0x0f", 0x0f, true},
- {"0f", 0x0f, true},
- {" 45", 0x45, false},
- {"\t\n\v\f\r 0x45", 0x45, false},
- {" 45", 0x45, false},
- {"45 ", 0x45, false},
- {"45:", 0x45, false},
- {"efgh", 0xef, false},
- {"0xefgh", 0xef, false},
- {"hgfe", 0, false},
- {"-", 0, false},
- {"", 0, false},
- {"0x", 0, false},
+ {"0", 0, true},
+ {"42", 0x42, true},
+ {"-42", 0, false},
+ {"+42", 0x42, true},
+ {"7fffffff", INT_MAX, true},
+ {"-80000000", 0, false},
+ {"ffffffff", 0xffffffff, true},
+ {"DeadBeef", 0xdeadbeef, true},
+ {"0x42", 0x42, true},
+ {"-0x42", 0, false},
+ {"+0x42", 0x42, true},
+ {"0x7fffffff", INT_MAX, true},
+ {"-0x80000000", 0, false},
+ {"0xffffffff", std::numeric_limits<uint32_t>::max(), true},
+ {"0XDeadBeef", 0xdeadbeef, true},
+ {"0x7fffffffffffffff", std::numeric_limits<uint32_t>::max(),
+ false}, // Overflow test.
+ {"-0x8000000000000000", 0, false},
+ {"0x8000000000000000", std::numeric_limits<uint32_t>::max(),
+ false}, // Overflow test.
+ {"-0x8000000000000001", 0, false},
+ {"0xFFFFFFFFFFFFFFFF", std::numeric_limits<uint32_t>::max(),
+ false}, // Overflow test.
+ {"FFFFFFFFFFFFFFFF", std::numeric_limits<uint32_t>::max(),
+ false}, // Overflow test.
+ {"0x0000000000000000", 0, true},
+ {"0000000000000000", 0, true},
+ {"1FFFFFFFFFFFFFFFF", std::numeric_limits<uint32_t>::max(),
+ false}, // Overflow test.
+ {"0x0f", 0x0f, true},
+ {"0f", 0x0f, true},
+ {" 45", 0x45, false},
+ {"\t\n\v\f\r 0x45", 0x45, false},
+ {" 45", 0x45, false},
+ {"45 ", 0x45, false},
+ {"45:", 0x45, false},
+ {"efgh", 0xef, false},
+ {"0xefgh", 0xef, false},
+ {"hgfe", 0, false},
+ {"-", 0, false},
+ {"", 0, false},
+ {"0x", 0, false},
};
for (size_t i = 0; i < arraysize(cases); ++i) {
- uint32 output = 0;
+ uint32_t output = 0;
EXPECT_EQ(cases[i].success, HexStringToUInt(cases[i].input, &output));
EXPECT_EQ(cases[i].output, output);
}
@@ -536,7 +544,7 @@ TEST(StringNumberConversionsTest, HexStringToUInt) {
// interpreted as junk after the number.
const char input[] = "0xc0ffee\0" "9";
std::string input_string(input, arraysize(input) - 1);
- uint32 output;
+ uint32_t output;
EXPECT_FALSE(HexStringToUInt(input_string, &output));
EXPECT_EQ(0xc0ffeeU, output);
}
@@ -544,47 +552,49 @@ TEST(StringNumberConversionsTest, HexStringToUInt) {
TEST(StringNumberConversionsTest, HexStringToInt64) {
static const struct {
std::string input;
- int64 output;
+ int64_t output;
bool success;
} cases[] = {
- {"0", 0, true},
- {"42", 66, true},
- {"-42", -66, true},
- {"+42", 66, true},
- {"40acd88557b", INT64_C(4444444448123), true},
- {"7fffffff", INT_MAX, true},
- {"-80000000", INT_MIN, true},
- {"ffffffff", 0xffffffff, true},
- {"DeadBeef", 0xdeadbeef, true},
- {"0x42", 66, true},
- {"-0x42", -66, true},
- {"+0x42", 66, true},
- {"0x40acd88557b", INT64_C(4444444448123), true},
- {"0x7fffffff", INT_MAX, true},
- {"-0x80000000", INT_MIN, true},
- {"0xffffffff", 0xffffffff, true},
- {"0XDeadBeef", 0xdeadbeef, true},
- {"0x7fffffffffffffff", kint64max, true},
- {"-0x8000000000000000", kint64min, true},
- {"0x8000000000000000", kint64max, false}, // Overflow test.
- {"-0x8000000000000001", kint64min, false}, // Underflow test.
- {"0x0f", 15, true},
- {"0f", 15, true},
- {" 45", 0x45, false},
- {"\t\n\v\f\r 0x45", 0x45, false},
- {" 45", 0x45, false},
- {"45 ", 0x45, false},
- {"45:", 0x45, false},
- {"efgh", 0xef, false},
- {"0xefgh", 0xef, false},
- {"hgfe", 0, false},
- {"-", 0, false},
- {"", 0, false},
- {"0x", 0, false},
+ {"0", 0, true},
+ {"42", 66, true},
+ {"-42", -66, true},
+ {"+42", 66, true},
+ {"40acd88557b", INT64_C(4444444448123), true},
+ {"7fffffff", INT_MAX, true},
+ {"-80000000", INT_MIN, true},
+ {"ffffffff", 0xffffffff, true},
+ {"DeadBeef", 0xdeadbeef, true},
+ {"0x42", 66, true},
+ {"-0x42", -66, true},
+ {"+0x42", 66, true},
+ {"0x40acd88557b", INT64_C(4444444448123), true},
+ {"0x7fffffff", INT_MAX, true},
+ {"-0x80000000", INT_MIN, true},
+ {"0xffffffff", 0xffffffff, true},
+ {"0XDeadBeef", 0xdeadbeef, true},
+ {"0x7fffffffffffffff", std::numeric_limits<int64_t>::max(), true},
+ {"-0x8000000000000000", std::numeric_limits<int64_t>::min(), true},
+ {"0x8000000000000000", std::numeric_limits<int64_t>::max(),
+ false}, // Overflow test.
+ {"-0x8000000000000001", std::numeric_limits<int64_t>::min(),
+ false}, // Underflow test.
+ {"0x0f", 15, true},
+ {"0f", 15, true},
+ {" 45", 0x45, false},
+ {"\t\n\v\f\r 0x45", 0x45, false},
+ {" 45", 0x45, false},
+ {"45 ", 0x45, false},
+ {"45:", 0x45, false},
+ {"efgh", 0xef, false},
+ {"0xefgh", 0xef, false},
+ {"hgfe", 0, false},
+ {"-", 0, false},
+ {"", 0, false},
+ {"0x", 0, false},
};
for (size_t i = 0; i < arraysize(cases); ++i) {
- int64 output = 0;
+ int64_t output = 0;
EXPECT_EQ(cases[i].success, HexStringToInt64(cases[i].input, &output));
EXPECT_EQ(cases[i].output, output);
}
@@ -593,7 +603,7 @@ TEST(StringNumberConversionsTest, HexStringToInt64) {
// interpreted as junk after the number.
const char input[] = "0xc0ffee\0" "9";
std::string input_string(input, arraysize(input) - 1);
- int64 output;
+ int64_t output;
EXPECT_FALSE(HexStringToInt64(input_string, &output));
EXPECT_EQ(0xc0ffee, output);
}
@@ -601,52 +611,53 @@ TEST(StringNumberConversionsTest, HexStringToInt64) {
TEST(StringNumberConversionsTest, HexStringToUInt64) {
static const struct {
std::string input;
- uint64 output;
+ uint64_t output;
bool success;
} cases[] = {
- {"0", 0, true},
- {"42", 66, true},
- {"-42", 0, false},
- {"+42", 66, true},
- {"40acd88557b", INT64_C(4444444448123), true},
- {"7fffffff", INT_MAX, true},
- {"-80000000", 0, false},
- {"ffffffff", 0xffffffff, true},
- {"DeadBeef", 0xdeadbeef, true},
- {"0x42", 66, true},
- {"-0x42", 0, false},
- {"+0x42", 66, true},
- {"0x40acd88557b", INT64_C(4444444448123), true},
- {"0x7fffffff", INT_MAX, true},
- {"-0x80000000", 0, false},
- {"0xffffffff", 0xffffffff, true},
- {"0XDeadBeef", 0xdeadbeef, true},
- {"0x7fffffffffffffff", kint64max, true},
- {"-0x8000000000000000", 0, false},
- {"0x8000000000000000", UINT64_C(0x8000000000000000), true},
- {"-0x8000000000000001", 0, false},
- {"0xFFFFFFFFFFFFFFFF", kuint64max, true},
- {"FFFFFFFFFFFFFFFF", kuint64max, true},
- {"0x0000000000000000", 0, true},
- {"0000000000000000", 0, true},
- {"1FFFFFFFFFFFFFFFF", kuint64max, false}, // Overflow test.
- {"0x0f", 15, true},
- {"0f", 15, true},
- {" 45", 0x45, false},
- {"\t\n\v\f\r 0x45", 0x45, false},
- {" 45", 0x45, false},
- {"45 ", 0x45, false},
- {"45:", 0x45, false},
- {"efgh", 0xef, false},
- {"0xefgh", 0xef, false},
- {"hgfe", 0, false},
- {"-", 0, false},
- {"", 0, false},
- {"0x", 0, false},
+ {"0", 0, true},
+ {"42", 66, true},
+ {"-42", 0, false},
+ {"+42", 66, true},
+ {"40acd88557b", INT64_C(4444444448123), true},
+ {"7fffffff", INT_MAX, true},
+ {"-80000000", 0, false},
+ {"ffffffff", 0xffffffff, true},
+ {"DeadBeef", 0xdeadbeef, true},
+ {"0x42", 66, true},
+ {"-0x42", 0, false},
+ {"+0x42", 66, true},
+ {"0x40acd88557b", INT64_C(4444444448123), true},
+ {"0x7fffffff", INT_MAX, true},
+ {"-0x80000000", 0, false},
+ {"0xffffffff", 0xffffffff, true},
+ {"0XDeadBeef", 0xdeadbeef, true},
+ {"0x7fffffffffffffff", std::numeric_limits<int64_t>::max(), true},
+ {"-0x8000000000000000", 0, false},
+ {"0x8000000000000000", UINT64_C(0x8000000000000000), true},
+ {"-0x8000000000000001", 0, false},
+ {"0xFFFFFFFFFFFFFFFF", std::numeric_limits<uint64_t>::max(), true},
+ {"FFFFFFFFFFFFFFFF", std::numeric_limits<uint64_t>::max(), true},
+ {"0x0000000000000000", 0, true},
+ {"0000000000000000", 0, true},
+ {"1FFFFFFFFFFFFFFFF", std::numeric_limits<uint64_t>::max(),
+ false}, // Overflow test.
+ {"0x0f", 15, true},
+ {"0f", 15, true},
+ {" 45", 0x45, false},
+ {"\t\n\v\f\r 0x45", 0x45, false},
+ {" 45", 0x45, false},
+ {"45 ", 0x45, false},
+ {"45:", 0x45, false},
+ {"efgh", 0xef, false},
+ {"0xefgh", 0xef, false},
+ {"hgfe", 0, false},
+ {"-", 0, false},
+ {"", 0, false},
+ {"0x", 0, false},
};
for (size_t i = 0; i < arraysize(cases); ++i) {
- uint64 output = 0;
+ uint64_t output = 0;
EXPECT_EQ(cases[i].success, HexStringToUInt64(cases[i].input, &output));
EXPECT_EQ(cases[i].output, output);
}
@@ -655,7 +666,7 @@ TEST(StringNumberConversionsTest, HexStringToUInt64) {
// interpreted as junk after the number.
const char input[] = "0xc0ffee\0" "9";
std::string input_string(input, arraysize(input) - 1);
- uint64 output;
+ uint64_t output;
EXPECT_FALSE(HexStringToUInt64(input_string, &output));
EXPECT_EQ(0xc0ffeeU, output);
}
@@ -688,12 +699,12 @@ TEST(StringNumberConversionsTest, HexStringToBytes) {
for (size_t i = 0; i < arraysize(cases); ++i) {
- std::vector<uint8> output;
- std::vector<uint8> compare;
+ std::vector<uint8_t> output;
+ std::vector<uint8_t> compare;
EXPECT_EQ(cases[i].success, HexStringToBytes(cases[i].input, &output)) <<
i << ": " << cases[i].input;
for (size_t j = 0; j < cases[i].output_len; ++j)
- compare.push_back(static_cast<uint8>(cases[i].output[j]));
+ compare.push_back(static_cast<uint8_t>(cases[i].output[j]));
ASSERT_EQ(output.size(), compare.size()) << i << ": " << cases[i].input;
EXPECT_TRUE(std::equal(output.begin(), output.end(), compare.begin())) <<
i << ": " << cases[i].input;
diff --git a/chromium/base/strings/string_piece.cc b/chromium/base/strings/string_piece.cc
index 99975725afc..c26bb3652fa 100644
--- a/chromium/base/strings/string_piece.cc
+++ b/chromium/base/strings/string_piece.cc
@@ -5,6 +5,8 @@
#include "base/strings/string_piece.h"
+#include <limits.h>
+
#include <algorithm>
#include <ostream>
@@ -435,7 +437,7 @@ StringPiece16 substr(const StringPiece16& self,
return substrT(self, pos, n);
}
-#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+#if DCHECK_IS_ON()
void AssertIteratorsInOrder(std::string::const_iterator begin,
std::string::const_iterator end) {
DCHECK(begin <= end) << "StringPiece iterators swapped or invalid.";
diff --git a/chromium/base/strings/string_piece.h b/chromium/base/strings/string_piece.h
index c1af175406c..31e7596d119 100644
--- a/chromium/base/strings/string_piece.h
+++ b/chromium/base/strings/string_piece.h
@@ -28,8 +28,8 @@
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/containers/hash_tables.h"
+#include "base/logging.h"
#include "base/strings/string16.h"
namespace base {
@@ -143,7 +143,7 @@ BASE_EXPORT StringPiece16 substr(const StringPiece16& self,
size_t pos,
size_t n);
-#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+#if DCHECK_IS_ON()
// Asserts that begin <= end to catch some errors with iterator usage.
BASE_EXPORT void AssertIteratorsInOrder(std::string::const_iterator begin,
std::string::const_iterator end);
@@ -189,7 +189,7 @@ template <typename STRING_TYPE> class BasicStringPiece {
: ptr_(offset), length_(len) {}
BasicStringPiece(const typename STRING_TYPE::const_iterator& begin,
const typename STRING_TYPE::const_iterator& end) {
-#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
+#if DCHECK_IS_ON()
// This assertion is done out-of-line to avoid bringing in logging.h and
// instantiating logging macros for every instantiation.
internal::AssertIteratorsInOrder(begin, end);
diff --git a/chromium/base/strings/string_piece_unittest.cc b/chromium/base/strings/string_piece_unittest.cc
index 53366036d6f..f05aa152b50 100644
--- a/chromium/base/strings/string_piece_unittest.cc
+++ b/chromium/base/strings/string_piece_unittest.cc
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
+
#include <string>
#include "base/strings/string16.h"
diff --git a/chromium/base/strings/string_split.cc b/chromium/base/strings/string_split.cc
index 4253e2f8f86..6c949b989a9 100644
--- a/chromium/base/strings/string_split.cc
+++ b/chromium/base/strings/string_split.cc
@@ -4,6 +4,8 @@
#include "base/strings/string_split.h"
+#include <stddef.h>
+
#include "base/logging.h"
#include "base/strings/string_util.h"
#include "base/third_party/icu/icu_utf.h"
@@ -128,28 +130,28 @@ bool AppendStringKeyValue(StringPiece input,
return true;
}
-template <typename Str>
+template <typename Str, typename OutputStringType>
void SplitStringUsingSubstrT(BasicStringPiece<Str> input,
BasicStringPiece<Str> delimiter,
- std::vector<Str>* result) {
+ WhitespaceHandling whitespace,
+ SplitResult result_type,
+ std::vector<OutputStringType>* result) {
using Piece = BasicStringPiece<Str>;
using size_type = typename Piece::size_type;
result->clear();
- size_type begin_index = 0;
- while (true) {
- size_type end_index = input.find(delimiter, begin_index);
- if (end_index == Piece::npos) {
- // No delimiter, use the rest of the string.
- Piece term = TrimString(input.substr(begin_index),
- WhitespaceForType<Str>(), TRIM_ALL);
- result->push_back(term.as_string());
- return;
- }
- Piece term = TrimString(input.substr(begin_index, end_index - begin_index),
- WhitespaceForType<Str>(), TRIM_ALL);
- result->push_back(term.as_string());
- begin_index = end_index + delimiter.size();
+ for (size_type begin_index = 0, end_index = 0; end_index != Piece::npos;
+ begin_index = end_index + delimiter.size()) {
+ end_index = input.find(delimiter, begin_index);
+ Piece term = end_index == Piece::npos
+ ? input.substr(begin_index)
+ : input.substr(begin_index, end_index - begin_index);
+
+ if (whitespace == TRIM_WHITESPACE)
+ term = TrimString(term, WhitespaceForType<Str>(), TRIM_ALL);
+
+ if (result_type == SPLIT_WANT_ALL || !term.empty())
+ result->push_back(PieceToOutputType<Str, OutputStringType>(term));
}
}
@@ -228,13 +230,35 @@ bool SplitStringIntoKeyValuePairs(StringPiece input,
void SplitStringUsingSubstr(StringPiece16 input,
StringPiece16 delimiter,
std::vector<string16>* result) {
- SplitStringUsingSubstrT(input, delimiter, result);
+ SplitStringUsingSubstrT(input, delimiter, TRIM_WHITESPACE, SPLIT_WANT_ALL,
+ result);
}
void SplitStringUsingSubstr(StringPiece input,
StringPiece delimiter,
std::vector<std::string>* result) {
- SplitStringUsingSubstrT(input, delimiter, result);
+ SplitStringUsingSubstrT(input, delimiter, TRIM_WHITESPACE, SPLIT_WANT_ALL,
+ result);
+}
+
+std::vector<StringPiece16> SplitStringPieceUsingSubstr(
+ StringPiece16 input,
+ StringPiece16 delimiter,
+ WhitespaceHandling whitespace,
+ SplitResult result_type) {
+ std::vector<StringPiece16> result;
+ SplitStringUsingSubstrT(input, delimiter, whitespace, result_type, &result);
+ return result;
+}
+
+std::vector<StringPiece> SplitStringPieceUsingSubstr(
+ StringPiece input,
+ StringPiece delimiter,
+ WhitespaceHandling whitespace,
+ SplitResult result_type) {
+ std::vector<StringPiece> result;
+ SplitStringUsingSubstrT(input, delimiter, whitespace, result_type, &result);
+ return result;
}
} // namespace base
diff --git a/chromium/base/strings/string_split.h b/chromium/base/strings/string_split.h
index 2a0c79561b8..ec9f24604a6 100644
--- a/chromium/base/strings/string_split.h
+++ b/chromium/base/strings/string_split.h
@@ -101,6 +101,29 @@ BASE_EXPORT void SplitStringUsingSubstr(StringPiece input,
StringPiece delimiter,
std::vector<std::string>* result);
+// Like SplitStringUsingSubstr above except it returns a vector of StringPieces
+// which reference the original buffer without copying. Although you have to be
+// careful to keep the original string unmodified, this provides an efficient
+// way to iterate through tokens in a string.
+//
+// To iterate through all newline-separated tokens in an input string:
+//
+// for (const auto& cur :
+// base::SplitStringUsingSubstr(input, "\r\n",
+// base::KEEP_WHITESPACE,
+// base::SPLIT_WANT_NONEMPTY)) {
+// ...
+BASE_EXPORT std::vector<StringPiece16> SplitStringPieceUsingSubstr(
+ StringPiece16 input,
+ StringPiece16 delimiter,
+ WhitespaceHandling whitespace,
+ SplitResult result_type);
+BASE_EXPORT std::vector<StringPiece> SplitStringPieceUsingSubstr(
+ StringPiece input,
+ StringPiece delimiter,
+ WhitespaceHandling whitespace,
+ SplitResult result_type);
+
} // namespace base
#endif // BASE_STRINGS_STRING_SPLIT_H_
diff --git a/chromium/base/strings/string_split_unittest.cc b/chromium/base/strings/string_split_unittest.cc
index 0416776b54c..657a2db7b51 100644
--- a/chromium/base/strings/string_split_unittest.cc
+++ b/chromium/base/strings/string_split_unittest.cc
@@ -4,6 +4,9 @@
#include "base/strings/string_split.h"
+#include <stddef.h>
+
+#include "base/macros.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -265,6 +268,71 @@ TEST(SplitStringUsingSubstrTest, TrailingDelimitersSkipped) {
results, ElementsAre("un", "deux", "trois", "quatre", "", "", ""));
}
+TEST(SplitStringPieceUsingSubstrTest, StringWithNoDelimiter) {
+ std::vector<base::StringPiece> results =
+ SplitStringPieceUsingSubstr("alongwordwithnodelimiter", "DELIMITER",
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+ ASSERT_EQ(1u, results.size());
+ EXPECT_THAT(results, ElementsAre("alongwordwithnodelimiter"));
+}
+
+TEST(SplitStringPieceUsingSubstrTest, LeadingDelimitersSkipped) {
+ std::vector<base::StringPiece> results = SplitStringPieceUsingSubstr(
+ "DELIMITERDELIMITERDELIMITERoneDELIMITERtwoDELIMITERthree", "DELIMITER",
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+ ASSERT_EQ(6u, results.size());
+ EXPECT_THAT(results, ElementsAre("", "", "", "one", "two", "three"));
+}
+
+TEST(SplitStringPieceUsingSubstrTest, ConsecutiveDelimitersSkipped) {
+ std::vector<base::StringPiece> results = SplitStringPieceUsingSubstr(
+ "unoDELIMITERDELIMITERDELIMITERdosDELIMITERtresDELIMITERDELIMITERcuatro",
+ "DELIMITER", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+ ASSERT_EQ(7u, results.size());
+ EXPECT_THAT(results, ElementsAre("uno", "", "", "dos", "tres", "", "cuatro"));
+}
+
+TEST(SplitStringPieceUsingSubstrTest, TrailingDelimitersSkipped) {
+ std::vector<base::StringPiece> results = SplitStringPieceUsingSubstr(
+ "unDELIMITERdeuxDELIMITERtroisDELIMITERquatreDELIMITERDELIMITERDELIMITER",
+ "DELIMITER", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+ ASSERT_EQ(7u, results.size());
+ EXPECT_THAT(results,
+ ElementsAre("un", "deux", "trois", "quatre", "", "", ""));
+}
+
+TEST(SplitStringPieceUsingSubstrTest, KeepWhitespace) {
+ std::vector<base::StringPiece> results = SplitStringPieceUsingSubstr(
+ "un DELIMITERdeux\tDELIMITERtrois\nDELIMITERquatre", "DELIMITER",
+ base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
+ ASSERT_EQ(4u, results.size());
+ EXPECT_THAT(results, ElementsAre("un ", "deux\t", "trois\n", "quatre"));
+}
+
+TEST(SplitStringPieceUsingSubstrTest, TrimWhitespace) {
+ std::vector<base::StringPiece> results = SplitStringPieceUsingSubstr(
+ "un DELIMITERdeux\tDELIMITERtrois\nDELIMITERquatre", "DELIMITER",
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+ ASSERT_EQ(4u, results.size());
+ EXPECT_THAT(results, ElementsAre("un", "deux", "trois", "quatre"));
+}
+
+TEST(SplitStringPieceUsingSubstrTest, SplitWantAll) {
+ std::vector<base::StringPiece> results = SplitStringPieceUsingSubstr(
+ "unDELIMITERdeuxDELIMITERtroisDELIMITERDELIMITER", "DELIMITER",
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+ ASSERT_EQ(5u, results.size());
+ EXPECT_THAT(results, ElementsAre("un", "deux", "trois", "", ""));
+}
+
+TEST(SplitStringPieceUsingSubstrTest, SplitWantNonEmpty) {
+ std::vector<base::StringPiece> results = SplitStringPieceUsingSubstr(
+ "unDELIMITERdeuxDELIMITERtroisDELIMITERDELIMITER", "DELIMITER",
+ base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+ ASSERT_EQ(3u, results.size());
+ EXPECT_THAT(results, ElementsAre("un", "deux", "trois"));
+}
+
TEST(StringSplitTest, StringSplitKeepWhitespace) {
std::vector<std::string> r;
diff --git a/chromium/base/strings/string_util.cc b/chromium/base/strings/string_util.cc
index d7a1d54c722..e8000abd40b 100644
--- a/chromium/base/strings/string_util.cc
+++ b/chromium/base/strings/string_util.cc
@@ -8,6 +8,7 @@
#include <errno.h>
#include <math.h>
#include <stdarg.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -16,10 +17,11 @@
#include <wctype.h>
#include <algorithm>
+#include <limits>
#include <vector>
-#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/singleton.h"
#include "base/strings/string_split.h"
#include "base/strings/utf_string_conversion_utils.h"
@@ -99,18 +101,6 @@ template<> struct NonASCIIMask<8, wchar_t> {
};
#endif // WCHAR_T_IS_UTF32
-// DO NOT USE. http://crbug.com/24917
-//
-// tolower() will given incorrect results for non-ASCII characters. Use the
-// ASCII version, base::i18n::ToLower, or base::i18n::FoldCase. This is here
-// for backwards-compat for StartsWith until such calls can be updated.
-struct CaseInsensitiveCompareDeprecated {
- public:
- bool operator()(char16 x, char16 y) const {
- return tolower(x) == tolower(y);
- }
-};
-
} // namespace
bool IsWprintfFormatPortable(const wchar_t* format) {
@@ -366,10 +356,11 @@ void TruncateUTF8ToByteSize(const std::string& input,
*output = input;
return;
}
- DCHECK_LE(byte_size, static_cast<uint32>(kint32max));
- // Note: This cast is necessary because CBU8_NEXT uses int32s.
- int32 truncation_length = static_cast<int32>(byte_size);
- int32 char_index = truncation_length - 1;
+ DCHECK_LE(byte_size,
+ static_cast<uint32_t>(std::numeric_limits<int32_t>::max()));
+ // Note: This cast is necessary because CBU8_NEXT uses int32_ts.
+ int32_t truncation_length = static_cast<int32_t>(byte_size);
+ int32_t char_index = truncation_length - 1;
const char* data = input.data();
// Using CBU8, we will move backwards from the truncation point
@@ -377,7 +368,7 @@ void TruncateUTF8ToByteSize(const std::string& input,
// character. Once a full UTF8 character is found, we will
// truncate the string to the end of that character.
while (char_index >= 0) {
- int32 prev = char_index;
+ int32_t prev = char_index;
base_icu::UChar32 code_point = 0;
CBU8_NEXT(data, char_index, truncation_length, code_point);
if (!IsValidCharacter(code_point) ||
@@ -415,14 +406,6 @@ StringPiece TrimWhitespaceASCII(StringPiece input, TrimPositions positions) {
return TrimStringPieceT(input, StringPiece(kWhitespaceASCII), positions);
}
-// This function is only for backward-compatibility.
-// To be removed when all callers are updated.
-TrimPositions TrimWhitespace(const std::string& input,
- TrimPositions positions,
- std::string* output) {
- return TrimWhitespaceASCII(input, positions, output);
-}
-
template<typename STR>
STR CollapseWhitespaceT(const STR& text,
bool trim_sequences_with_line_breaks) {
@@ -535,11 +518,11 @@ bool IsStringASCII(const std::wstring& str) {
bool IsStringUTF8(const StringPiece& str) {
const char *src = str.data();
- int32 src_len = static_cast<int32>(str.length());
- int32 char_index = 0;
+ int32_t src_len = static_cast<int32_t>(str.length());
+ int32_t char_index = 0;
while (char_index < src_len) {
- int32 code_point;
+ int32_t code_point;
CBU8_NEXT(src, char_index, src_len, code_point);
if (!IsValidCharacter(code_point))
return false;
@@ -674,6 +657,15 @@ char HexDigitToInt(wchar_t c) {
return 0;
}
+bool IsUnicodeWhitespace(wchar_t c) {
+ // kWhitespaceWide is a NULL-terminated string
+ for (const wchar_t* cur = kWhitespaceWide; *cur; ++cur) {
+ if (*cur == c)
+ return true;
+ }
+ return false;
+}
+
static const char* const kByteStringsUnlocalized[] = {
" B",
" kB",
@@ -683,7 +675,7 @@ static const char* const kByteStringsUnlocalized[] = {
" PB"
};
-string16 FormatBytesUnlocalized(int64 bytes) {
+string16 FormatBytesUnlocalized(int64_t bytes) {
double unit_amount = static_cast<double>(bytes);
size_t dimension = 0;
const int kKilo = 1024;
diff --git a/chromium/base/strings/string_util.h b/chromium/base/strings/string_util.h
index 169726bca5a..e369f294d0b 100644
--- a/chromium/base/strings/string_util.h
+++ b/chromium/base/strings/string_util.h
@@ -9,15 +9,17 @@
#include <ctype.h>
#include <stdarg.h> // va_list
+#include <stddef.h>
+#include <stdint.h>
#include <string>
#include <vector>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/strings/string16.h"
#include "base/strings/string_piece.h" // For implicit conversions.
+#include "build/build_config.h"
namespace base {
@@ -36,9 +38,14 @@ int vsnprintf(char* buffer, size_t size, const char* format, va_list arguments)
// We separate the declaration from the implementation of this inline
// function just so the PRINTF_FORMAT works.
-inline int snprintf(char* buffer, size_t size, const char* format, ...)
- PRINTF_FORMAT(3, 4);
-inline int snprintf(char* buffer, size_t size, const char* format, ...) {
+inline int snprintf(char* buffer,
+ size_t size,
+ _Printf_format_string_ const char* format,
+ ...) PRINTF_FORMAT(3, 4);
+inline int snprintf(char* buffer,
+ size_t size,
+ _Printf_format_string_ const char* format,
+ ...) {
va_list arguments;
va_start(arguments, format);
int result = vsnprintf(buffer, size, format, arguments);
@@ -238,12 +245,6 @@ BASE_EXPORT TrimPositions TrimWhitespaceASCII(const std::string& input,
BASE_EXPORT StringPiece TrimWhitespaceASCII(StringPiece input,
TrimPositions positions);
-// Deprecated. This function is only for backward compatibility and calls
-// TrimWhitespaceASCII().
-BASE_EXPORT TrimPositions TrimWhitespace(const std::string& input,
- TrimPositions positions,
- std::string* output);
-
// Searches for CR or LF characters. Removes all contiguous whitespace
// strings that contain them. This is useful when trying to deal with text
// copied from terminals.
@@ -358,15 +359,13 @@ inline bool IsHexDigit(Char c) {
BASE_EXPORT char HexDigitToInt(wchar_t c);
// Returns true if it's a Unicode whitespace character.
-inline bool IsUnicodeWhitespace(wchar_t c) {
- return wcschr(base::kWhitespaceWide, c) != NULL;
-}
+BASE_EXPORT bool IsUnicodeWhitespace(wchar_t c);
// Return a byte string in human-readable format with a unit suffix. Not
// appropriate for use in any UI; use of FormatBytes and friends in ui/base is
// highly recommended instead. TODO(avi): Figure out how to get callers to use
// FormatBytes instead; remove this.
-BASE_EXPORT string16 FormatBytesUnlocalized(int64 bytes);
+BASE_EXPORT string16 FormatBytesUnlocalized(int64_t bytes);
// Starting at |start_offset| (usually 0), replace the first instance of
// |find_this| with |replace_with|.
diff --git a/chromium/base/strings/string_util_posix.h b/chromium/base/strings/string_util_posix.h
index 9e96697ff56..8299118e106 100644
--- a/chromium/base/strings/string_util_posix.h
+++ b/chromium/base/strings/string_util_posix.h
@@ -6,6 +6,7 @@
#define BASE_STRINGS_STRING_UTIL_POSIX_H_
#include <stdarg.h>
+#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <wchar.h>
diff --git a/chromium/base/strings/string_util_unittest.cc b/chromium/base/strings/string_util_unittest.cc
index 187e49e6698..79eed61d5cb 100644
--- a/chromium/base/strings/string_util_unittest.cc
+++ b/chromium/base/strings/string_util_unittest.cc
@@ -6,10 +6,12 @@
#include <math.h>
#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
#include <algorithm>
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -250,7 +252,7 @@ TEST(StringUtilTest, TrimWhitespace) {
for (size_t i = 0; i < arraysize(trim_cases_ascii); ++i) {
const trim_case_ascii& value = trim_cases_ascii[i];
EXPECT_EQ(value.return_value,
- TrimWhitespace(value.input, value.positions, &output_ascii));
+ TrimWhitespaceASCII(value.input, value.positions, &output_ascii));
EXPECT_EQ(value.output, output_ascii);
}
}
@@ -549,7 +551,7 @@ TEST(StringUtilTest, LowerCaseEqualsASCII) {
TEST(StringUtilTest, FormatBytesUnlocalized) {
static const struct {
- int64 bytes;
+ int64_t bytes;
const char* expected;
} cases[] = {
// Expected behavior: we show one post-decimal digit when we have
@@ -1080,6 +1082,26 @@ TEST(StringUtilTest, EqualsCaseInsensitiveASCII) {
EXPECT_FALSE(EqualsCaseInsensitiveASCII("Asdf", "aSDFz"));
}
+TEST(StringUtilTest, IsUnicodeWhitespace) {
+ // NOT unicode white space.
+ EXPECT_FALSE(IsUnicodeWhitespace(L'\0'));
+ EXPECT_FALSE(IsUnicodeWhitespace(L'A'));
+ EXPECT_FALSE(IsUnicodeWhitespace(L'0'));
+ EXPECT_FALSE(IsUnicodeWhitespace(L'.'));
+ EXPECT_FALSE(IsUnicodeWhitespace(L';'));
+ EXPECT_FALSE(IsUnicodeWhitespace(L'\x4100'));
+
+ // Actual unicode whitespace.
+ EXPECT_TRUE(IsUnicodeWhitespace(L' '));
+ EXPECT_TRUE(IsUnicodeWhitespace(L'\xa0'));
+ EXPECT_TRUE(IsUnicodeWhitespace(L'\x3000'));
+ EXPECT_TRUE(IsUnicodeWhitespace(L'\t'));
+ EXPECT_TRUE(IsUnicodeWhitespace(L'\r'));
+ EXPECT_TRUE(IsUnicodeWhitespace(L'\v'));
+ EXPECT_TRUE(IsUnicodeWhitespace(L'\f'));
+ EXPECT_TRUE(IsUnicodeWhitespace(L'\n'));
+}
+
class WriteIntoTest : public testing::Test {
protected:
static void WritesCorrectly(size_t num_chars) {
diff --git a/chromium/base/strings/string_util_win.h b/chromium/base/strings/string_util_win.h
index 839a799a157..7f260bfc8b4 100644
--- a/chromium/base/strings/string_util_win.h
+++ b/chromium/base/strings/string_util_win.h
@@ -6,6 +6,7 @@
#define BASE_STRINGS_STRING_UTIL_WIN_H_
#include <stdarg.h>
+#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <wchar.h>
diff --git a/chromium/base/strings/stringprintf.cc b/chromium/base/strings/stringprintf.cc
index 537873d71c8..415845d6165 100644
--- a/chromium/base/strings/stringprintf.cc
+++ b/chromium/base/strings/stringprintf.cc
@@ -5,12 +5,15 @@
#include "base/strings/stringprintf.h"
#include <errno.h>
+#include <stddef.h>
#include <vector>
+#include "base/macros.h"
#include "base/scoped_clear_errno.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
namespace base {
diff --git a/chromium/base/strings/stringprintf.h b/chromium/base/strings/stringprintf.h
index 523f7ee55bf..7a75d89e10f 100644
--- a/chromium/base/strings/stringprintf.h
+++ b/chromium/base/strings/stringprintf.h
@@ -11,15 +11,18 @@
#include "base/base_export.h"
#include "base/compiler_specific.h"
+#include "build/build_config.h"
namespace base {
// Return a C++ string given printf-like input.
-BASE_EXPORT std::string StringPrintf(const char* format, ...)
+BASE_EXPORT std::string StringPrintf(_Printf_format_string_ const char* format,
+ ...)
PRINTF_FORMAT(1, 2) WARN_UNUSED_RESULT;
#if defined(OS_WIN)
-BASE_EXPORT std::wstring StringPrintf(const wchar_t* format, ...)
- WPRINTF_FORMAT(1, 2) WARN_UNUSED_RESULT;
+BASE_EXPORT std::wstring StringPrintf(
+ _Printf_format_string_ const wchar_t* format,
+ ...) WPRINTF_FORMAT(1, 2) WARN_UNUSED_RESULT;
#endif
// Return a C++ string given vprintf-like input.
@@ -27,21 +30,25 @@ BASE_EXPORT std::string StringPrintV(const char* format, va_list ap)
PRINTF_FORMAT(1, 0) WARN_UNUSED_RESULT;
// Store result into a supplied string and return it.
-BASE_EXPORT const std::string& SStringPrintf(std::string* dst,
- const char* format, ...)
- PRINTF_FORMAT(2, 3);
+BASE_EXPORT const std::string& SStringPrintf(
+ std::string* dst,
+ _Printf_format_string_ const char* format,
+ ...) PRINTF_FORMAT(2, 3);
#if defined(OS_WIN)
-BASE_EXPORT const std::wstring& SStringPrintf(std::wstring* dst,
- const wchar_t* format, ...)
- WPRINTF_FORMAT(2, 3);
+BASE_EXPORT const std::wstring& SStringPrintf(
+ std::wstring* dst,
+ _Printf_format_string_ const wchar_t* format,
+ ...) WPRINTF_FORMAT(2, 3);
#endif
// Append result to a supplied string.
-BASE_EXPORT void StringAppendF(std::string* dst, const char* format, ...)
- PRINTF_FORMAT(2, 3);
+BASE_EXPORT void StringAppendF(std::string* dst,
+ _Printf_format_string_ const char* format,
+ ...) PRINTF_FORMAT(2, 3);
#if defined(OS_WIN)
-BASE_EXPORT void StringAppendF(std::wstring* dst, const wchar_t* format, ...)
- WPRINTF_FORMAT(2, 3);
+BASE_EXPORT void StringAppendF(std::wstring* dst,
+ _Printf_format_string_ const wchar_t* format,
+ ...) WPRINTF_FORMAT(2, 3);
#endif
// Lower-level routine that takes a va_list and appends to a specified
diff --git a/chromium/base/strings/stringprintf_unittest.cc b/chromium/base/strings/stringprintf_unittest.cc
index c49637c23f2..e2d3a90ffdf 100644
--- a/chromium/base/strings/stringprintf_unittest.cc
+++ b/chromium/base/strings/stringprintf_unittest.cc
@@ -5,8 +5,10 @@
#include "base/strings/stringprintf.h"
#include <errno.h>
+#include <stddef.h>
-#include "base/basictypes.h"
+#include "base/macros.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
@@ -148,10 +150,10 @@ TEST(StringPrintfTest, GrowBoundary) {
EXPECT_STREQ(src, out.c_str());
}
-// TODO(evanm): what's the proper cross-platform test here?
#if defined(OS_WIN)
-// sprintf in Visual Studio fails when given U+FFFF. This tests that the
-// failure case is gracefuly handled.
+// vswprintf in Visual Studio 2013 fails when given U+FFFF. This tests that the
+// failure case is gracefuly handled. In Visual Studio 2015 the bad character
+// is passed through.
TEST(StringPrintfTest, Invalid) {
wchar_t invalid[2];
invalid[0] = 0xffff;
@@ -159,7 +161,11 @@ TEST(StringPrintfTest, Invalid) {
std::wstring out;
SStringPrintf(&out, L"%ls", invalid);
+#if _MSC_VER >= 1900
+ EXPECT_STREQ(invalid, out.c_str());
+#else
EXPECT_STREQ(L"", out.c_str());
+#endif
}
#endif
diff --git a/chromium/base/strings/sys_string_conversions.h b/chromium/base/strings/sys_string_conversions.h
index 42f2389a8b1..b41a2288ca9 100644
--- a/chromium/base/strings/sys_string_conversions.h
+++ b/chromium/base/strings/sys_string_conversions.h
@@ -9,12 +9,14 @@
// necessary to not use ICU. Generally, you should not need this in Chrome,
// but it is used in some shared code. Dependencies should be minimal.
+#include <stdint.h>
+
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/strings/string16.h"
#include "base/strings/string_piece.h"
+#include "build/build_config.h"
#if defined(OS_MACOSX)
#include <CoreFoundation/CoreFoundation.h>
@@ -46,9 +48,9 @@ BASE_EXPORT std::wstring SysNativeMBToWide(const StringPiece& native_mb);
// code page identifier is one accepted by the Windows function
// MultiByteToWideChar().
BASE_EXPORT std::wstring SysMultiByteToWide(const StringPiece& mb,
- uint32 code_page);
+ uint32_t code_page);
BASE_EXPORT std::string SysWideToMultiByte(const std::wstring& wide,
- uint32 code_page);
+ uint32_t code_page);
#endif // defined(OS_WIN)
diff --git a/chromium/base/strings/sys_string_conversions_mac.mm b/chromium/base/strings/sys_string_conversions_mac.mm
index 9479e787c0e..32fe89cc367 100644
--- a/chromium/base/strings/sys_string_conversions_mac.mm
+++ b/chromium/base/strings/sys_string_conversions_mac.mm
@@ -5,6 +5,7 @@
#include "base/strings/sys_string_conversions.h"
#import <Foundation/Foundation.h>
+#include <stddef.h>
#include <vector>
diff --git a/chromium/base/strings/sys_string_conversions_posix.cc b/chromium/base/strings/sys_string_conversions_posix.cc
index 3b1845622fd..a8dcfd0a907 100644
--- a/chromium/base/strings/sys_string_conversions_posix.cc
+++ b/chromium/base/strings/sys_string_conversions_posix.cc
@@ -4,10 +4,12 @@
#include "base/strings/sys_string_conversions.h"
+#include <stddef.h>
#include <wchar.h>
#include "base/strings/string_piece.h"
#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
namespace base {
diff --git a/chromium/base/strings/sys_string_conversions_unittest.cc b/chromium/base/strings/sys_string_conversions_unittest.cc
index 90c4767e25d..f5ffaec17bf 100644
--- a/chromium/base/strings/sys_string_conversions_unittest.cc
+++ b/chromium/base/strings/sys_string_conversions_unittest.cc
@@ -2,13 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
+
#include <string>
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/strings/string_piece.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_locale.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#ifdef WCHAR_T_IS_UTF32
diff --git a/chromium/base/strings/sys_string_conversions_win.cc b/chromium/base/strings/sys_string_conversions_win.cc
index 94d44662236..b70854421df 100644
--- a/chromium/base/strings/sys_string_conversions_win.cc
+++ b/chromium/base/strings/sys_string_conversions_win.cc
@@ -5,6 +5,7 @@
#include "base/strings/sys_string_conversions.h"
#include <windows.h>
+#include <stdint.h>
#include "base/strings/string_piece.h"
@@ -29,7 +30,7 @@ std::wstring SysNativeMBToWide(const StringPiece& native_mb) {
}
// Do not assert in this function since it is used by the asssertion code!
-std::wstring SysMultiByteToWide(const StringPiece& mb, uint32 code_page) {
+std::wstring SysMultiByteToWide(const StringPiece& mb, uint32_t code_page) {
if (mb.empty())
return std::wstring();
@@ -48,7 +49,7 @@ std::wstring SysMultiByteToWide(const StringPiece& mb, uint32 code_page) {
}
// Do not assert in this function since it is used by the asssertion code!
-std::string SysWideToMultiByte(const std::wstring& wide, uint32 code_page) {
+std::string SysWideToMultiByte(const std::wstring& wide, uint32_t code_page) {
int wide_length = static_cast<int>(wide.length());
if (wide_length == 0)
return std::string();
diff --git a/chromium/base/strings/utf_offset_string_conversions.cc b/chromium/base/strings/utf_offset_string_conversions.cc
index c2270bfce2f..322c7a28d3a 100644
--- a/chromium/base/strings/utf_offset_string_conversions.cc
+++ b/chromium/base/strings/utf_offset_string_conversions.cc
@@ -4,6 +4,8 @@
#include "base/strings/utf_offset_string_conversions.h"
+#include <stdint.h>
+
#include <algorithm>
#include "base/logging.h"
@@ -188,9 +190,9 @@ bool ConvertUnicode(const SrcChar* src,
adjustments->clear();
// ICU requires 32-bit numbers.
bool success = true;
- int32 src_len32 = static_cast<int32>(src_len);
- for (int32 i = 0; i < src_len32; i++) {
- uint32 code_point;
+ int32_t src_len32 = static_cast<int32_t>(src_len);
+ for (int32_t i = 0; i < src_len32; i++) {
+ uint32_t code_point;
size_t original_i = i;
size_t chars_written = 0;
if (ReadUnicodeCharacter(src, src_len32, &i, &code_point)) {
diff --git a/chromium/base/strings/utf_offset_string_conversions.h b/chromium/base/strings/utf_offset_string_conversions.h
index d4494894efb..1844601fae0 100644
--- a/chromium/base/strings/utf_offset_string_conversions.h
+++ b/chromium/base/strings/utf_offset_string_conversions.h
@@ -5,6 +5,8 @@
#ifndef BASE_STRINGS_UTF_OFFSET_STRING_CONVERSIONS_H_
#define BASE_STRINGS_UTF_OFFSET_STRING_CONVERSIONS_H_
+#include <stddef.h>
+
#include <string>
#include <vector>
diff --git a/chromium/base/strings/utf_offset_string_conversions_unittest.cc b/chromium/base/strings/utf_offset_string_conversions_unittest.cc
index 9398a56233c..fe0e4da81af 100644
--- a/chromium/base/strings/utf_offset_string_conversions_unittest.cc
+++ b/chromium/base/strings/utf_offset_string_conversions_unittest.cc
@@ -2,9 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
+
#include <algorithm>
#include "base/logging.h"
+#include "base/macros.h"
#include "base/strings/string_piece.h"
#include "base/strings/utf_offset_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/base/strings/utf_string_conversion_utils.cc b/chromium/base/strings/utf_string_conversion_utils.cc
index 022c0dffd89..3101a602888 100644
--- a/chromium/base/strings/utf_string_conversion_utils.cc
+++ b/chromium/base/strings/utf_string_conversion_utils.cc
@@ -11,15 +11,15 @@ namespace base {
// ReadUnicodeCharacter --------------------------------------------------------
bool ReadUnicodeCharacter(const char* src,
- int32 src_len,
- int32* char_index,
- uint32* code_point_out) {
+ int32_t src_len,
+ int32_t* char_index,
+ uint32_t* code_point_out) {
// U8_NEXT expects to be able to use -1 to signal an error, so we must
// use a signed type for code_point. But this function returns false
// on error anyway, so code_point_out is unsigned.
- int32 code_point;
+ int32_t code_point;
CBU8_NEXT(src, *char_index, src_len, code_point);
- *code_point_out = static_cast<uint32>(code_point);
+ *code_point_out = static_cast<uint32_t>(code_point);
// The ICU macro above moves to the next char, we want to point to the last
// char consumed.
@@ -30,9 +30,9 @@ bool ReadUnicodeCharacter(const char* src,
}
bool ReadUnicodeCharacter(const char16* src,
- int32 src_len,
- int32* char_index,
- uint32* code_point) {
+ int32_t src_len,
+ int32_t* char_index,
+ uint32_t* code_point) {
if (CBU16_IS_SURROGATE(src[*char_index])) {
if (!CBU16_IS_SURROGATE_LEAD(src[*char_index]) ||
*char_index + 1 >= src_len ||
@@ -55,9 +55,9 @@ bool ReadUnicodeCharacter(const char16* src,
#if defined(WCHAR_T_IS_UTF32)
bool ReadUnicodeCharacter(const wchar_t* src,
- int32 src_len,
- int32* char_index,
- uint32* code_point) {
+ int32_t src_len,
+ int32_t* char_index,
+ uint32_t* code_point) {
// Conversion is easy since the source is 32-bit.
*code_point = src[*char_index];
@@ -68,7 +68,7 @@ bool ReadUnicodeCharacter(const wchar_t* src,
// WriteUnicodeCharacter -------------------------------------------------------
-size_t WriteUnicodeCharacter(uint32 code_point, std::string* output) {
+size_t WriteUnicodeCharacter(uint32_t code_point, std::string* output) {
if (code_point <= 0x7f) {
// Fast path the common case of one byte.
output->push_back(static_cast<char>(code_point));
@@ -89,7 +89,7 @@ size_t WriteUnicodeCharacter(uint32 code_point, std::string* output) {
return char_offset - original_char_offset;
}
-size_t WriteUnicodeCharacter(uint32 code_point, string16* output) {
+size_t WriteUnicodeCharacter(uint32_t code_point, string16* output) {
if (CBU16_LENGTH(code_point) == 1) {
// Thie code point is in the Basic Multilingual Plane (BMP).
output->push_back(static_cast<char16>(code_point));
diff --git a/chromium/base/strings/utf_string_conversion_utils.h b/chromium/base/strings/utf_string_conversion_utils.h
index a1b2e64a182..c7164045390 100644
--- a/chromium/base/strings/utf_string_conversion_utils.h
+++ b/chromium/base/strings/utf_string_conversion_utils.h
@@ -7,12 +7,15 @@
// This should only be used by the various UTF string conversion files.
+#include <stddef.h>
+#include <stdint.h>
+
#include "base/base_export.h"
#include "base/strings/string16.h"
namespace base {
-inline bool IsValidCodepoint(uint32 code_point) {
+inline bool IsValidCodepoint(uint32_t code_point) {
// Excludes the surrogate code points ([0xD800, 0xDFFF]) and
// codepoints larger than 0x10FFFF (the highest codepoint allowed).
// Non-characters and unassigned codepoints are allowed.
@@ -20,7 +23,7 @@ inline bool IsValidCodepoint(uint32 code_point) {
(code_point >= 0xE000u && code_point <= 0x10FFFFu);
}
-inline bool IsValidCharacter(uint32 code_point) {
+inline bool IsValidCharacter(uint32_t code_point) {
// Excludes non-characters (U+FDD0..U+FDEF, and all codepoints ending in
// 0xFFFE or 0xFFFF) from the set of valid code points.
return code_point < 0xD800u || (code_point >= 0xE000u &&
@@ -38,39 +41,39 @@ inline bool IsValidCharacter(uint32 code_point) {
//
// Returns true on success. On false, |*code_point| will be invalid.
BASE_EXPORT bool ReadUnicodeCharacter(const char* src,
- int32 src_len,
- int32* char_index,
- uint32* code_point_out);
+ int32_t src_len,
+ int32_t* char_index,
+ uint32_t* code_point_out);
// Reads a UTF-16 character. The usage is the same as the 8-bit version above.
BASE_EXPORT bool ReadUnicodeCharacter(const char16* src,
- int32 src_len,
- int32* char_index,
- uint32* code_point);
+ int32_t src_len,
+ int32_t* char_index,
+ uint32_t* code_point);
#if defined(WCHAR_T_IS_UTF32)
// Reads UTF-32 character. The usage is the same as the 8-bit version above.
BASE_EXPORT bool ReadUnicodeCharacter(const wchar_t* src,
- int32 src_len,
- int32* char_index,
- uint32* code_point);
+ int32_t src_len,
+ int32_t* char_index,
+ uint32_t* code_point);
#endif // defined(WCHAR_T_IS_UTF32)
// WriteUnicodeCharacter -------------------------------------------------------
// Appends a UTF-8 character to the given 8-bit string. Returns the number of
// bytes written.
-BASE_EXPORT size_t WriteUnicodeCharacter(uint32 code_point,
+BASE_EXPORT size_t WriteUnicodeCharacter(uint32_t code_point,
std::string* output);
// Appends the given code point as a UTF-16 character to the given 16-bit
// string. Returns the number of 16-bit values written.
-BASE_EXPORT size_t WriteUnicodeCharacter(uint32 code_point, string16* output);
+BASE_EXPORT size_t WriteUnicodeCharacter(uint32_t code_point, string16* output);
#if defined(WCHAR_T_IS_UTF32)
// Appends the given UTF-32 character to the given 32-bit string. Returns the
// number of 32-bit values written.
-inline size_t WriteUnicodeCharacter(uint32 code_point, std::wstring* output) {
+inline size_t WriteUnicodeCharacter(uint32_t code_point, std::wstring* output) {
// This is the easy case, just append the character.
output->push_back(code_point);
return 1;
diff --git a/chromium/base/strings/utf_string_conversions.cc b/chromium/base/strings/utf_string_conversions.cc
index b6cf6ff9b10..6b17eacd6ce 100644
--- a/chromium/base/strings/utf_string_conversions.cc
+++ b/chromium/base/strings/utf_string_conversions.cc
@@ -4,9 +4,12 @@
#include "base/strings/utf_string_conversions.h"
+#include <stdint.h>
+
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversion_utils.h"
+#include "build/build_config.h"
namespace base {
@@ -24,9 +27,9 @@ bool ConvertUnicode(const SRC_CHAR* src,
DEST_STRING* output) {
// ICU requires 32-bit numbers.
bool success = true;
- int32 src_len32 = static_cast<int32>(src_len);
- for (int32 i = 0; i < src_len32; i++) {
- uint32 code_point;
+ int32_t src_len32 = static_cast<int32_t>(src_len);
+ for (int32_t i = 0; i < src_len32; i++) {
+ uint32_t code_point;
if (ReadUnicodeCharacter(src, src_len32, &i, &code_point)) {
WriteUnicodeCharacter(code_point, output);
} else {
diff --git a/chromium/base/strings/utf_string_conversions.h b/chromium/base/strings/utf_string_conversions.h
index 9b15730df38..2995f4cbcf6 100644
--- a/chromium/base/strings/utf_string_conversions.h
+++ b/chromium/base/strings/utf_string_conversions.h
@@ -5,6 +5,8 @@
#ifndef BASE_STRINGS_UTF_STRING_CONVERSIONS_H_
#define BASE_STRINGS_UTF_STRING_CONVERSIONS_H_
+#include <stddef.h>
+
#include <string>
#include "base/base_export.h"
diff --git a/chromium/base/strings/utf_string_conversions_unittest.cc b/chromium/base/strings/utf_string_conversions_unittest.cc
index 97d8cbb668c..810771357a2 100644
--- a/chromium/base/strings/utf_string_conversions_unittest.cc
+++ b/chromium/base/strings/utf_string_conversions_unittest.cc
@@ -2,11 +2,14 @@
// 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 <stddef.h>
+
#include "base/logging.h"
+#include "base/macros.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
@@ -139,13 +142,11 @@ TEST(UTFStringConversionsTest, ConvertUTF16ToUTF8) {
{L"\x597d\xd800", "\xe5\xa5\xbd\xef\xbf\xbd", false},
};
- for (int i = 0; i < arraysize(convert_cases); i++) {
+ for (const auto& test : convert_cases) {
std::string converted;
- EXPECT_EQ(convert_cases[i].success,
- WideToUTF8(convert_cases[i].utf16,
- wcslen(convert_cases[i].utf16),
- &converted));
- std::string expected(convert_cases[i].utf8);
+ EXPECT_EQ(test.success,
+ WideToUTF8(test.utf16, wcslen(test.utf16), &converted));
+ std::string expected(test.utf8);
EXPECT_EQ(expected, converted);
}
}
@@ -172,13 +173,11 @@ TEST(UTFStringConversionsTest, ConvertUTF32ToUTF8) {
{L"\xdc01Hello", "\xef\xbf\xbdHello", false},
};
- for (size_t i = 0; i < arraysize(convert_cases); i++) {
+ for (const auto& test : convert_cases) {
std::string converted;
- EXPECT_EQ(convert_cases[i].success,
- WideToUTF8(convert_cases[i].utf32,
- wcslen(convert_cases[i].utf32),
- &converted));
- std::string expected(convert_cases[i].utf8);
+ EXPECT_EQ(test.success,
+ WideToUTF8(test.utf32, wcslen(test.utf32), &converted));
+ std::string expected(test.utf8);
EXPECT_EQ(expected, converted);
}
}
diff --git a/chromium/base/supports_user_data.h b/chromium/base/supports_user_data.h
index 711ee7d8979..5c1c7e945f6 100644
--- a/chromium/base/supports_user_data.h
+++ b/chromium/base/supports_user_data.h
@@ -8,6 +8,7 @@
#include <map>
#include "base/base_export.h"
+#include "base/macros.h"
#include "base/memory/linked_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/threading/thread_checker.h"
diff --git a/chromium/base/sync_socket.h b/chromium/base/sync_socket.h
index 201fb1c1553..fcf4155047e 100644
--- a/chromium/base/sync_socket.h
+++ b/chromium/base/sync_socket.h
@@ -9,17 +9,20 @@
// data. Because the receiving is blocking, they can be used to perform
// rudimentary cross-process synchronization with low latency.
-#include "base/basictypes.h"
-#if defined(OS_WIN)
-#include <windows.h>
-#endif
-#include <sys/types.h>
+#include <stddef.h>
#include "base/base_export.h"
#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "base/process/process_handle.h"
#include "base/synchronization/waitable_event.h"
#include "base/time/time.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+#include <sys/types.h>
#if defined(OS_POSIX)
#include "base/file_descriptor_posix.h"
diff --git a/chromium/base/sync_socket_nacl.cc b/chromium/base/sync_socket_nacl.cc
index 9e9243d5ff9..4a02082edd6 100644
--- a/chromium/base/sync_socket_nacl.cc
+++ b/chromium/base/sync_socket_nacl.cc
@@ -6,6 +6,7 @@
#include <errno.h>
#include <limits.h>
+#include <stddef.h>
#include <stdio.h>
#include <sys/types.h>
diff --git a/chromium/base/sync_socket_posix.cc b/chromium/base/sync_socket_posix.cc
index 51b38a586dd..7b9995ce3a2 100644
--- a/chromium/base/sync_socket_posix.cc
+++ b/chromium/base/sync_socket_posix.cc
@@ -7,6 +7,7 @@
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
+#include <stddef.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
@@ -19,6 +20,7 @@
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/threading/thread_restrictions.h"
+#include "build/build_config.h"
namespace base {
diff --git a/chromium/base/sync_socket_unittest.cc b/chromium/base/sync_socket_unittest.cc
index ff9b8bc8c2f..97a1aec47d3 100644
--- a/chromium/base/sync_socket_unittest.cc
+++ b/chromium/base/sync_socket_unittest.cc
@@ -2,11 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/basictypes.h"
-// TODO(ellyjones): Remove once http://crbug.com/523296 is fixed.
-#if defined(OS_IOS) && !TARGET_IPHONE_SIMULATOR
-#include "base/ios/ios_util.h"
-#endif
+#include "base/macros.h"
#include "base/sync_socket.h"
#include "base/threading/simple_thread.h"
#include "base/time/time.h"
@@ -53,7 +49,7 @@ class HangingReceiveThread : public base::DelegateSimpleThread::Delegate {
void SendReceivePeek(base::SyncSocket* socket_a, base::SyncSocket* socket_b) {
int received = 0;
const int kSending = 123;
- COMPILE_ASSERT(sizeof(kSending) == sizeof(received), Invalid_Data_Size);
+ static_assert(sizeof(kSending) == sizeof(received), "invalid data size");
ASSERT_EQ(0u, socket_a->Peek());
ASSERT_EQ(0u, socket_b->Peek());
@@ -118,11 +114,6 @@ TEST(CancelableSyncSocket, ClonedSendReceivePeek) {
}
TEST(CancelableSyncSocket, CancelReceiveShutdown) {
-// TODO(ellyjones): This test fails on iOS 7 devices. http://crbug.com/523296
-#if defined(OS_IOS) && !TARGET_IPHONE_SIMULATOR
- if (!base::ios::IsRunningOnIOS8OrLater())
- return;
-#endif
base::CancelableSyncSocket socket_a, socket_b;
ASSERT_TRUE(base::CancelableSyncSocket::CreatePair(&socket_a, &socket_b));
diff --git a/chromium/base/sync_socket_win.cc b/chromium/base/sync_socket_win.cc
index e16b925bbdf..067c7de217b 100644
--- a/chromium/base/sync_socket_win.cc
+++ b/chromium/base/sync_socket_win.cc
@@ -4,7 +4,11 @@
#include "base/sync_socket.h"
+#include <limits.h>
+#include <stddef.h>
+
#include "base/logging.h"
+#include "base/macros.h"
#include "base/rand_util.h"
#include "base/threading/thread_restrictions.h"
#include "base/win/scoped_handle.h"
@@ -121,7 +125,7 @@ size_t CancelableFileOperation(Function operation,
DWORD timeout_in_ms) {
ThreadRestrictions::AssertIOAllowed();
// The buffer must be byte size or the length check won't make much sense.
- COMPILE_ASSERT(sizeof(buffer[0]) == sizeof(char), incorrect_buffer_type);
+ static_assert(sizeof(buffer[0]) == sizeof(char), "incorrect buffer type");
DCHECK_GT(length, 0u);
DCHECK_LE(length, kMaxMessageLength);
DCHECK_NE(file, SyncSocket::kInvalidHandle);
diff --git a/chromium/base/synchronization/cancellation_flag.h b/chromium/base/synchronization/cancellation_flag.h
index 0f0f08ee8f7..f2f83f47dad 100644
--- a/chromium/base/synchronization/cancellation_flag.h
+++ b/chromium/base/synchronization/cancellation_flag.h
@@ -5,8 +5,9 @@
#ifndef BASE_SYNCHRONIZATION_CANCELLATION_FLAG_H_
#define BASE_SYNCHRONIZATION_CANCELLATION_FLAG_H_
-#include "base/base_export.h"
#include "base/atomicops.h"
+#include "base/base_export.h"
+#include "base/macros.h"
#include "base/threading/platform_thread.h"
namespace base {
diff --git a/chromium/base/synchronization/condition_variable.h b/chromium/base/synchronization/condition_variable.h
index 91e4d1350d6..a41b2ba5a78 100644
--- a/chromium/base/synchronization/condition_variable.h
+++ b/chromium/base/synchronization/condition_variable.h
@@ -65,17 +65,16 @@
#ifndef BASE_SYNCHRONIZATION_CONDITION_VARIABLE_H_
#define BASE_SYNCHRONIZATION_CONDITION_VARIABLE_H_
+#include "base/base_export.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/synchronization/lock.h"
#include "build/build_config.h"
#if defined(OS_POSIX)
#include <pthread.h>
#endif
-#include "base/base_export.h"
-#include "base/basictypes.h"
-#include "base/logging.h"
-#include "base/synchronization/lock.h"
-
namespace base {
class ConditionVarImpl;
diff --git a/chromium/base/synchronization/condition_variable_posix.cc b/chromium/base/synchronization/condition_variable_posix.cc
index 0e4668feb2a..d86fd180ec7 100644
--- a/chromium/base/synchronization/condition_variable_posix.cc
+++ b/chromium/base/synchronization/condition_variable_posix.cc
@@ -5,11 +5,13 @@
#include "base/synchronization/condition_variable.h"
#include <errno.h>
+#include <stdint.h>
#include <sys/time.h>
#include "base/synchronization/lock.h"
#include "base/threading/thread_restrictions.h"
#include "base/time/time.h"
+#include "build/build_config.h"
namespace base {
@@ -73,7 +75,7 @@ void ConditionVariable::Wait() {
void ConditionVariable::TimedWait(const TimeDelta& max_time) {
base::ThreadRestrictions::AssertWaitAllowed();
- int64 usecs = max_time.InMicroseconds();
+ int64_t usecs = max_time.InMicroseconds();
struct timespec relative_time;
relative_time.tv_sec = usecs / Time::kMicrosecondsPerSecond;
relative_time.tv_nsec =
diff --git a/chromium/base/synchronization/condition_variable_unittest.cc b/chromium/base/synchronization/condition_variable_unittest.cc
index e63a723d009..4503922ecec 100644
--- a/chromium/base/synchronization/condition_variable_unittest.cc
+++ b/chromium/base/synchronization/condition_variable_unittest.cc
@@ -20,6 +20,7 @@
#include "base/threading/thread.h"
#include "base/threading/thread_collision_warner.h"
#include "base/time/time.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
diff --git a/chromium/base/synchronization/condition_variable_win.cc b/chromium/base/synchronization/condition_variable_win.cc
index 4256ac8224d..6812eb9c7b0 100644
--- a/chromium/base/synchronization/condition_variable_win.cc
+++ b/chromium/base/synchronization/condition_variable_win.cc
@@ -8,6 +8,7 @@
#include <stack>
#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "base/synchronization/lock.h"
#include "base/threading/thread_restrictions.h"
#include "base/time/time.h"
diff --git a/chromium/base/synchronization/lock.h b/chromium/base/synchronization/lock.h
index 81e274809f8..f7dd35dccba 100644
--- a/chromium/base/synchronization/lock.h
+++ b/chromium/base/synchronization/lock.h
@@ -7,8 +7,10 @@
#include "base/base_export.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/synchronization/lock_impl.h"
#include "base/threading/platform_thread.h"
+#include "build/build_config.h"
namespace base {
diff --git a/chromium/base/synchronization/lock_impl.h b/chromium/base/synchronization/lock_impl.h
index 42e2f99068b..ed85987b39e 100644
--- a/chromium/base/synchronization/lock_impl.h
+++ b/chromium/base/synchronization/lock_impl.h
@@ -5,6 +5,8 @@
#ifndef BASE_SYNCHRONIZATION_LOCK_IMPL_H_
#define BASE_SYNCHRONIZATION_LOCK_IMPL_H_
+#include "base/base_export.h"
+#include "base/macros.h"
#include "build/build_config.h"
#if defined(OS_WIN)
@@ -13,9 +15,6 @@
#include <pthread.h>
#endif
-#include "base/base_export.h"
-#include "base/basictypes.h"
-
namespace base {
namespace internal {
diff --git a/chromium/base/synchronization/lock_unittest.cc b/chromium/base/synchronization/lock_unittest.cc
index 967efb8e923..27f335e2cc5 100644
--- a/chromium/base/synchronization/lock_unittest.cc
+++ b/chromium/base/synchronization/lock_unittest.cc
@@ -7,6 +7,7 @@
#include <stdlib.h>
#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "base/threading/platform_thread.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/base/synchronization/waitable_event.h b/chromium/base/synchronization/waitable_event.h
index c35af5467f6..b5d91d00b51 100644
--- a/chromium/base/synchronization/waitable_event.h
+++ b/chromium/base/synchronization/waitable_event.h
@@ -5,8 +5,11 @@
#ifndef BASE_SYNCHRONIZATION_WAITABLE_EVENT_H_
#define BASE_SYNCHRONIZATION_WAITABLE_EVENT_H_
+#include <stddef.h>
+
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
+#include "build/build_config.h"
#if defined(OS_WIN)
#include "base/win/scoped_handle.h"
diff --git a/chromium/base/synchronization/waitable_event_posix.cc b/chromium/base/synchronization/waitable_event_posix.cc
index 696ffc7a02a..64d4376fe56 100644
--- a/chromium/base/synchronization/waitable_event_posix.cc
+++ b/chromium/base/synchronization/waitable_event_posix.cc
@@ -2,13 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
+
#include <algorithm>
#include <vector>
#include "base/logging.h"
-#include "base/synchronization/waitable_event.h"
#include "base/synchronization/condition_variable.h"
#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
#include "base/threading/thread_restrictions.h"
// -----------------------------------------------------------------------------
diff --git a/chromium/base/synchronization/waitable_event_unittest.cc b/chromium/base/synchronization/waitable_event_unittest.cc
index be56cf171a1..2930409b597 100644
--- a/chromium/base/synchronization/waitable_event_unittest.cc
+++ b/chromium/base/synchronization/waitable_event_unittest.cc
@@ -4,9 +4,12 @@
#include "base/synchronization/waitable_event.h"
+#include <stddef.h>
+
#include "base/compiler_specific.h"
#include "base/threading/platform_thread.h"
#include "base/time/time.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
diff --git a/chromium/base/synchronization/waitable_event_watcher_posix.cc b/chromium/base/synchronization/waitable_event_watcher_posix.cc
index ad66a4c769a..aa425f25500 100644
--- a/chromium/base/synchronization/waitable_event_watcher_posix.cc
+++ b/chromium/base/synchronization/waitable_event_watcher_posix.cc
@@ -6,6 +6,7 @@
#include "base/bind.h"
#include "base/location.h"
+#include "base/macros.h"
#include "base/single_thread_task_runner.h"
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
diff --git a/chromium/base/synchronization/waitable_event_watcher_unittest.cc b/chromium/base/synchronization/waitable_event_watcher_unittest.cc
index 5319d1efba3..58444b3c4ef 100644
--- a/chromium/base/synchronization/waitable_event_watcher_unittest.cc
+++ b/chromium/base/synchronization/waitable_event_watcher_unittest.cc
@@ -6,10 +6,12 @@
#include "base/bind.h"
#include "base/callback.h"
+#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/platform_thread.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
diff --git a/chromium/base/synchronization/waitable_event_win.cc b/chromium/base/synchronization/waitable_event_win.cc
index 2d6d7348755..6674cdb923f 100644
--- a/chromium/base/synchronization/waitable_event_win.cc
+++ b/chromium/base/synchronization/waitable_event_win.cc
@@ -5,6 +5,7 @@
#include "base/synchronization/waitable_event.h"
#include <windows.h>
+#include <stddef.h>
#include "base/logging.h"
#include "base/numerics/safe_conversions.h"
diff --git a/chromium/base/sys_byteorder.h b/chromium/base/sys_byteorder.h
index 704ed568b09..ddb3f5bcda4 100644
--- a/chromium/base/sys_byteorder.h
+++ b/chromium/base/sys_byteorder.h
@@ -11,28 +11,23 @@
#ifndef BASE_SYS_BYTEORDER_H_
#define BASE_SYS_BYTEORDER_H_
-#include "base/basictypes.h"
-#include "build/build_config.h"
+#include <stdint.h>
-#if defined(OS_WIN)
-#include <winsock2.h>
-#else
-#include <arpa/inet.h>
-#endif
+#include "build/build_config.h"
namespace base {
// Returns a value with all bytes in |x| swapped, i.e. reverses the endianness.
-inline uint16 ByteSwap(uint16 x) {
+inline uint16_t ByteSwap(uint16_t x) {
return ((x & 0x00ff) << 8) | ((x & 0xff00) >> 8);
}
-inline uint32 ByteSwap(uint32 x) {
+inline uint32_t ByteSwap(uint32_t x) {
return ((x & 0x000000fful) << 24) | ((x & 0x0000ff00ul) << 8) |
((x & 0x00ff0000ul) >> 8) | ((x & 0xff000000ul) >> 24);
}
-inline uint64 ByteSwap(uint64 x) {
+inline uint64_t ByteSwap(uint64_t x) {
return ((x & 0x00000000000000ffull) << 56) |
((x & 0x000000000000ff00ull) << 40) |
((x & 0x0000000000ff0000ull) << 24) |
@@ -45,21 +40,21 @@ inline uint64 ByteSwap(uint64 x) {
// Converts the bytes in |x| from host order (endianness) to little endian, and
// returns the result.
-inline uint16 ByteSwapToLE16(uint16 x) {
+inline uint16_t ByteSwapToLE16(uint16_t x) {
#if defined(ARCH_CPU_LITTLE_ENDIAN)
return x;
#else
return ByteSwap(x);
#endif
}
-inline uint32 ByteSwapToLE32(uint32 x) {
+inline uint32_t ByteSwapToLE32(uint32_t x) {
#if defined(ARCH_CPU_LITTLE_ENDIAN)
return x;
#else
return ByteSwap(x);
#endif
}
-inline uint64 ByteSwapToLE64(uint64 x) {
+inline uint64_t ByteSwapToLE64(uint64_t x) {
#if defined(ARCH_CPU_LITTLE_ENDIAN)
return x;
#else
@@ -69,21 +64,21 @@ inline uint64 ByteSwapToLE64(uint64 x) {
// Converts the bytes in |x| from network to host order (endianness), and
// returns the result.
-inline uint16 NetToHost16(uint16 x) {
+inline uint16_t NetToHost16(uint16_t x) {
#if defined(ARCH_CPU_LITTLE_ENDIAN)
return ByteSwap(x);
#else
return x;
#endif
}
-inline uint32 NetToHost32(uint32 x) {
+inline uint32_t NetToHost32(uint32_t x) {
#if defined(ARCH_CPU_LITTLE_ENDIAN)
return ByteSwap(x);
#else
return x;
#endif
}
-inline uint64 NetToHost64(uint64 x) {
+inline uint64_t NetToHost64(uint64_t x) {
#if defined(ARCH_CPU_LITTLE_ENDIAN)
return ByteSwap(x);
#else
@@ -93,21 +88,21 @@ inline uint64 NetToHost64(uint64 x) {
// Converts the bytes in |x| from host to network order (endianness), and
// returns the result.
-inline uint16 HostToNet16(uint16 x) {
+inline uint16_t HostToNet16(uint16_t x) {
#if defined(ARCH_CPU_LITTLE_ENDIAN)
return ByteSwap(x);
#else
return x;
#endif
}
-inline uint32 HostToNet32(uint32 x) {
+inline uint32_t HostToNet32(uint32_t x) {
#if defined(ARCH_CPU_LITTLE_ENDIAN)
return ByteSwap(x);
#else
return x;
#endif
}
-inline uint64 HostToNet64(uint64 x) {
+inline uint64_t HostToNet64(uint64_t x) {
#if defined(ARCH_CPU_LITTLE_ENDIAN)
return ByteSwap(x);
#else
diff --git a/chromium/base/sys_info.cc b/chromium/base/sys_info.cc
index f24ebd3547d..cebb3630099 100644
--- a/chromium/base/sys_info.cc
+++ b/chromium/base/sys_info.cc
@@ -12,6 +12,7 @@
#include "base/strings/string_util.h"
#include "base/sys_info_internal.h"
#include "base/time/time.h"
+#include "build/build_config.h"
namespace base {
@@ -55,12 +56,12 @@ std::string SysInfo::HardwareModelName() {
#endif
// static
-int64 SysInfo::Uptime() {
+base::TimeDelta SysInfo::Uptime() {
// This code relies on an implementation detail of TimeTicks::Now() - that
// its return value happens to coincide with the system uptime value in
// microseconds, on Win/Mac/iOS/Linux/ChromeOS and Android.
- int64 uptime_in_microseconds = TimeTicks::Now().ToInternalValue();
- return uptime_in_microseconds / 1000;
+ int64_t uptime_in_microseconds = TimeTicks::Now().ToInternalValue();
+ return base::TimeDelta::FromMicroseconds(uptime_in_microseconds);
}
} // namespace base
diff --git a/chromium/base/sys_info.h b/chromium/base/sys_info.h
index 5a81dc1583f..5686dcbb49d 100644
--- a/chromium/base/sys_info.h
+++ b/chromium/base/sys_info.h
@@ -5,11 +5,13 @@
#ifndef BASE_SYS_INFO_H_
#define BASE_SYS_INFO_H_
+#include <stddef.h>
+#include <stdint.h>
+
#include <map>
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/files/file_path.h"
#include "base/time/time.h"
#include "build/build_config.h"
@@ -22,16 +24,16 @@ class BASE_EXPORT SysInfo {
static int NumberOfProcessors();
// Return the number of bytes of physical memory on the current machine.
- static int64 AmountOfPhysicalMemory();
+ static int64_t AmountOfPhysicalMemory();
// Return the number of bytes of current available physical memory on the
// machine.
- static int64 AmountOfAvailablePhysicalMemory();
+ static int64_t AmountOfAvailablePhysicalMemory();
// Return the number of bytes of virtual memory of this process. A return
// value of zero means that there is no limit on the available virtual
// memory.
- static int64 AmountOfVirtualMemory();
+ static int64_t AmountOfVirtualMemory();
// Return the number of megabytes of physical memory on the current machine.
static int AmountOfPhysicalMemoryMB() {
@@ -46,10 +48,10 @@ class BASE_EXPORT SysInfo {
// Return the available disk space in bytes on the volume containing |path|,
// or -1 on failure.
- static int64 AmountOfFreeDiskSpace(const FilePath& path);
+ static int64_t AmountOfFreeDiskSpace(const FilePath& path);
- // Returns system uptime in milliseconds.
- static int64 Uptime();
+ // Returns system uptime.
+ static TimeDelta Uptime();
// Returns a descriptive string for the current machine model or an empty
// string if the machine model is unknown or an error occured.
@@ -71,9 +73,9 @@ class BASE_EXPORT SysInfo {
// an OS version check instead of a feature check, use the base::mac::IsOS*
// family from base/mac/mac_util.h, or base::win::GetVersion from
// base/win/windows_version.h.
- static void OperatingSystemVersionNumbers(int32* major_version,
- int32* minor_version,
- int32* bugfix_version);
+ static void OperatingSystemVersionNumbers(int32_t* major_version,
+ int32_t* minor_version,
+ int32_t* bugfix_version);
// Returns the architecture of the running operating system.
// Exact return value may differ across platforms.
@@ -94,7 +96,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 uint64 MaxSharedMemorySize();
+ static uint64_t 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 c288ae2fe87..cb25cdc51a3 100644
--- a/chromium/base/sys_info_android.cc
+++ b/chromium/base/sys_info_android.cc
@@ -5,6 +5,8 @@
#include "base/sys_info.h"
#include <dlfcn.h>
+#include <stddef.h>
+#include <stdint.h>
#include <sys/system_properties.h>
#include "base/android/sys_utils.h"
@@ -59,15 +61,15 @@ 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 = 5;
-const int kDefaultAndroidMinorVersion = 1;
+const int kDefaultAndroidMajorVersion = 6;
+const int kDefaultAndroidMinorVersion = 0;
const int kDefaultAndroidBugfixVersion = 99;
// Parse out the OS version numbers from the system properties.
void ParseOSVersionNumbers(const char* os_version_str,
- int32 *major_version,
- int32 *minor_version,
- int32 *bugfix_version) {
+ int32_t* major_version,
+ int32_t* minor_version,
+ int32_t* bugfix_version) {
if (os_version_str[0]) {
// Try to parse out the version numbers from the string.
int num_read = sscanf(os_version_str, "%d.%d.%d", major_version,
@@ -90,13 +92,13 @@ void ParseOSVersionNumbers(const char* os_version_str,
// Parses a system property (specified with unit 'k','m' or 'g').
// Returns a value in bytes.
// Returns -1 if the string could not be parsed.
-int64 ParseSystemPropertyBytes(const base::StringPiece& str) {
- const int64 KB = 1024;
- const int64 MB = 1024 * KB;
- const int64 GB = 1024 * MB;
+int64_t ParseSystemPropertyBytes(const base::StringPiece& str) {
+ const int64_t KB = 1024;
+ const int64_t MB = 1024 * KB;
+ const int64_t GB = 1024 * MB;
if (str.size() == 0u)
return -1;
- int64 unit_multiplier = 1;
+ int64_t unit_multiplier = 1;
size_t length = str.size();
if (str[length - 1] == 'k') {
unit_multiplier = KB;
@@ -108,10 +110,11 @@ int64 ParseSystemPropertyBytes(const base::StringPiece& str) {
unit_multiplier = GB;
length--;
}
- int64 result = 0;
+ int64_t result = 0;
bool parsed = base::StringToInt64(str.substr(0, length), &result);
bool negative = result <= 0;
- bool overflow = result >= std::numeric_limits<int64>::max() / unit_multiplier;
+ bool overflow =
+ result >= std::numeric_limits<int64_t>::max() / unit_multiplier;
if (!parsed || negative || overflow)
return -1;
return result * unit_multiplier;
@@ -123,14 +126,15 @@ int GetDalvikHeapSizeMB() {
// dalvik.vm.heapsize property is writable by a root user.
// Clamp it to reasonable range as a sanity check,
// a typical android device will never have less than 48MB.
- const int64 MB = 1024 * 1024;
- int64 result = ParseSystemPropertyBytes(heap_size_str);
+ const int64_t MB = 1024 * 1024;
+ int64_t result = ParseSystemPropertyBytes(heap_size_str);
if (result == -1) {
// We should consider not exposing these values if they are not reliable.
LOG(ERROR) << "Can't parse dalvik.vm.heapsize: " << heap_size_str;
result = base::SysInfo::AmountOfPhysicalMemoryMB() / 3;
}
- result = std::min<int64>(std::max<int64>(32 * MB, result), 1024 * MB) / MB;
+ result =
+ std::min<int64_t>(std::max<int64_t>(32 * MB, result), 1024 * MB) / MB;
return static_cast<int>(result);
}
@@ -140,14 +144,14 @@ int GetDalvikHeapGrowthLimitMB() {
// dalvik.vm.heapgrowthlimit property is writable by a root user.
// Clamp it to reasonable range as a sanity check,
// a typical android device will never have less than 24MB.
- const int64 MB = 1024 * 1024;
- int64 result = ParseSystemPropertyBytes(heap_size_str);
+ const int64_t MB = 1024 * 1024;
+ int64_t result = ParseSystemPropertyBytes(heap_size_str);
if (result == -1) {
// We should consider not exposing these values if they are not reliable.
LOG(ERROR) << "Can't parse dalvik.vm.heapgrowthlimit: " << heap_size_str;
result = base::SysInfo::AmountOfPhysicalMemoryMB() / 6;
}
- result = std::min<int64>(std::max<int64>(16 * MB, result), 512 * MB) / MB;
+ result = std::min<int64_t>(std::max<int64_t>(16 * MB, result), 512 * MB) / MB;
return static_cast<int>(result);
}
@@ -166,14 +170,14 @@ std::string SysInfo::OperatingSystemName() {
}
std::string SysInfo::OperatingSystemVersion() {
- int32 major, minor, bugfix;
+ int32_t major, minor, bugfix;
OperatingSystemVersionNumbers(&major, &minor, &bugfix);
return StringPrintf("%d.%d.%d", major, minor, bugfix);
}
-void SysInfo::OperatingSystemVersionNumbers(int32* major_version,
- int32* minor_version,
- int32* bugfix_version) {
+void SysInfo::OperatingSystemVersionNumbers(int32_t* major_version,
+ int32_t* minor_version,
+ int32_t* bugfix_version) {
// Read the version number string out from the properties.
char os_version_str[PROP_VALUE_MAX];
__system_property_get("ro.build.version.release", os_version_str);
diff --git a/chromium/base/sys_info_chromeos.cc b/chromium/base/sys_info_chromeos.cc
index 9915055996d..e35bd0a5907 100644
--- a/chromium/base/sys_info_chromeos.cc
+++ b/chromium/base/sys_info_chromeos.cc
@@ -4,12 +4,15 @@
#include "base/sys_info.h"
-#include "base/basictypes.h"
+#include <stddef.h>
+#include <stdint.h>
+
#include "base/environment.h"
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/lazy_instance.h"
+#include "base/macros.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_split.h"
@@ -90,9 +93,9 @@ class ChromeOSVersionInfo {
return true;
}
- void GetVersionNumbers(int32* major_version,
- int32* minor_version,
- int32* bugfix_version) {
+ void GetVersionNumbers(int32_t* major_version,
+ int32_t* minor_version,
+ int32_t* bugfix_version) {
*major_version = major_version_;
*minor_version = minor_version_;
*bugfix_version = bugfix_version_;
@@ -154,9 +157,9 @@ class ChromeOSVersionInfo {
Time lsb_release_time_;
SysInfo::LsbReleaseMap lsb_release_map_;
- int32 major_version_;
- int32 minor_version_;
- int32 bugfix_version_;
+ int32_t major_version_;
+ int32_t minor_version_;
+ int32_t bugfix_version_;
bool is_running_on_chromeos_;
};
@@ -170,9 +173,9 @@ ChromeOSVersionInfo& GetChromeOSVersionInfo() {
} // namespace
// static
-void SysInfo::OperatingSystemVersionNumbers(int32* major_version,
- int32* minor_version,
- int32* bugfix_version) {
+void SysInfo::OperatingSystemVersionNumbers(int32_t* major_version,
+ int32_t* minor_version,
+ int32_t* bugfix_version) {
return GetChromeOSVersionInfo().GetVersionNumbers(
major_version, minor_version, bugfix_version);
}
diff --git a/chromium/base/sys_info_freebsd.cc b/chromium/base/sys_info_freebsd.cc
index 515b59d6e98..0b2008d5526 100644
--- a/chromium/base/sys_info_freebsd.cc
+++ b/chromium/base/sys_info_freebsd.cc
@@ -4,13 +4,15 @@
#include "base/sys_info.h"
+#include <stddef.h>
+#include <stdint.h>
#include <sys/sysctl.h>
#include "base/logging.h"
namespace base {
-int64 SysInfo::AmountOfPhysicalMemory() {
+int64_t SysInfo::AmountOfPhysicalMemory() {
int pages, page_size;
size_t size = sizeof(pages);
sysctlbyname("vm.stats.vm.v_page_count", &pages, &size, NULL, 0);
@@ -19,18 +21,18 @@ int64 SysInfo::AmountOfPhysicalMemory() {
NOTREACHED();
return 0;
}
- return static_cast<int64>(pages) * page_size;
+ return static_cast<int64_t>(pages) * page_size;
}
// static
-uint64 SysInfo::MaxSharedMemorySize() {
+uint64_t SysInfo::MaxSharedMemorySize() {
size_t limit;
size_t size = sizeof(limit);
if (sysctlbyname("kern.ipc.shmmax", &limit, &size, NULL, 0) < 0) {
NOTREACHED();
return 0;
}
- return static_cast<uint64>(limit);
+ return static_cast<uint64_t>(limit);
}
} // namespace base
diff --git a/chromium/base/sys_info_internal.h b/chromium/base/sys_info_internal.h
index e7674d5c09f..a1792191f5b 100644
--- a/chromium/base/sys_info_internal.h
+++ b/chromium/base/sys_info_internal.h
@@ -5,7 +5,7 @@
#ifndef BASE_SYS_INFO_INTERNAL_H_
#define BASE_SYS_INFO_INTERNAL_H_
-#include "base/basictypes.h"
+#include "base/macros.h"
namespace base {
diff --git a/chromium/base/sys_info_ios.mm b/chromium/base/sys_info_ios.mm
index 0e24a2a4f59..9a95298e692 100644
--- a/chromium/base/sys_info_ios.mm
+++ b/chromium/base/sys_info_ios.mm
@@ -5,6 +5,8 @@
#include "base/sys_info.h"
#include <mach/mach.h>
+#include <stddef.h>
+#include <stdint.h>
#include <sys/sysctl.h>
#include <sys/types.h>
#import <UIKit/UIKit.h>
@@ -12,6 +14,7 @@
#include "base/logging.h"
#include "base/mac/scoped_mach_port.h"
#include "base/mac/scoped_nsautorelease_pool.h"
+#include "base/macros.h"
#include "base/strings/sys_string_conversions.h"
namespace base {
@@ -43,9 +46,9 @@ std::string SysInfo::OperatingSystemVersion() {
}
// static
-void SysInfo::OperatingSystemVersionNumbers(int32* major_version,
- int32* minor_version,
- int32* bugfix_version) {
+void SysInfo::OperatingSystemVersionNumbers(int32_t* major_version,
+ int32_t* minor_version,
+ int32_t* bugfix_version) {
base::mac::ScopedNSAutoreleasePool pool;
std::string system_version = OperatingSystemVersion();
if (!system_version.empty()) {
@@ -62,11 +65,11 @@ void SysInfo::OperatingSystemVersionNumbers(int32* major_version,
}
// static
-int64 SysInfo::AmountOfPhysicalMemory() {
+int64_t SysInfo::AmountOfPhysicalMemory() {
struct host_basic_info hostinfo;
mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT;
base::mac::ScopedMachSendRight host(mach_host_self());
- int result = host_info(host,
+ int result = host_info(host.get(),
HOST_BASIC_INFO,
reinterpret_cast<host_info_t>(&hostinfo),
&count);
@@ -75,11 +78,11 @@ int64 SysInfo::AmountOfPhysicalMemory() {
return 0;
}
DCHECK_EQ(HOST_BASIC_INFO_COUNT, count);
- return static_cast<int64>(hostinfo.max_mem);
+ return static_cast<int64_t>(hostinfo.max_mem);
}
// static
-int64 SysInfo::AmountOfAvailablePhysicalMemory() {
+int64_t SysInfo::AmountOfAvailablePhysicalMemory() {
base::mac::ScopedMachSendRight host(mach_host_self());
vm_statistics_data_t vm_info;
mach_msg_type_number_t count = HOST_VM_INFO_COUNT;
@@ -91,8 +94,8 @@ int64 SysInfo::AmountOfAvailablePhysicalMemory() {
return 0;
}
- return static_cast<int64>(
- vm_info.free_count - vm_info.speculative_count) * PAGE_SIZE;
+ return static_cast<int64_t>(vm_info.free_count - vm_info.speculative_count) *
+ PAGE_SIZE;
}
// static
diff --git a/chromium/base/sys_info_linux.cc b/chromium/base/sys_info_linux.cc
index 1bbfe9c604e..8e1f533bed7 100644
--- a/chromium/base/sys_info_linux.cc
+++ b/chromium/base/sys_info_linux.cc
@@ -4,6 +4,9 @@
#include "base/sys_info.h"
+#include <stddef.h>
+#include <stdint.h>
+
#include <limits>
#include "base/files/file_util.h"
@@ -12,24 +15,25 @@
#include "base/numerics/safe_conversions.h"
#include "base/strings/string_number_conversions.h"
#include "base/sys_info_internal.h"
+#include "build/build_config.h"
namespace {
-int64 AmountOfMemory(int pages_name) {
+int64_t AmountOfMemory(int pages_name) {
long pages = sysconf(pages_name);
long page_size = sysconf(_SC_PAGESIZE);
if (pages == -1 || page_size == -1) {
NOTREACHED();
return 0;
}
- return static_cast<int64>(pages) * page_size;
+ return static_cast<int64_t>(pages) * page_size;
}
-int64 AmountOfPhysicalMemory() {
+int64_t AmountOfPhysicalMemory() {
return AmountOfMemory(_SC_PHYS_PAGES);
}
-uint64 MaxSharedMemorySize() {
+uint64_t MaxSharedMemorySize() {
std::string contents;
base::ReadFileToString(base::FilePath("/proc/sys/kernel/shmmax"), &contents);
DCHECK(!contents.empty());
@@ -37,7 +41,7 @@ uint64 MaxSharedMemorySize() {
contents.erase(contents.length() - 1);
}
- uint64 limit;
+ uint64_t limit;
if (!base::StringToUint64(contents, &limit)) {
limit = 0;
}
@@ -46,10 +50,10 @@ uint64 MaxSharedMemorySize() {
}
base::LazyInstance<
- base::internal::LazySysInfoValue<int64, AmountOfPhysicalMemory> >::Leaky
+ base::internal::LazySysInfoValue<int64_t, AmountOfPhysicalMemory>>::Leaky
g_lazy_physical_memory = LAZY_INSTANCE_INITIALIZER;
base::LazyInstance<
- base::internal::LazySysInfoValue<uint64, MaxSharedMemorySize> >::Leaky
+ base::internal::LazySysInfoValue<uint64_t, MaxSharedMemorySize>>::Leaky
g_lazy_max_shared_memory = LAZY_INSTANCE_INITIALIZER;
} // namespace
@@ -57,17 +61,17 @@ base::LazyInstance<
namespace base {
// static
-int64 SysInfo::AmountOfAvailablePhysicalMemory() {
+int64_t SysInfo::AmountOfAvailablePhysicalMemory() {
return AmountOfMemory(_SC_AVPHYS_PAGES);
}
// static
-int64 SysInfo::AmountOfPhysicalMemory() {
+int64_t SysInfo::AmountOfPhysicalMemory() {
return g_lazy_physical_memory.Get().value();
}
// static
-uint64 SysInfo::MaxSharedMemorySize() {
+uint64_t SysInfo::MaxSharedMemorySize() {
return g_lazy_max_shared_memory.Get().value();
}
diff --git a/chromium/base/sys_info_mac.cc b/chromium/base/sys_info_mac.cc
index 18df62482ea..ff1ec5c1e69 100644
--- a/chromium/base/sys_info_mac.cc
+++ b/chromium/base/sys_info_mac.cc
@@ -8,11 +8,14 @@
#include <CoreServices/CoreServices.h>
#include <mach/mach_host.h>
#include <mach/mach_init.h>
+#include <stddef.h>
+#include <stdint.h>
#include <sys/sysctl.h>
#include <sys/types.h>
#include "base/logging.h"
#include "base/mac/scoped_mach_port.h"
+#include "base/macros.h"
#include "base/strings/stringprintf.h"
namespace base {
@@ -24,15 +27,15 @@ std::string SysInfo::OperatingSystemName() {
// static
std::string SysInfo::OperatingSystemVersion() {
- int32 major, minor, bugfix;
+ int32_t major, minor, bugfix;
OperatingSystemVersionNumbers(&major, &minor, &bugfix);
return base::StringPrintf("%d.%d.%d", major, minor, bugfix);
}
// static
-void SysInfo::OperatingSystemVersionNumbers(int32* major_version,
- int32* minor_version,
- int32* bugfix_version) {
+void SysInfo::OperatingSystemVersionNumbers(int32_t* major_version,
+ int32_t* minor_version,
+ int32_t* bugfix_version) {
Gestalt(gestaltSystemVersionMajor,
reinterpret_cast<SInt32*>(major_version));
Gestalt(gestaltSystemVersionMinor,
@@ -42,11 +45,11 @@ void SysInfo::OperatingSystemVersionNumbers(int32* major_version,
}
// static
-int64 SysInfo::AmountOfPhysicalMemory() {
+int64_t SysInfo::AmountOfPhysicalMemory() {
struct host_basic_info hostinfo;
mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT;
base::mac::ScopedMachSendRight host(mach_host_self());
- int result = host_info(host,
+ int result = host_info(host.get(),
HOST_BASIC_INFO,
reinterpret_cast<host_info_t>(&hostinfo),
&count);
@@ -55,11 +58,11 @@ int64 SysInfo::AmountOfPhysicalMemory() {
return 0;
}
DCHECK_EQ(HOST_BASIC_INFO_COUNT, count);
- return static_cast<int64>(hostinfo.max_mem);
+ return static_cast<int64_t>(hostinfo.max_mem);
}
// static
-int64 SysInfo::AmountOfAvailablePhysicalMemory() {
+int64_t SysInfo::AmountOfAvailablePhysicalMemory() {
base::mac::ScopedMachSendRight host(mach_host_self());
vm_statistics_data_t vm_info;
mach_msg_type_number_t count = HOST_VM_INFO_COUNT;
@@ -72,8 +75,8 @@ int64 SysInfo::AmountOfAvailablePhysicalMemory() {
return 0;
}
- return static_cast<int64>(
- vm_info.free_count - vm_info.speculative_count) * PAGE_SIZE;
+ return static_cast<int64_t>(vm_info.free_count - vm_info.speculative_count) *
+ PAGE_SIZE;
}
// static
diff --git a/chromium/base/sys_info_openbsd.cc b/chromium/base/sys_info_openbsd.cc
index 595291b0e01..531c11733b6 100644
--- a/chromium/base/sys_info_openbsd.cc
+++ b/chromium/base/sys_info_openbsd.cc
@@ -4,22 +4,25 @@
#include "base/sys_info.h"
+#include <stddef.h>
+#include <stdint.h>
#include <sys/param.h>
#include <sys/shm.h>
#include <sys/sysctl.h>
#include "base/logging.h"
+#include "base/macros.h"
namespace {
-int64 AmountOfMemory(int pages_name) {
+int64_t AmountOfMemory(int pages_name) {
long pages = sysconf(pages_name);
long page_size = sysconf(_SC_PAGESIZE);
if (pages == -1 || page_size == -1) {
NOTREACHED();
return 0;
}
- return static_cast<int64>(pages) * page_size;
+ return static_cast<int64_t>(pages) * page_size;
}
} // namespace
@@ -39,17 +42,17 @@ int SysInfo::NumberOfProcessors() {
}
// static
-int64 SysInfo::AmountOfPhysicalMemory() {
+int64_t SysInfo::AmountOfPhysicalMemory() {
return AmountOfMemory(_SC_PHYS_PAGES);
}
// static
-int64 SysInfo::AmountOfAvailablePhysicalMemory() {
+int64_t SysInfo::AmountOfAvailablePhysicalMemory() {
return AmountOfMemory(_SC_AVPHYS_PAGES);
}
// static
-uint64 SysInfo::MaxSharedMemorySize() {
+uint64_t SysInfo::MaxSharedMemorySize() {
int mib[] = { CTL_KERN, KERN_SHMINFO, KERN_SHMINFO_SHMMAX };
size_t limit;
size_t size = sizeof(limit);
@@ -57,7 +60,7 @@ uint64 SysInfo::MaxSharedMemorySize() {
NOTREACHED();
return 0;
}
- return static_cast<uint64>(limit);
+ return static_cast<uint64_t>(limit);
}
// static
diff --git a/chromium/base/sys_info_posix.cc b/chromium/base/sys_info_posix.cc
index 3d49bf94da9..85ae0391189 100644
--- a/chromium/base/sys_info_posix.cc
+++ b/chromium/base/sys_info_posix.cc
@@ -5,19 +5,21 @@
#include "base/sys_info.h"
#include <errno.h>
+#include <stddef.h>
+#include <stdint.h>
#include <string.h>
#include <sys/param.h>
#include <sys/resource.h>
#include <sys/utsname.h>
#include <unistd.h>
-#include "base/basictypes.h"
#include "base/files/file_util.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
#include "base/sys_info_internal.h"
#include "base/threading/thread_restrictions.h"
+#include "build/build_config.h"
#if defined(OS_ANDROID)
#include <sys/vfs.h>
@@ -57,7 +59,7 @@ base::LazyInstance<
g_lazy_number_of_processors = LAZY_INSTANCE_INITIALIZER;
#endif
-int64 AmountOfVirtualMemory() {
+int64_t AmountOfVirtualMemory() {
struct rlimit limit;
int result = getrlimit(RLIMIT_DATA, &limit);
if (result != 0) {
@@ -68,7 +70,7 @@ int64 AmountOfVirtualMemory() {
}
base::LazyInstance<
- base::internal::LazySysInfoValue<int64, AmountOfVirtualMemory> >::Leaky
+ base::internal::LazySysInfoValue<int64_t, AmountOfVirtualMemory>>::Leaky
g_lazy_virtual_memory = LAZY_INSTANCE_INITIALIZER;
} // namespace
@@ -82,18 +84,18 @@ int SysInfo::NumberOfProcessors() {
#endif
// static
-int64 SysInfo::AmountOfVirtualMemory() {
+int64_t SysInfo::AmountOfVirtualMemory() {
return g_lazy_virtual_memory.Get().value();
}
// static
-int64 SysInfo::AmountOfFreeDiskSpace(const FilePath& path) {
+int64_t SysInfo::AmountOfFreeDiskSpace(const FilePath& path) {
base::ThreadRestrictions::AssertIOAllowed();
struct statvfs stats;
if (HANDLE_EINTR(statvfs(path.value().c_str(), &stats)) != 0)
return -1;
- return static_cast<int64>(stats.f_bavail) * stats.f_frsize;
+ return static_cast<int64_t>(stats.f_bavail) * stats.f_frsize;
}
#if !defined(OS_MACOSX) && !defined(OS_ANDROID)
diff --git a/chromium/base/sys_info_unittest.cc b/chromium/base/sys_info_unittest.cc
index 15ae0989b1d..3f284ba8684 100644
--- a/chromium/base/sys_info_unittest.cc
+++ b/chromium/base/sys_info_unittest.cc
@@ -2,11 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stdint.h>
+
#include "base/environment.h"
#include "base/files/file_util.h"
#include "base/sys_info.h"
#include "base/threading/platform_thread.h"
#include "base/time/time.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
@@ -43,9 +46,9 @@ TEST_F(SysInfoTest, AmountOfFreeDiskSpace) {
#if defined(OS_WIN) || defined(OS_MACOSX)
TEST_F(SysInfoTest, OperatingSystemVersionNumbers) {
- int32 os_major_version = -1;
- int32 os_minor_version = -1;
- int32 os_bugfix_version = -1;
+ int32_t os_major_version = -1;
+ int32_t os_minor_version = -1;
+ int32_t os_bugfix_version = -1;
base::SysInfo::OperatingSystemVersionNumbers(&os_major_version,
&os_minor_version,
&os_bugfix_version);
@@ -56,13 +59,13 @@ TEST_F(SysInfoTest, OperatingSystemVersionNumbers) {
#endif
TEST_F(SysInfoTest, Uptime) {
- int64 up_time_1 = base::SysInfo::Uptime();
+ base::TimeDelta up_time_1 = base::SysInfo::Uptime();
// UpTime() is implemented internally using TimeTicks::Now(), which documents
// system resolution as being 1-15ms. Sleep a little longer than that.
base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(20));
- int64 up_time_2 = base::SysInfo::Uptime();
- EXPECT_GT(up_time_1, 0);
- EXPECT_GT(up_time_2, up_time_1);
+ base::TimeDelta up_time_2 = base::SysInfo::Uptime();
+ EXPECT_GT(up_time_1.InMicroseconds(), 0);
+ EXPECT_GT(up_time_2.InMicroseconds(), up_time_1.InMicroseconds());
}
#if defined(OS_MACOSX) && !defined(OS_IOS)
@@ -75,9 +78,9 @@ TEST_F(SysInfoTest, HardwareModelName) {
#if defined(OS_CHROMEOS)
TEST_F(SysInfoTest, GoogleChromeOSVersionNumbers) {
- int32 os_major_version = -1;
- int32 os_minor_version = -1;
- int32 os_bugfix_version = -1;
+ int32_t os_major_version = -1;
+ int32_t os_minor_version = -1;
+ int32_t os_bugfix_version = -1;
const char kLsbRelease[] =
"FOO=1234123.34.5\n"
"CHROMEOS_RELEASE_VERSION=1.2.3.4\n";
@@ -91,9 +94,9 @@ TEST_F(SysInfoTest, GoogleChromeOSVersionNumbers) {
}
TEST_F(SysInfoTest, GoogleChromeOSVersionNumbersFirst) {
- int32 os_major_version = -1;
- int32 os_minor_version = -1;
- int32 os_bugfix_version = -1;
+ int32_t os_major_version = -1;
+ int32_t os_minor_version = -1;
+ int32_t os_bugfix_version = -1;
const char kLsbRelease[] =
"CHROMEOS_RELEASE_VERSION=1.2.3.4\n"
"FOO=1234123.34.5\n";
@@ -107,9 +110,9 @@ TEST_F(SysInfoTest, GoogleChromeOSVersionNumbersFirst) {
}
TEST_F(SysInfoTest, GoogleChromeOSNoVersionNumbers) {
- int32 os_major_version = -1;
- int32 os_minor_version = -1;
- int32 os_bugfix_version = -1;
+ int32_t os_major_version = -1;
+ int32_t os_minor_version = -1;
+ int32_t os_bugfix_version = -1;
const char kLsbRelease[] = "FOO=1234123.34.5\n";
base::SysInfo::SetChromeOSVersionInfoForTest(kLsbRelease, base::Time());
base::SysInfo::OperatingSystemVersionNumbers(&os_major_version,
diff --git a/chromium/base/sys_info_win.cc b/chromium/base/sys_info_win.cc
index c8314c7a6a9..e2da617cf55 100644
--- a/chromium/base/sys_info_win.cc
+++ b/chromium/base/sys_info_win.cc
@@ -5,6 +5,10 @@
#include "base/sys_info.h"
#include <windows.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <limits>
#include "base/files/file_path.h"
#include "base/logging.h"
@@ -15,7 +19,7 @@
namespace {
-int64 AmountOfMemory(DWORDLONG MEMORYSTATUSEX::* memory_field) {
+int64_t AmountOfMemory(DWORDLONG MEMORYSTATUSEX::*memory_field) {
MEMORYSTATUSEX memory_info;
memory_info.dwLength = sizeof(memory_info);
if (!GlobalMemoryStatusEx(&memory_info)) {
@@ -23,8 +27,8 @@ int64 AmountOfMemory(DWORDLONG MEMORYSTATUSEX::* memory_field) {
return 0;
}
- int64 rv = static_cast<int64>(memory_info.*memory_field);
- return rv < 0 ? kint64max : rv;
+ int64_t rv = static_cast<int64_t>(memory_info.*memory_field);
+ return rv < 0 ? std::numeric_limits<int64_t>::max() : rv;
}
} // namespace
@@ -37,30 +41,30 @@ int SysInfo::NumberOfProcessors() {
}
// static
-int64 SysInfo::AmountOfPhysicalMemory() {
+int64_t SysInfo::AmountOfPhysicalMemory() {
return AmountOfMemory(&MEMORYSTATUSEX::ullTotalPhys);
}
// static
-int64 SysInfo::AmountOfAvailablePhysicalMemory() {
+int64_t SysInfo::AmountOfAvailablePhysicalMemory() {
return AmountOfMemory(&MEMORYSTATUSEX::ullAvailPhys);
}
// static
-int64 SysInfo::AmountOfVirtualMemory() {
- return 0;
+int64_t SysInfo::AmountOfVirtualMemory() {
+ return AmountOfMemory(&MEMORYSTATUSEX::ullTotalVirtual);
}
// static
-int64 SysInfo::AmountOfFreeDiskSpace(const FilePath& path) {
+int64_t SysInfo::AmountOfFreeDiskSpace(const FilePath& path) {
ThreadRestrictions::AssertIOAllowed();
ULARGE_INTEGER available, total, free;
if (!GetDiskFreeSpaceExW(path.value().c_str(), &available, &total, &free))
return -1;
- int64 rv = static_cast<int64>(available.QuadPart);
- return rv < 0 ? kint64max : rv;
+ int64_t rv = static_cast<int64_t>(available.QuadPart);
+ return rv < 0 ? std::numeric_limits<int64_t>::max() : rv;
}
std::string SysInfo::OperatingSystemName() {
@@ -113,9 +117,9 @@ size_t SysInfo::VMAllocationGranularity() {
}
// static
-void SysInfo::OperatingSystemVersionNumbers(int32* major_version,
- int32* minor_version,
- int32* bugfix_version) {
+void SysInfo::OperatingSystemVersionNumbers(int32_t* major_version,
+ int32_t* minor_version,
+ int32_t* bugfix_version) {
win::OSInfo* os_info = win::OSInfo::GetInstance();
*major_version = os_info->version_number().major;
*minor_version = os_info->version_number().minor;
diff --git a/chromium/base/system_monitor/system_monitor.h b/chromium/base/system_monitor/system_monitor.h
index 5dd849f5e3e..8cfe5e94ec1 100644
--- a/chromium/base/system_monitor/system_monitor.h
+++ b/chromium/base/system_monitor/system_monitor.h
@@ -6,7 +6,7 @@
#define BASE_SYSTEM_MONITOR_SYSTEM_MONITOR_H_
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/observer_list_threadsafe.h"
#include "build/build_config.h"
diff --git a/chromium/base/system_monitor/system_monitor_unittest.cc b/chromium/base/system_monitor/system_monitor_unittest.cc
index f3db4c77c94..a874f8bfa45 100644
--- a/chromium/base/system_monitor/system_monitor_unittest.cc
+++ b/chromium/base/system_monitor/system_monitor_unittest.cc
@@ -4,6 +4,7 @@
#include "base/system_monitor/system_monitor.h"
+#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/test/mock_devices_changed_observer.h"
diff --git a/chromium/base/task/cancelable_task_tracker.cc b/chromium/base/task/cancelable_task_tracker.cc
index a2e4799f438..a756f4ec3ee 100644
--- a/chromium/base/task/cancelable_task_tracker.cc
+++ b/chromium/base/task/cancelable_task_tracker.cc
@@ -4,6 +4,8 @@
#include "base/task/cancelable_task_tracker.h"
+#include <stddef.h>
+
#include <utility>
#include "base/bind.h"
@@ -92,7 +94,7 @@ CancelableTaskTracker::TaskId CancelableTaskTracker::PostTaskAndReply(
CancellationFlag* flag = new CancellationFlag();
TaskId id = next_id_;
- next_id_++; // int64 is big enough that we ignore the potential overflow.
+ next_id_++; // int64_t is big enough that we ignore the potential overflow.
const Closure& untrack_closure =
Bind(&CancelableTaskTracker::Untrack, weak_factory_.GetWeakPtr(), id);
@@ -117,7 +119,7 @@ CancelableTaskTracker::TaskId CancelableTaskTracker::NewTrackedTaskId(
DCHECK(base::ThreadTaskRunnerHandle::IsSet());
TaskId id = next_id_;
- next_id_++; // int64 is big enough that we ignore the potential overflow.
+ next_id_++; // int64_t is big enough that we ignore the potential overflow.
// Will be deleted by |untrack_and_delete_flag| after Untrack().
CancellationFlag* flag = new CancellationFlag();
diff --git a/chromium/base/task/cancelable_task_tracker.h b/chromium/base/task/cancelable_task_tracker.h
index b8a8b70e333..86b5a458450 100644
--- a/chromium/base/task/cancelable_task_tracker.h
+++ b/chromium/base/task/cancelable_task_tracker.h
@@ -36,10 +36,12 @@
#ifndef BASE_TASK_CANCELABLE_TASK_TRACKER_H_
#define BASE_TASK_CANCELABLE_TASK_TRACKER_H_
+#include <stdint.h>
+
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/callback.h"
#include "base/containers/hash_tables.h"
+#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/task_runner_util.h"
#include "base/threading/thread_checker.h"
@@ -56,7 +58,7 @@ class TaskRunner;
class BASE_EXPORT CancelableTaskTracker {
public:
// All values except kBadTaskId are valid.
- typedef int64 TaskId;
+ typedef int64_t TaskId;
static const TaskId kBadTaskId;
typedef base::Callback<bool()> IsCanceledCallback;
diff --git a/chromium/base/task_runner.h b/chromium/base/task_runner.h
index 6369c4f65fa..6dd82ccaca9 100644
--- a/chromium/base/task_runner.h
+++ b/chromium/base/task_runner.h
@@ -5,8 +5,9 @@
#ifndef BASE_TASK_RUNNER_H_
#define BASE_TASK_RUNNER_H_
+#include <stddef.h>
+
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/callback_forward.h"
#include "base/memory/ref_counted.h"
#include "base/time/time.h"
diff --git a/chromium/base/task_runner_util_unittest.cc b/chromium/base/task_runner_util_unittest.cc
index 8245cfcdc50..0a4f22e5ae8 100644
--- a/chromium/base/task_runner_util_unittest.cc
+++ b/chromium/base/task_runner_util_unittest.cc
@@ -4,6 +4,8 @@
#include "base/task_runner_util.h"
+#include <utility>
+
#include "base/bind.h"
#include "base/location.h"
#include "base/run_loop.h"
@@ -40,7 +42,7 @@ scoped_ptr<Foo> CreateFoo() {
void ExpectFoo(scoped_ptr<Foo> foo) {
EXPECT_TRUE(foo.get());
- scoped_ptr<Foo> local_foo(foo.Pass());
+ scoped_ptr<Foo> local_foo(std::move(foo));
EXPECT_TRUE(local_foo.get());
EXPECT_FALSE(foo.get());
}
@@ -58,7 +60,7 @@ scoped_ptr<Foo, FooDeleter> CreateScopedFoo() {
void ExpectScopedFoo(scoped_ptr<Foo, FooDeleter> foo) {
EXPECT_TRUE(foo.get());
- scoped_ptr<Foo, FooDeleter> local_foo(foo.Pass());
+ scoped_ptr<Foo, FooDeleter> local_foo(std::move(foo));
EXPECT_TRUE(local_foo.get());
EXPECT_FALSE(foo.get());
}
diff --git a/chromium/base/template_util.h b/chromium/base/template_util.h
index 83fa322a672..d58807a77ce 100644
--- a/chromium/base/template_util.h
+++ b/chromium/base/template_util.h
@@ -5,7 +5,7 @@
#ifndef BASE_TEMPLATE_UTIL_H_
#define BASE_TEMPLATE_UTIL_H_
-#include <cstddef> // For size_t.
+#include <stddef.h>
#include "build/build_config.h"
@@ -117,12 +117,6 @@ struct is_class
sizeof(internal::YesType)> {
};
-template<bool B, class T = void>
-struct enable_if {};
-
-template<class T>
-struct enable_if<true, T> { typedef T type; };
-
} // namespace base
#endif // BASE_TEMPLATE_UTIL_H_
diff --git a/chromium/base/template_util_unittest.cc b/chromium/base/template_util_unittest.cc
index 3ec3887154d..b960ab1ceac 100644
--- a/chromium/base/template_util_unittest.cc
+++ b/chromium/base/template_util_unittest.cc
@@ -4,7 +4,6 @@
#include "base/template_util.h"
-#include "base/basictypes.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
@@ -18,23 +17,24 @@ class Parent {};
class Child : public Parent {};
// is_pointer<Type>
-COMPILE_ASSERT(!is_pointer<int>::value, IsPointer);
-COMPILE_ASSERT(!is_pointer<int&>::value, IsPointer);
-COMPILE_ASSERT(is_pointer<int*>::value, IsPointer);
-COMPILE_ASSERT(is_pointer<const int*>::value, IsPointer);
+static_assert(!is_pointer<int>::value, "IsPointer");
+static_assert(!is_pointer<int&>::value, "IsPointer");
+static_assert(is_pointer<int*>::value, "IsPointer");
+static_assert(is_pointer<const int*>::value, "IsPointer");
// is_array<Type>
-COMPILE_ASSERT(!is_array<int>::value, IsArray);
-COMPILE_ASSERT(!is_array<int*>::value, IsArray);
-COMPILE_ASSERT(!is_array<int(*)[3]>::value, IsArray);
-COMPILE_ASSERT(is_array<int[]>::value, IsArray);
-COMPILE_ASSERT(is_array<const int[]>::value, IsArray);
-COMPILE_ASSERT(is_array<int[3]>::value, IsArray);
+static_assert(!is_array<int>::value, "IsArray");
+static_assert(!is_array<int*>::value, "IsArray");
+static_assert(!is_array<int (*)[3]>::value, "IsArray");
+static_assert(is_array<int[]>::value, "IsArray");
+static_assert(is_array<const int[]>::value, "IsArray");
+static_assert(is_array<int[3]>::value, "IsArray");
// is_non_const_reference<Type>
-COMPILE_ASSERT(!is_non_const_reference<int>::value, IsNonConstReference);
-COMPILE_ASSERT(!is_non_const_reference<const int&>::value, IsNonConstReference);
-COMPILE_ASSERT(is_non_const_reference<int&>::value, IsNonConstReference);
+static_assert(!is_non_const_reference<int>::value, "IsNonConstReference");
+static_assert(!is_non_const_reference<const int&>::value,
+ "IsNonConstReference");
+static_assert(is_non_const_reference<int&>::value, "IsNonConstReference");
// is_convertible<From, To>
@@ -44,66 +44,64 @@ COMPILE_ASSERT(is_non_const_reference<int&>::value, IsNonConstReference);
// (is_convertible < Child), (Parent > ::value)
//
// Silly C++.
-COMPILE_ASSERT( (is_convertible<Child, Parent>::value), IsConvertible);
-COMPILE_ASSERT(!(is_convertible<Parent, Child>::value), IsConvertible);
-COMPILE_ASSERT(!(is_convertible<Parent, AStruct>::value), IsConvertible);
-COMPILE_ASSERT( (is_convertible<int, double>::value), IsConvertible);
-COMPILE_ASSERT( (is_convertible<int*, void*>::value), IsConvertible);
-COMPILE_ASSERT(!(is_convertible<void*, int*>::value), IsConvertible);
+static_assert((is_convertible<Child, Parent>::value), "IsConvertible");
+static_assert(!(is_convertible<Parent, Child>::value), "IsConvertible");
+static_assert(!(is_convertible<Parent, AStruct>::value), "IsConvertible");
+static_assert((is_convertible<int, double>::value), "IsConvertible");
+static_assert((is_convertible<int*, void*>::value), "IsConvertible");
+static_assert(!(is_convertible<void*, int*>::value), "IsConvertible");
// Array types are an easy corner case. Make sure to test that
// it does indeed compile.
-COMPILE_ASSERT(!(is_convertible<int[10], double>::value), IsConvertible);
-COMPILE_ASSERT(!(is_convertible<double, int[10]>::value), IsConvertible);
-COMPILE_ASSERT( (is_convertible<int[10], int*>::value), IsConvertible);
+static_assert(!(is_convertible<int[10], double>::value), "IsConvertible");
+static_assert(!(is_convertible<double, int[10]>::value), "IsConvertible");
+static_assert((is_convertible<int[10], int*>::value), "IsConvertible");
// is_same<Type1, Type2>
-COMPILE_ASSERT(!(is_same<Child, Parent>::value), IsSame);
-COMPILE_ASSERT(!(is_same<Parent, Child>::value), IsSame);
-COMPILE_ASSERT( (is_same<Parent, Parent>::value), IsSame);
-COMPILE_ASSERT( (is_same<int*, int*>::value), IsSame);
-COMPILE_ASSERT( (is_same<int, int>::value), IsSame);
-COMPILE_ASSERT( (is_same<void, void>::value), IsSame);
-COMPILE_ASSERT(!(is_same<int, double>::value), IsSame);
-
+static_assert(!(is_same<Child, Parent>::value), "IsSame");
+static_assert(!(is_same<Parent, Child>::value), "IsSame");
+static_assert((is_same<Parent, Parent>::value), "IsSame");
+static_assert((is_same<int*, int*>::value), "IsSame");
+static_assert((is_same<int, int>::value), "IsSame");
+static_assert((is_same<void, void>::value), "IsSame");
+static_assert(!(is_same<int, double>::value), "IsSame");
// is_class<Type>
-COMPILE_ASSERT(is_class<AStruct>::value, IsClass);
-COMPILE_ASSERT(is_class<AClass>::value, IsClass);
-COMPILE_ASSERT(!is_class<AnEnum>::value, IsClass);
-COMPILE_ASSERT(!is_class<int>::value, IsClass);
-COMPILE_ASSERT(!is_class<char*>::value, IsClass);
-COMPILE_ASSERT(!is_class<int&>::value, IsClass);
-COMPILE_ASSERT(!is_class<char[3]>::value, IsClass);
-
-
-COMPILE_ASSERT(!is_member_function_pointer<int>::value,
- IsMemberFunctionPointer);
-COMPILE_ASSERT(!is_member_function_pointer<int*>::value,
- IsMemberFunctionPointer);
-COMPILE_ASSERT(!is_member_function_pointer<void*>::value,
- IsMemberFunctionPointer);
-COMPILE_ASSERT(!is_member_function_pointer<AStruct>::value,
- IsMemberFunctionPointer);
-COMPILE_ASSERT(!is_member_function_pointer<AStruct*>::value,
- IsMemberFunctionPointer);
-COMPILE_ASSERT(!is_member_function_pointer<void(*)()>::value,
- IsMemberFunctionPointer);
-COMPILE_ASSERT(!is_member_function_pointer<int(*)(int)>::value,
- IsMemberFunctionPointer);
-COMPILE_ASSERT(!is_member_function_pointer<int(*)(int, int)>::value,
- IsMemberFunctionPointer);
-
-COMPILE_ASSERT(is_member_function_pointer<void (AStruct::*)()>::value,
- IsMemberFunctionPointer);
-COMPILE_ASSERT(is_member_function_pointer<void (AStruct::*)(int)>::value,
- IsMemberFunctionPointer);
-COMPILE_ASSERT(is_member_function_pointer<int (AStruct::*)(int)>::value,
- IsMemberFunctionPointer);
-COMPILE_ASSERT(is_member_function_pointer<int (AStruct::*)(int) const>::value,
- IsMemberFunctionPointer);
-COMPILE_ASSERT(is_member_function_pointer<int (AStruct::*)(int, int)>::value,
- IsMemberFunctionPointer);
+static_assert(is_class<AStruct>::value, "IsClass");
+static_assert(is_class<AClass>::value, "IsClass");
+static_assert(!is_class<AnEnum>::value, "IsClass");
+static_assert(!is_class<int>::value, "IsClass");
+static_assert(!is_class<char*>::value, "IsClass");
+static_assert(!is_class<int&>::value, "IsClass");
+static_assert(!is_class<char[3]>::value, "IsClass");
+
+static_assert(!is_member_function_pointer<int>::value,
+ "IsMemberFunctionPointer");
+static_assert(!is_member_function_pointer<int*>::value,
+ "IsMemberFunctionPointer");
+static_assert(!is_member_function_pointer<void*>::value,
+ "IsMemberFunctionPointer");
+static_assert(!is_member_function_pointer<AStruct>::value,
+ "IsMemberFunctionPointer");
+static_assert(!is_member_function_pointer<AStruct*>::value,
+ "IsMemberFunctionPointer");
+static_assert(!is_member_function_pointer<void (*)()>::value,
+ "IsMemberFunctionPointer");
+static_assert(!is_member_function_pointer<int (*)(int)>::value,
+ "IsMemberFunctionPointer");
+static_assert(!is_member_function_pointer<int (*)(int, int)>::value,
+ "IsMemberFunctionPointer");
+
+static_assert(is_member_function_pointer<void (AStruct::*)()>::value,
+ "IsMemberFunctionPointer");
+static_assert(is_member_function_pointer<void (AStruct::*)(int)>::value,
+ "IsMemberFunctionPointer");
+static_assert(is_member_function_pointer<int (AStruct::*)(int)>::value,
+ "IsMemberFunctionPointer");
+static_assert(is_member_function_pointer<int (AStruct::*)(int) const>::value,
+ "IsMemberFunctionPointer");
+static_assert(is_member_function_pointer<int (AStruct::*)(int, int)>::value,
+ "IsMemberFunctionPointer");
} // namespace
} // namespace base
diff --git a/chromium/base/third_party/dynamic_annotations/BUILD.gn b/chromium/base/third_party/dynamic_annotations/BUILD.gn
index 86f6558401a..0fc4bf74081 100644
--- a/chromium/base/third_party/dynamic_annotations/BUILD.gn
+++ b/chromium/base/third_party/dynamic_annotations/BUILD.gn
@@ -12,7 +12,8 @@ if (is_nacl) {
]
}
} else {
- source_set("dynamic_annotations") {
+ # Should be static library, see documentation on //base:base for discussion.
+ static_library("dynamic_annotations") {
sources = [
"../valgrind/valgrind.h",
"dynamic_annotations.c",
diff --git a/chromium/base/third_party/icu/icu_utf.cc b/chromium/base/third_party/icu/icu_utf.cc
index b47c8ac3c11..2b67c5d9c21 100644
--- a/chromium/base/third_party/icu/icu_utf.cc
+++ b/chromium/base/third_party/icu/icu_utf.cc
@@ -74,32 +74,28 @@ namespace base_icu {
* lead bytes above 0xf4 are illegal.
* We keep them in this table for skipping long ISO 10646-UTF-8 sequences.
*/
-const uint8
-utf8_countTrailBytes[256]={
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-
- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
- 3, 3, 3, 3, 3,
- 3, 3, 3, /* illegal in Unicode */
- 4, 4, 4, 4, /* illegal in Unicode */
- 5, 5, /* illegal in Unicode */
- 0, 0 /* illegal bytes 0xfe and 0xff */
+const uint8_t utf8_countTrailBytes[256] =
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3,
+ 3, 3, /* illegal in Unicode */
+ 4, 4, 4, 4, /* illegal in Unicode */
+ 5, 5, /* illegal in Unicode */
+ 0, 0 /* illegal bytes 0xfe and 0xff */
};
static const UChar32
@@ -133,12 +129,15 @@ utf8_errorValue[6]={
*
* Note that a UBool is the same as an int8_t.
*/
-UChar32
-utf8_nextCharSafeBody(const uint8 *s, int32 *pi, int32 length, UChar32 c, UBool strict) {
- int32 i=*pi;
- uint8 count=CBU8_COUNT_TRAIL_BYTES(c);
+UChar32 utf8_nextCharSafeBody(const uint8_t* s,
+ int32_t* pi,
+ int32_t length,
+ UChar32 c,
+ UBool strict) {
+ int32_t i = *pi;
+ uint8_t count = CBU8_COUNT_TRAIL_BYTES(c);
if((i)+count<=(length)) {
- uint8 trail, illegal=0;
+ uint8_t trail, illegal = 0;
CBU8_MASK_LEAD_BYTE((c), count);
/* count==0 for illegally leading trail bytes and the illegal bytes 0xfe and 0xff */
@@ -192,7 +191,7 @@ utf8_nextCharSafeBody(const uint8 *s, int32 *pi, int32 length, UChar32 c, UBool
/* illegal is also set if count>=4 */
if(illegal || (c)<utf8_minLegal[count] || (CBU_IS_SURROGATE(c) && strict!=-2)) {
/* error handling */
- uint8 errorCount=count;
+ uint8_t errorCount = count;
/* don't go beyond this sequence */
i=*pi;
while(count>0 && CBU8_IS_TRAIL(s[i])) {
@@ -210,7 +209,7 @@ utf8_nextCharSafeBody(const uint8 *s, int32 *pi, int32 length, UChar32 c, UBool
}
} else /* too few bytes left */ {
/* error handling */
- int32 i0=i;
+ int32_t i0 = i;
/* don't just set (i)=(length) in case there is an illegal sequence */
while((i)<(length) && CBU8_IS_TRAIL(s[i])) {
++(i);
diff --git a/chromium/base/third_party/icu/icu_utf.h b/chromium/base/third_party/icu/icu_utf.h
index 2b993b099f8..4370fdec15e 100644
--- a/chromium/base/third_party/icu/icu_utf.h
+++ b/chromium/base/third_party/icu/icu_utf.h
@@ -17,13 +17,13 @@
#ifndef BASE_THIRD_PARTY_ICU_ICU_UTF_H_
#define BASE_THIRD_PARTY_ICU_ICU_UTF_H_
-#include "base/basictypes.h"
+#include <stdint.h>
namespace base_icu {
-typedef int32 UChar32;
-typedef uint16 UChar;
-typedef int8 UBool;
+typedef int32_t UChar32;
+typedef uint16_t UChar;
+typedef int8_t UBool;
// General ---------------------------------------------------------------------
// from utf.h
@@ -54,10 +54,9 @@ typedef int8 UBool;
* @return TRUE or FALSE
* @stable ICU 2.4
*/
-#define CBU_IS_UNICODE_NONCHAR(c) \
- ((c)>=0xfdd0 && \
- ((uint32)(c)<=0xfdef || ((c)&0xfffe)==0xfffe) && \
- (uint32)(c)<=0x10ffff)
+#define CBU_IS_UNICODE_NONCHAR(c) \
+ ((c) >= 0xfdd0 && ((uint32_t)(c) <= 0xfdef || ((c)&0xfffe) == 0xfffe) && \
+ (uint32_t)(c) <= 0x10ffff)
/**
* Is c a Unicode code point value (0..U+10ffff)
@@ -76,11 +75,10 @@ typedef int8 UBool;
* @return TRUE or FALSE
* @stable ICU 2.4
*/
-#define CBU_IS_UNICODE_CHAR(c) \
- ((uint32)(c)<0xd800 || \
- ((uint32)(c)>0xdfff && \
- (uint32)(c)<=0x10ffff && \
- !CBU_IS_UNICODE_NONCHAR(c)))
+#define CBU_IS_UNICODE_CHAR(c) \
+ ((uint32_t)(c) < 0xd800 || \
+ ((uint32_t)(c) > 0xdfff && (uint32_t)(c) <= 0x10ffff && \
+ !CBU_IS_UNICODE_NONCHAR(c)))
/**
* Is this code point a surrogate (U+d800..U+dfff)?
@@ -103,13 +101,14 @@ typedef int8 UBool;
// UTF-8 macros ----------------------------------------------------------------
// from utf8.h
-extern const uint8 utf8_countTrailBytes[256];
+extern const uint8_t utf8_countTrailBytes[256];
/**
* Count the trail bytes for a UTF-8 lead byte.
* @internal
*/
-#define CBU8_COUNT_TRAIL_BYTES(leadByte) (base_icu::utf8_countTrailBytes[(uint8)leadByte])
+#define CBU8_COUNT_TRAIL_BYTES(leadByte) \
+ (base_icu::utf8_countTrailBytes[(uint8_t)leadByte])
/**
* Mask a UTF-8 lead byte, leave only the lower bits that form part of the code point value.
@@ -131,7 +130,7 @@ extern const uint8 utf8_countTrailBytes[256];
* @return TRUE or FALSE
* @stable ICU 2.4
*/
-#define CBU8_IS_LEAD(c) ((uint8)((c)-0xc0)<0x3e)
+#define CBU8_IS_LEAD(c) ((uint8_t)((c)-0xc0) < 0x3e)
/**
* Is this code unit (byte) a UTF-8 trail byte?
@@ -148,16 +147,16 @@ extern const uint8 utf8_countTrailBytes[256];
* @return 1..4, or 0 if c is a surrogate or not a Unicode code point
* @stable ICU 2.4
*/
-#define CBU8_LENGTH(c) \
- ((uint32)(c)<=0x7f ? 1 : \
- ((uint32)(c)<=0x7ff ? 2 : \
- ((uint32)(c)<=0xd7ff ? 3 : \
- ((uint32)(c)<=0xdfff || (uint32)(c)>0x10ffff ? 0 : \
- ((uint32)(c)<=0xffff ? 3 : 4)\
- ) \
- ) \
- ) \
- )
+#define CBU8_LENGTH(c) \
+ ((uint32_t)(c) <= 0x7f \
+ ? 1 \
+ : ((uint32_t)(c) <= 0x7ff \
+ ? 2 \
+ : ((uint32_t)(c) <= 0xd7ff \
+ ? 3 \
+ : ((uint32_t)(c) <= 0xdfff || (uint32_t)(c) > 0x10ffff \
+ ? 0 \
+ : ((uint32_t)(c) <= 0xffff ? 3 : 4)))))
/**
* The maximum number of UTF-8 code units (bytes) per Unicode code point (U+0000..U+10ffff).
@@ -170,7 +169,11 @@ extern const uint8 utf8_countTrailBytes[256];
* Function for handling "next code point" with error-checking.
* @internal
*/
-UChar32 utf8_nextCharSafeBody(const uint8 *s, int32 *pi, int32 length, UChar32 c, UBool strict);
+UChar32 utf8_nextCharSafeBody(const uint8_t* s,
+ int32_t* pi,
+ int32_t length,
+ UChar32 c,
+ UBool strict);
/**
* Get a code point from a string at a code point boundary offset,
@@ -183,55 +186,59 @@ UChar32 utf8_nextCharSafeBody(const uint8 *s, int32 *pi, int32 length, UChar32 c
* If the offset points to a trail byte or an illegal UTF-8 sequence, then
* c is set to a negative value.
*
- * @param s const uint8 * string
+ * @param s const uint8_t * string
* @param i string offset, i<length
* @param length string length
* @param c output UChar32 variable, set to <0 in case of an error
* @see CBU8_NEXT_UNSAFE
* @stable ICU 2.4
*/
-#define CBU8_NEXT(s, i, length, c) { \
- (c)=(s)[(i)++]; \
- if(((uint8)(c))>=0x80) { \
- if(CBU8_IS_LEAD(c)) { \
- (c)=base_icu::utf8_nextCharSafeBody((const uint8 *)s, &(i), (int32)(length), c, -1); \
- } else { \
- (c)=CBU_SENTINEL; \
- } \
- } \
-}
+#define CBU8_NEXT(s, i, length, c) \
+ { \
+ (c) = (s)[(i)++]; \
+ if (((uint8_t)(c)) >= 0x80) { \
+ if (CBU8_IS_LEAD(c)) { \
+ (c) = base_icu::utf8_nextCharSafeBody((const uint8_t*)s, &(i), \
+ (int32_t)(length), c, -1); \
+ } else { \
+ (c) = CBU_SENTINEL; \
+ } \
+ } \
+ }
/**
* Append a code point to a string, overwriting 1 to 4 bytes.
* The offset points to the current end of the string contents
* and is advanced (post-increment).
- * "Unsafe" macro, assumes a valid code point and sufficient space in the string.
+ * "Unsafe" macro, assumes a valid code point and sufficient space in the
+ * string.
* Otherwise, the result is undefined.
*
- * @param s const uint8 * string buffer
+ * @param s const uint8_t * string buffer
* @param i string offset
* @param c code point to append
* @see CBU8_APPEND
* @stable ICU 2.4
*/
-#define CBU8_APPEND_UNSAFE(s, i, c) { \
- if((uint32)(c)<=0x7f) { \
- (s)[(i)++]=(uint8)(c); \
- } else { \
- if((uint32)(c)<=0x7ff) { \
- (s)[(i)++]=(uint8)(((c)>>6)|0xc0); \
- } else { \
- if((uint32)(c)<=0xffff) { \
- (s)[(i)++]=(uint8)(((c)>>12)|0xe0); \
- } else { \
- (s)[(i)++]=(uint8)(((c)>>18)|0xf0); \
- (s)[(i)++]=(uint8)((((c)>>12)&0x3f)|0x80); \
- } \
- (s)[(i)++]=(uint8)((((c)>>6)&0x3f)|0x80); \
- } \
- (s)[(i)++]=(uint8)(((c)&0x3f)|0x80); \
- } \
-}
+#define CBU8_APPEND_UNSAFE(s, i, c) \
+ { \
+ if ((uint32_t)(c) <= 0x7f) { \
+ (s)[(i)++] = (uint8_t)(c); \
+ } else { \
+ if ((uint32_t)(c) <= 0x7ff) { \
+ (s)[(i)++] = (uint8_t)(((c) >> 6) | 0xc0); \
+ } else { \
+ if ((uint32_t)(c) <= 0xffff) { \
+ (s)[(i)++] = (uint8_t)(((c) >> 12) | 0xe0); \
+ } else { \
+ (s)[(i)++] = (uint8_t)(((c) >> 18) | 0xf0); \
+ (s)[(i)++] = (uint8_t)((((c) >> 12) & 0x3f) | 0x80); \
+ } \
+ (s)[(i)++] = (uint8_t)((((c) >> 6) & 0x3f) | 0x80); \
+ } \
+ (s)[(i)++] = (uint8_t)(((c)&0x3f) | 0x80); \
+ } \
+ }
// UTF-16 macros ---------------------------------------------------------------
// from utf16.h
@@ -325,7 +332,7 @@ UChar32 utf8_nextCharSafeBody(const uint8 *s, int32 *pi, int32 length, UChar32 c
* @return 1 or 2
* @stable ICU 2.4
*/
-#define CBU16_LENGTH(c) ((uint32)(c)<=0xffff ? 1 : 2)
+#define CBU16_LENGTH(c) ((uint32_t)(c) <= 0xffff ? 1 : 2)
/**
* The maximum number of 16-bit code units per Unicode code point (U+0000..U+10ffff).
@@ -353,16 +360,17 @@ UChar32 utf8_nextCharSafeBody(const uint8 *s, int32 *pi, int32 length, UChar32 c
* @param c output UChar32 variable
* @stable ICU 2.4
*/
-#define CBU16_NEXT(s, i, length, c) { \
- (c)=(s)[(i)++]; \
- if(CBU16_IS_LEAD(c)) { \
- uint16 __c2; \
- if((i)<(length) && CBU16_IS_TRAIL(__c2=(s)[(i)])) { \
- ++(i); \
- (c)=CBU16_GET_SUPPLEMENTARY((c), __c2); \
- } \
- } \
-}
+#define CBU16_NEXT(s, i, length, c) \
+ { \
+ (c) = (s)[(i)++]; \
+ if (CBU16_IS_LEAD(c)) { \
+ uint16_t __c2; \
+ if ((i) < (length) && CBU16_IS_TRAIL(__c2 = (s)[(i)])) { \
+ ++(i); \
+ (c) = CBU16_GET_SUPPLEMENTARY((c), __c2); \
+ } \
+ } \
+ }
/**
* Append a code point to a string, overwriting 1 or 2 code units.
@@ -377,14 +385,15 @@ UChar32 utf8_nextCharSafeBody(const uint8 *s, int32 *pi, int32 length, UChar32 c
* @see CBU16_APPEND
* @stable ICU 2.4
*/
-#define CBU16_APPEND_UNSAFE(s, i, c) { \
- if((uint32)(c)<=0xffff) { \
- (s)[(i)++]=(uint16)(c); \
- } else { \
- (s)[(i)++]=(uint16)(((c)>>10)+0xd7c0); \
- (s)[(i)++]=(uint16)(((c)&0x3ff)|0xdc00); \
- } \
-}
+#define CBU16_APPEND_UNSAFE(s, i, c) \
+ { \
+ if ((uint32_t)(c) <= 0xffff) { \
+ (s)[(i)++] = (uint16_t)(c); \
+ } else { \
+ (s)[(i)++] = (uint16_t)(((c) >> 10) + 0xd7c0); \
+ (s)[(i)++] = (uint16_t)(((c)&0x3ff) | 0xdc00); \
+ } \
+ }
} // namesapce base_icu
diff --git a/chromium/base/third_party/libevent/BUILD.gn b/chromium/base/third_party/libevent/BUILD.gn
new file mode 100644
index 00000000000..67e326d1125
--- /dev/null
+++ b/chromium/base/third_party/libevent/BUILD.gn
@@ -0,0 +1,55 @@
+# 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.
+
+import("//build/config/nacl/config.gni")
+
+source_set("libevent") {
+ sources = [
+ "buffer.c",
+ "evbuffer.c",
+ "evdns.c",
+ "event.c",
+ "event_tagging.c",
+ "evrpc.c",
+ "evutil.c",
+ "http.c",
+ "log.c",
+ "poll.c",
+ "select.c",
+ "signal.c",
+ "strlcpy.c",
+ ]
+
+ defines = [ "HAVE_CONFIG_H" ]
+
+ if (is_mac || is_ios) {
+ sources += [ "kqueue.c" ]
+ include_dirs = [ "mac" ]
+ } else if (is_linux) {
+ sources += [ "epoll.c" ]
+ include_dirs = [ "linux" ]
+ } else if (is_android) {
+ sources += [ "epoll.c" ]
+ include_dirs = [ "android" ]
+ } else if (is_nacl_nonsfi) {
+ sources -= [
+ "evdns.c",
+ "event_tagging.c",
+ "evrpc.c",
+ "http.c",
+ "select.c",
+ "signal.c",
+ ]
+ sources += [
+ "nacl_nonsfi/config.h",
+ "nacl_nonsfi/event-config.h",
+ "nacl_nonsfi/random.c",
+ "nacl_nonsfi/signal_stub.c",
+ ]
+ include_dirs = [ "nacl_nonsfi" ]
+ }
+
+ configs -= [ "//build/config/compiler:chromium_code" ]
+ configs += [ "//build/config/compiler:no_chromium_code" ]
+}
diff --git a/chromium/base/third_party/libevent/ChangeLog b/chromium/base/third_party/libevent/ChangeLog
new file mode 100644
index 00000000000..893b0873ae3
--- /dev/null
+++ b/chromium/base/third_party/libevent/ChangeLog
@@ -0,0 +1,253 @@
+Changes in 1.4.15-stable (5 January 2015)
+
+ o Avoid integer overflow bugs in evbuffer_add() and related functions. See CVE-2014-6272 advisory for more information. (d49bc0e88b81a5812116074dc007f1db0ca1eecd)
+
+ o Pass flags to fcntl(F_SETFL) as int, not long (b3d0382)
+ o Backport and tweak the LICENSE file for 1.4 (8a5ebd3)
+ o set close-on-exec bit for filedescriptors created by dns subsystem (9985231 Ralf Schmitt)
+ o Replace unused case of FD_CLOSEONEXEC with a proper null statement. (44f04a2)
+ o Fix kqueue correctness test on x84_64 (1c25b07)
+ o Avoid deadlock when activating signals. (e0e6958)
+ o Backport doc fix for evhttp_bind_socket. (95b71d0 Marco)
+ o Fix an issue with forking and signal socketpairs in select/poll backends (f0ff765)
+ o Fix compilation on Visual Studio 2010 (53c47c2 VDm)
+ o Defensive programming to prevent (hopefully impossible) stack-stomping (2d8cf0b)
+ o Check for POLLERR, POLLHUP and POLLNVAL for Solaris event ports (353b4ac Trond Norbye)
+ o Fix a bug that could allow dns requests with duplicate tx ids (e50ba5b)
+ o Avoid truncating huge values for content-length (1d6e30e)
+ o Take generated files out of git; add correct m4 magic for libtool to auto* files (7cf794b)
+ o Prefer autoregen -ivf to manual autogen.sh (823d9be)
+
+
+Changes in 1.4.14b-stable
+ o Set the VERSION_INFO correctly for 1.4.14
+
+
+Changes in 1.4.14-stable
+ o Add a .gitignore file for the 1.4 branch. (d014edb)
+ o Backport evbuffer_readln(). (b04cc60 Nicholas Marriott)
+ o Make the evbuffer_readln backport follow the current API (c545485)
+ o Valgrind fix: Clear struct kevent before checking for OSX bug. (5713d5d William Ahern)
+ o Fix a crash when reading badly formatted resolve.conf (5b10d00 Yasuoka Masahiko)
+ o Fix memory-leak of signal handler array with kqueue. [backport] (01f3775)
+ o Update sample/signal-test.c to use newer APIs and not leak. (891765c Evan Jones)
+ o Correct all versions in 1.4 branch (ac0d213)
+ o Make evutil_make_socket_nonblocking() leave any other flags alone. (81c26ba Jardel Weyrich)
+ o Adjusted fcntl() retval comparison on evutil_make_socket_nonblocking(). (5f2e250 Jardel Weyrich)
+ o Correct a debug message in evhttp_parse_request_line (35df59e)
+ o Merge branch 'readln-backport' into patches-1.4 (8771d5b)
+ o Do not send an HTTP error when we've already closed or responded. (4fd2dd9 Pavel Plesov)
+ o Re-add event_siglcb; some old code _was_ still using it. :( (bd03d06)
+ o Make Libevent 1.4 build on win32 with Unicode enabled. (bce58d6 Brodie Thiesfield)
+ o Distribute nmake makefile for 1.4 (20d706d)
+ o do not fail while sending on http connections the client closed. (5c8b446)
+ o make evhttp_send() safe against terminated connections, too (01ea0c5)
+ o Fix a free(NULL) in min_heap.h (2458934)
+ o Fix memory leak when setting up priorities; reported by Alexander Drozdov (cb1a722)
+ o Clean up properly when adding a signal handler fails. (ae6ece0 Gilad Benjamini)
+ o Do not abort HTTP requests missing a reason string. (29d7b32 Pierre Phaneuf)
+ o Fix compile warning in http.c (906d573)
+ o Define _REENTRANT as needed on Solaris, elsewhere (6cbea13)
+
+
+Changes in 1.4.13-stable:
+ o If the kernel tells us that there are a negative number of bytes to read from a socket, do not believe it. Fixes bug 2841177; found by Alexander Pronchenkov.
+ o Do not allocate the maximum event queue and fd array for the epoll backend at startup. Instead, start out accepting 32 events at a time, and double the queue's size when it seems that the OS is generating events faster than we're requesting them. Saves up to 512K per epoll-based event_base. Resolves bug 2839240.
+ o Fix compilation on Android, which forgot to define fd_mask in its sys/select.h
+ o Do not drop data from evbuffer when out of memory; reported by Jacek Masiulaniec
+ o Rename our replacement compat/sys/_time.h header to avoid build a conflict on HPUX; reported by Kathryn Hogg.
+ o Build kqueue.c correctly on GNU/kFreeBSD platforms. Patch pulled upstream from Debian.
+ o Fix a problem with excessive memory allocation when using multiple event priorities.
+ o When running set[ug]id, don't check the environment. Based on a patch from OpenBSD.
+
+
+Changes in 1.4.12-stable:
+ o Try to contain degree of failure when running on a win32 version so heavily firewalled that we can't fake a socketpair.
+ o Fix an obscure timing-dependent, allocator-dependent crash in the evdns code.
+ o Use __VA_ARGS__ syntax for varargs macros in event_rpcgen when compiler is not GCC.
+ o Activate fd events in a pseudorandom order with O(N) backends, so that we don't systematically favor low fds (select) or earlier-added fds (poll, win32).
+ o Fix another pair of fencepost bugs in epoll.c. [Patch from Adam Langley.]
+ o Do not break evdns connections to nameservers when our IP changes.
+ o Set truncated flag correctly in evdns server replies.
+ o Disable strict aliasing with GCC: our code is not compliant with it.
+
+Changes in 1.4.11-stable:
+ o Fix a bug when removing a timeout from the heap. [Patch from Marko Kreen]
+ o Remove the limit on size of HTTP headers by removing static buffers.
+ o Fix a nasty dangling pointer bug in epoll.c that could occur after epoll_recalc(). [Patch from Kevin Springborn]
+ o Distribute Win32-Code/event-config.h, not ./event-config.h
+
+Changes in 1.4.10-stable:
+ o clean up buffered http connection data on reset; reported by Brian O'Kelley
+ o bug fix and potential race condition in signal handling; from Alexander Drozdov
+ o rename the Solaris event ports backend to evport
+ o support compilation on Haiku
+ o fix signal processing when a signal callback delivers a signal; from Alexander Drozdov
+ o const-ify some arguments to evdns functions.
+ o off-by-one error in epoll_recalc; reported by Victor Goya
+ o include Doxyfile in tar ball; from Jeff Garzik
+ o correctly parse queries with encoded \r, \n or + characters
+
+Changes in 1.4.9-stable:
+ o event_add would not return error for some backends; from Dean McNamee
+ o Clear the timer cache on entering the event loop; reported by Victor Chang
+ o Only bind the socket on connect when a local address has been provided; reported by Alejo Sanchez
+ o Allow setting of local port for evhttp connections to support millions of connections from a single system; from Richard Jones.
+ o Clear the timer cache when leaving the event loop; reported by Robin Haberkorn
+ o Fix a typo in setting the global event base; reported by lance.
+ o Fix a memory leak when reading multi-line headers
+ o Fix a memory leak by not running explicit close detection for server connections
+
+Changes in 1.4.8-stable:
+ o Match the query in DNS replies to the query in the request; from Vsevolod Stakhov.
+ o Fix a merge problem in which name_from_addr returned pointers to the stack; found by Jiang Hong.
+ o Do not remove Accept-Encoding header
+
+Changes in 1.4.7-stable:
+ o Fix a bug where headers arriving in multiple packets were not parsed; fix from Jiang Hong; test by me.
+
+Changes in 1.4.6-stable:
+ o evutil.h now includes <stdarg.h> directly
+ o switch all uses of [v]snprintf over to evutil
+ o Correct handling of trailing headers in chunked replies; from Scott Lamb.
+ o Support multi-line HTTP headers; based on a patch from Moshe Litvin
+ o Reject negative Content-Length headers; anonymous bug report
+ o Detect CLOCK_MONOTONIC at runtime for evdns; anonymous bug report
+ o Fix a bug where deleting signals with the kqueue backend would cause subsequent adds to fail
+ o Support multiple events listening on the same signal; make signals regular events that go on the same event queue; problem report by Alexander Drozdov.
+ o Deal with evbuffer_read() returning -1 on EINTR|EAGAIN; from Adam Langley.
+ o Fix a bug in which the DNS server would incorrectly set the type of a cname reply to a.
+ o Fix a bug where setting the timeout on a bufferevent would take not effect if the event was already pending.
+ o Fix a memory leak when using signals for some event bases; reported by Alexander Drozdov.
+ o Add libevent.vcproj file to distribution to help with Windows build.
+ o Fix a problem with epoll() and reinit; problem report by Alexander Drozdov.
+ o Fix off-by-one errors in devpoll; from Ian Bell
+ o Make event_add not change any state if it fails; reported by Ian Bell.
+ o Do not warn on accept when errno is either EAGAIN or EINTR
+
+Changes in 1.4.5-stable:
+ o Fix connection keep-alive behavior for HTTP/1.0
+ o Fix use of freed memory in event_reinit; pointed out by Peter Postma
+ o Constify struct timeval * where possible; pointed out by Forest Wilkinson
+ o allow min_heap_erase to be called on removed members; from liusifan.
+ o Rename INPUT and OUTPUT to EVRPC_INPUT and EVRPC_OUTPUT. Retain INPUT/OUTPUT aliases on on-win32 platforms for backwards compatibility.
+ o Do not use SO_REUSEADDR when connecting
+ o Fix Windows build
+ o Fix a bug in event_rpcgen when generated fixed-sized entries
+
+Changes in 1.4.4-stable:
+ o Correct the documentation on buffer printf functions.
+ o Don't warn on unimplemented epoll_create(): this isn't a problem, just a reason to fall back to poll or select.
+ o Correctly handle timeouts larger than 35 minutes on Linux with epoll.c. This is probably a kernel defect, but we'll have to support old kernels anyway even if it gets fixed.
+ o Fix a potential stack corruption bug in tagging on 64-bit CPUs.
+ o expose bufferevent_setwatermark via header files and fix high watermark on read
+ o fix a bug in bufferevent read water marks and add a test for them
+ o introduce bufferevent_setcb and bufferevent_setfd to allow better manipulation of bufferevents
+ o use libevent's internal timercmp on all platforms, to avoid bugs on old platforms where timercmp(a,b,<=) is buggy.
+ o reduce system calls for getting current time by caching it.
+ o fix evhttp_bind_socket() so that multiple sockets can be bound by the same http server.
+ o Build test directory correctly with CPPFLAGS set.
+ o Fix build under Visual C++ 2005.
+ o Expose evhttp_accept_socket() API.
+ o Merge windows gettimeofday() replacement into a new evutil_gettimeofday() function.
+ o Fix autoconf script behavior on IRIX.
+ o Make sure winsock2.h include always comes before windows.h include.
+
+Changes in 1.4.3-stable:
+ o include Content-Length in reply for HTTP/1.0 requests with keep-alive
+ o Patch from Tani Hosokawa: make some functions in http.c threadsafe.
+ o Do not free the kqop file descriptor in other processes, also allow it to be 0; from Andrei Nigmatulin
+ o make event_rpcgen.py generate code include event-config.h; reported by Sam Banks.
+ o make event methods static so that they are not exported; from Andrei Nigmatulin
+ o make RPC replies use application/octet-stream as mime type
+ o do not delete uninitialized timeout event in evdns
+
+Changes in 1.4.2-rc:
+ o remove pending timeouts on event_base_free()
+ o also check EAGAIN for Solaris' event ports; from W.C.A. Wijngaards
+ o devpoll and evport need reinit; tested by W.C.A Wijngaards
+ o event_base_get_method; from Springande Ulv
+ o Send CRLF after each chunk in HTTP output, for compliance with RFC2626. Patch from "propanbutan". Fixes bug 1894184.
+ o Add a int64_t parsing function, with unit tests, so we can apply Scott Lamb's fix to allow large HTTP values.
+ o Use a 64-bit field to hold HTTP content-lengths. Patch from Scott Lamb.
+ o Allow regression code to build even without Python installed
+ o remove NDEBUG ifdefs from evdns.c
+ o update documentation of event_loop and event_base_loop; from Tani Hosokawa.
+ o detect integer types properly on platforms without stdint.h
+ o Remove "AM_MAINTAINER_MODE" declaration in configure.in: now makefiles and configure should get re-generated automatically when Makefile.am or configure.in chanes.
+ o do not insert event into list when evsel->add fails
+
+Changes in 1.4.1-beta:
+ o free minheap on event_base_free(); from Christopher Layne
+ o debug cleanups in signal.c; from Christopher Layne
+ o provide event_base_new() that does not set the current_base global
+ o bufferevent_write now uses a const source argument; report from Charles Kerr
+ o better documentation for event_base_loopexit; from Scott Lamb.
+ o Make kqueue have the same behavior as other backends when a signal is caught between event_add() and event_loop(). Previously, it would catch and ignore such signals.
+ o Make kqueue restore signal handlers correctly when event_del() is called.
+ o provide event_reinit() to reintialize an event_base after fork
+ o small improvements to evhttp documentation
+ o always generate Date and Content-Length headers for HTTP/1.1 replies
+ o set the correct event base for HTTP close events
+ o New function, event_{base_}loopbreak. Like event_loopexit, it makes an event loop stop executing and return. Unlike event_loopexit, it keeps subsequent pending events from getting executed. Patch from Scott Lamb
+ o Removed obsoleted recalc code
+ o pull setters/getters out of RPC structures into a base class to which we just need to store a pointer; this reduces the memory footprint of these structures.
+ o fix a bug with event_rpcgen for integers
+ o move EV_PERSIST handling out of the event backends
+ o support for 32-bit tag numbers in rpc structures; this is wire compatible, but changes the API slightly.
+ o prefix {encode,decode}_tag functions with evtag to avoid collisions
+ o Correctly handle DNS replies with no answers set (Fixes bug 1846282)
+ o The configure script now takes an --enable-gcc-warnigns option that turns on many optional gcc warnings. (Nick has been building with these for a while, but they might be useful to other developers.)
+ o When building with GCC, use the "format" attribute to verify type correctness of calls to printf-like functions.
+ o removed linger from http server socket; reported by Ilya Martynov
+ o allow \r or \n individually to separate HTTP headers instead of the standard "\r\n"; from Charles Kerr.
+ o demote most http warnings to debug messages
+ o Fix Solaris compilation; from Magne Mahre
+ o Add a "Date" header to HTTP responses, as required by HTTP 1.1.
+ o Support specifying the local address of an evhttp_connection using set_local_address
+ o Fix a memory leak in which failed HTTP connections would not free the request object
+ o Make adding of array members in event_rpcgen more efficient, but doubling memory allocation
+ o Fix a memory leak in the DNS server
+ o Fix compilation when DNS_USE_OPENSSL_FOR_ID is enabled
+ o Fix buffer size and string generation in evdns_resolve_reverse_ipv6().
+ o Respond to nonstandard DNS queries with "NOTIMPL" rather than by ignoring them.
+ o In DNS responses, the CD flag should be preserved, not the TC flag.
+ o Fix http.c to compile properly with USE_DEBUG; from Christopher Layne
+ o Handle NULL timeouts correctly on Solaris; from Trond Norbye
+ o Recalculate pending events properly when reallocating event array on Solaris; from Trond Norbye
+ o Add Doxygen documentation to header files; from Mark Heily
+ o Add a evdns_set_transaction_id_fn() function to override the default
+ transaction ID generation code.
+ o Add an evutil module (with header evutil.h) to implement our standard cross-platform hacks, on the theory that somebody else would like to use them too.
+ o Fix signals implementation on windows.
+ o Fix http module on windows to close sockets properly.
+ o Make autogen.sh script run correctly on systems where /bin/sh isn't bash. (Patch from Trond Norbye, rewritten by Hagne Mahre and then Hannah Schroeter.)
+ o Skip calling gettime() in timeout_process if we are not in fact waiting for any events. (Patch from Trond Norbye)
+ o Make test subdirectory compile under mingw.
+ o Fix win32 buffer.c behavior so that it is correct for sockets (which do not like ReadFile and WriteFile).
+ o Make the test.sh script run unit tests for the evpoll method.
+ o Make the entire evdns.h header enclosed in "extern C" as appropriate.
+ o Fix implementation of strsep on platforms that lack it
+ o Fix implementation of getaddrinfo on platforms that lack it; mainly, this will make Windows http.c work better. Original patch by Lubomir Marinov.
+ o Fix evport implementation: port_disassociate called on unassociated events resulting in bogus errors; more efficient memory management; from Trond Norbye and Prakash Sangappa
+ o support for hooks on rpc input and output; can be used to implement rpc independent processing such as compression or authentication.
+ o use a min heap instead of a red-black tree for timeouts; as a result finding the min is a O(1) operation now; from Maxim Yegorushkin
+ o associate an event base with an rpc pool
+ o added two additional libraries: libevent_core and libevent_extra in addition to the regular libevent. libevent_core contains only the event core whereas libevent_extra contains dns, http and rpc support
+ o Begin using libtool's library versioning support correctly. If we don't mess up, this will more or less guarantee binaries linked against old versions of libevent continue working when we make changes to libevent that do not break backward compatibility.
+ o Fix evhttp.h compilation when TAILQ_ENTRY is not defined.
+ o Small code cleanups in epoll_dispatch().
+ o Increase the maximum number of addresses read from a packet in evdns to 32.
+ o Remove support for the rtsig method: it hasn't compiled for a while, and nobody seems to miss it very much. Let us know if there's a good reason to put it back in.
+ o Rename the "class" field in evdns_server_request to dns_question_class, so that it won't break compilation under C++. Use a macro so that old code won't break. Mark the macro as deprecated.
+ o Fix DNS unit tests so that having a DNS server with broken IPv6 support is no longer cause for aborting the unit tests.
+ o Make event_base_free() succeed even if there are pending non-internal events on a base. This may still leak memory and fds, but at least it no longer crashes.
+ o Post-process the config.h file into a new, installed event-config.h file that we can install, and whose macros will be safe to include in header files.
+ o Remove the long-deprecated acconfig.h file.
+ o Do not require #include <sys/types.h> before #include <event.h>.
+ o Add new evutil_timer* functions to wrap (or replace) the regular timeval manipulation functions.
+ o Fix many build issues when using the Microsoft C compiler.
+ o Remove a bash-ism in autogen.sh
+ o When calling event_del on a signal, restore the signal handler's previous value rather than setting it to SIG_DFL. Patch from Christopher Layne.
+ o Make the logic for active events work better with internal events; patch from Christopher Layne.
+ o We do not need to specially remove a timeout before calling event_del; patch from Christopher Layne.
diff --git a/chromium/base/third_party/libevent/Doxyfile b/chromium/base/third_party/libevent/Doxyfile
new file mode 100644
index 00000000000..77f6de89b46
--- /dev/null
+++ b/chromium/base/third_party/libevent/Doxyfile
@@ -0,0 +1,230 @@
+# Doxyfile 1.5.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = libevent
+
+# Place all output under 'doxygen/'
+
+OUTPUT_DIRECTORY = doxygen/
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like the Qt-style comments (thus requiring an
+# explicit @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF = YES
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = event.h evdns.h evhttp.h evrpc.h
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = YES
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED = TAILQ_ENTRY RB_ENTRY _EVENT_DEFINED_TQENTRY
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
diff --git a/chromium/base/third_party/libevent/LICENSE b/chromium/base/third_party/libevent/LICENSE
new file mode 100644
index 00000000000..cabd9fc7bfb
--- /dev/null
+++ b/chromium/base/third_party/libevent/LICENSE
@@ -0,0 +1,53 @@
+Libevent is available for use under the following license, commonly known
+as the 3-clause (or "modified") BSD license:
+
+==============================
+Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
+Copyright (c) 2007-2010 Niels Provos and Nick Mathewson
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+==============================
+
+Portions of Libevent are based on works by others, also made available by
+them under the three-clause BSD license above. The copyright notices are
+available in the corresponding source files; the license is as above. Here's
+a list:
+
+log.c:
+ Copyright (c) 2000 Dug Song <dugsong@monkey.org>
+ Copyright (c) 1993 The Regents of the University of California.
+
+strlcpy.c:
+ Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+
+win32.c:
+ Copyright (c) 2003 Michael A. Davis <mike@datanerds.net>
+
+evport.c:
+ Copyright (c) 2007 Sun Microsystems
+
+min_heap.h:
+ Copyright (c) 2006 Maxim Yegorushkin <maxim.yegorushkin@gmail.com>
+
+tree.h:
+ Copyright 2002 Niels Provos <provos@citi.umich.edu>
diff --git a/chromium/base/third_party/libevent/Makefile.am b/chromium/base/third_party/libevent/Makefile.am
new file mode 100644
index 00000000000..c1ed62a444e
--- /dev/null
+++ b/chromium/base/third_party/libevent/Makefile.am
@@ -0,0 +1,152 @@
+AUTOMAKE_OPTIONS = foreign no-dependencies
+
+ACLOCAL_AMFLAGS = -I m4
+
+# This is the point release for libevent. It shouldn't include any
+# a/b/c/d/e notations.
+RELEASE = 1.4
+
+# This is the version info for the libevent binary API. It has three
+# numbers:
+# Current -- the number of the binary API that we're implementing
+# Revision -- which iteration of the implementation of the binary
+# API are we supplying?
+# Age -- How many previous binary API versions do we also
+# support?
+#
+# If we release a new version that does not change the binary API,
+# increment Revision.
+#
+# If we release a new version that changes the binary API, but does
+# not break programs compiled against the old binary API, increment
+# Current and Age. Set Revision to 0, since this is the first
+# implementation of the new API.
+#
+# Otherwise, we're changing the binary API and breaking bakward
+# compatibility with old binaries. Increment Current. Set Age to 0,
+# since we're backward compatible with no previous APIs. Set Revision
+# to 0 too.
+VERSION_INFO = 4:1:2
+
+###
+# History:
+# We started using Libtool around version 1.0d. For all versions from
+# 1.0d through 1.3e, we set RELEASE to the version name, and
+# VERSION_INFO to something haphazard. The didn't matter, since
+# setting RELEASE meant that no version of Libevent was treated as
+# binary-compatible with any other version.
+#
+# As of 1.4.0-beta, we set RELEASE to "1.4", so that releases in the
+# 1.4.x series could be potentially binary-compatible with one another,
+# but not with any other series. (They aren't.) We didn't necessarily
+# set VERSION_INFO correctly, or update it as often as we should have.
+# The VERSION_INFO values were:
+# 1.4.0-beta .. 1.4.4-stable : 2:0:0 [See note 1]
+# 1.4.5-stable : 3:0:1 (compatible ABI change)
+# 1.4.6-stable : 3:1:1 (no ABI change)
+# 1.4.7-stable : 3:1:1 [see note 1]
+# 1.4.8-stable : 3:2:1 (no ABI change)
+# 1.4.9-stable : 3:2:1 [see note 1]
+# 1.4.10-stable : 3:3:1 (no ABI change)
+# 1.4.11-stable .. 1.4.13-stable : 3:3:1 [see note 1]
+# 1.4.14a-stable: : 3:3:2 [see note 2]
+# 1.4.14b-stable: : 4:0:2 (compatible ABI change)
+# 1.4.15-stable: : 4:1:2 (no ABI change)
+#
+# [1]: Using the same VERSION_INFO value was wrong; we should have been
+# updating the Revision field.
+# [2]: We set the VERSION_INFO completely wrong on 1.4.14b-stable
+
+bin_SCRIPTS = event_rpcgen.py
+
+EXTRA_DIST = autogen.sh event.h event-internal.h log.h evsignal.h evdns.3 \
+ evrpc.h evrpc-internal.h min_heap.h \
+ event.3 \
+ Doxyfile \
+ kqueue.c epoll_sub.c epoll.c select.c poll.c signal.c \
+ evport.c devpoll.c event_rpcgen.py \
+ sample/Makefile.am sample/Makefile.in sample/event-test.c \
+ sample/signal-test.c sample/time-test.c \
+ test/Makefile.am test/Makefile.in test/bench.c test/regress.c \
+ test/test-eof.c test/test-weof.c test/test-time.c \
+ test/test-init.c test/test.sh \
+ compat/sys/queue.h compat/sys/_libevent_time.h \
+ WIN32-Code/config.h \
+ WIN32-Code/event-config.h \
+ WIN32-Code/win32.c \
+ WIN32-Code/tree.h \
+ WIN32-Prj/event_test/event_test.dsp \
+ WIN32-Prj/event_test/test.txt WIN32-Prj/libevent.dsp \
+ WIN32-Prj/libevent.dsw WIN32-Prj/signal_test/signal_test.dsp \
+ WIN32-Prj/time_test/time_test.dsp WIN32-Prj/regress/regress.vcproj \
+ WIN32-Prj/libevent.sln WIN32-Prj/libevent.vcproj \
+ Makefile.nmake test/Makefile.nmake \
+ LICENSE
+
+lib_LTLIBRARIES = libevent.la libevent_core.la libevent_extra.la
+
+if BUILD_WIN32
+
+SUBDIRS = . sample
+SYS_LIBS = -lws2_32
+SYS_SRC = WIN32-Code/win32.c
+SYS_INCLUDES = -IWIN32-Code
+
+else
+
+SUBDIRS = . sample test
+SYS_LIBS =
+SYS_SRC =
+SYS_INCLUDES =
+
+endif
+
+BUILT_SOURCES = event-config.h
+
+event-config.h: config.h
+ echo '/* event-config.h' > $@
+ echo ' * Generated by autoconf; post-processed by libevent.' >> $@
+ echo ' * Do not edit this file.' >> $@
+ echo ' * Do not rely on macros in this file existing in later versions.'>> $@
+ echo ' */' >> $@
+ echo '#ifndef _EVENT_CONFIG_H_' >> $@
+ echo '#define _EVENT_CONFIG_H_' >> $@
+
+ sed -e 's/#define /#define _EVENT_/' \
+ -e 's/#undef /#undef _EVENT_/' \
+ -e 's/#ifndef /#ifndef _EVENT_/' < config.h >> $@
+ echo "#endif" >> $@
+
+CORE_SRC = event.c buffer.c evbuffer.c log.c evutil.c $(SYS_SRC)
+EXTRA_SRC = event_tagging.c http.c evhttp.h http-internal.h evdns.c \
+ evdns.h evrpc.c evrpc.h evrpc-internal.h \
+ strlcpy.c strlcpy-internal.h strlcpy-internal.h
+
+libevent_la_SOURCES = $(CORE_SRC) $(EXTRA_SRC)
+libevent_la_LIBADD = @LTLIBOBJS@ $(SYS_LIBS)
+libevent_la_LDFLAGS = -release $(RELEASE) -version-info $(VERSION_INFO)
+
+libevent_core_la_SOURCES = $(CORE_SRC)
+libevent_core_la_LIBADD = @LTLIBOBJS@ $(SYS_LIBS)
+libevent_core_la_LDFLAGS = -release $(RELEASE) -version-info $(VERSION_INFO)
+
+libevent_extra_la_SOURCES = $(EXTRA_SRC)
+libevent_extra_la_LIBADD = @LTLIBOBJS@ $(SYS_LIBS)
+libevent_extra_la_LDFLAGS = -release $(RELEASE) -version-info $(VERSION_INFO)
+
+include_HEADERS = event.h evhttp.h evdns.h evrpc.h evutil.h
+
+nodist_include_HEADERS = event-config.h
+
+INCLUDES = -I$(srcdir)/compat $(SYS_INCLUDES)
+
+man_MANS = event.3 evdns.3
+
+verify: libevent.la
+ cd test && make verify
+
+doxygen: FORCE
+ doxygen $(srcdir)/Doxyfile
+FORCE:
+
+DISTCLEANFILES = *~ event-config.h
diff --git a/chromium/base/third_party/libevent/Makefile.nmake b/chromium/base/third_party/libevent/Makefile.nmake
new file mode 100644
index 00000000000..f8d572204e2
--- /dev/null
+++ b/chromium/base/third_party/libevent/Makefile.nmake
@@ -0,0 +1,48 @@
+# WATCH OUT! This makefile is a work in progress. It is probably missing
+# tons of important things. DO NOT RELY ON IT TO BUILD A GOOD LIBEVENT.
+
+# Needed for correctness
+CFLAGS=/Iinclude /Icompat /IWIN32-Code /DWIN32 /DHAVE_CONFIG_H /I.
+
+# For optimization and warnings
+CFLAGS=$(CFLAGS) /Ox /W3 /wd4996 /nologo
+
+# XXXX have a debug mode
+
+LIBFLAGS=/nologo
+
+
+CORE_OBJS=event.obj buffer.obj evbuffer.obj \
+ log.obj evutil.obj \
+ strlcpy.obj signal.obj win32.obj
+EXTRA_OBJS=event_tagging.obj http.obj evdns.obj evrpc.obj
+
+ALL_OBJS=$(CORE_OBJS) $(WIN_OBJS) $(EXTRA_OBJS)
+STATIC_LIBS=libevent_core.lib libevent_extras.lib libevent.lib
+
+
+all: static_libs tests
+
+static_libs: $(STATIC_LIBS)
+
+win32.obj: WIN32-Code\win32.c
+ $(CC) $(CFLAGS) /c WIN32-Code\win32.c
+
+libevent_core.lib: $(CORE_OBJS)
+ lib $(LIBFLAGS) $(CORE_OBJS) /out:libevent_core.lib
+
+libevent_extras.lib: $(EXTRA_OBJS)
+ lib $(LIBFLAGS) $(EXTRA_OBJS) /out:libevent_extras.lib
+
+libevent.lib: $(CORE_OBJ) $(EXTRA_OBJS)
+ lib $(LIBFLAGS) $(CORE_OBJS) $(EXTRA_OBJS) /out:libevent.lib
+
+clean:
+ del $(ALL_OBJS)
+ del $(STATIC_LIBS)
+ cd test
+ $(MAKE) /F Makefile.nmake clean
+
+tests:
+ cd test
+ $(MAKE) /F Makefile.nmake
diff --git a/chromium/base/third_party/libevent/README b/chromium/base/third_party/libevent/README
new file mode 100644
index 00000000000..b0650392ed4
--- /dev/null
+++ b/chromium/base/third_party/libevent/README
@@ -0,0 +1,57 @@
+To build libevent, type
+
+$ ./configure && make
+
+ (If you got libevent from the subversion repository, you will
+ first need to run the included "autogen.sh" script in order to
+ generate the configure script.)
+
+Install as root via
+
+# make install
+
+You can run the regression tests by
+
+$ make verify
+
+Before, reporting any problems, please run the regression tests.
+
+To enable the low-level tracing build the library as:
+
+CFLAGS=-DUSE_DEBUG ./configure [...]
+
+Acknowledgements:
+-----------------
+
+The following people have helped with suggestions, ideas, code or
+fixing bugs:
+
+ Alejo
+ Weston Andros Adamson
+ William Ahern
+ Stas Bekman
+ Andrew Danforth
+ Mike Davis
+ Shie Erlich
+ Alexander von Gernler
+ Artur Grabowski
+ Aaron Hopkins
+ Claudio Jeker
+ Scott Lamb
+ Adam Langley
+ Philip Lewis
+ David Libenzi
+ Nick Mathewson
+ Andrey Matveev
+ Richard Nyberg
+ Jon Oberheide
+ Phil Oleson
+ Dave Pacheco
+ Tassilo von Parseval
+ Pierre Phaneuf
+ Jon Poland
+ Bert JW Regeer
+ Dug Song
+ Taral
+
+If I have forgotten your name, please contact me.
diff --git a/chromium/base/third_party/libevent/README.chromium b/chromium/base/third_party/libevent/README.chromium
new file mode 100644
index 00000000000..d8bb4de18bd
--- /dev/null
+++ b/chromium/base/third_party/libevent/README.chromium
@@ -0,0 +1,35 @@
+Name: libevent
+URL: http://libevent.org/
+Version: 1.4.15
+License: BSD
+Security Critical: yes
+
+Local Modifications:
+Rather than use libevent's own build system, we just build a Chrome
+static library using GYP.
+
+1) Run configure and "make event-config.h" on Linux, FreeBSD, Solaris,
+ and Mac and copy config.h and event-config.h to linux/, freebsd/,
+ solaris/, and mac/ respectively.
+2) Add libevent.gyp.
+3) chromium.patch is applied to make the following changes:
+ - Allow libevent to be used without being installed by changing <...>
+ #includes to "...".
+ - Fix a race condition in event_del.
+ - Optimistically assume CLOCK_MONOTONIC is available and fallback if it
+ fails, rather than explicitly testing for it.
+ - Remove an unneeded variable that causes a -Werror build failure.
+ - Add an #ifndef to fix a preprocessor redefined -Werror build failure.
+ - Revert the patch from http://sourceforge.net/p/levent/bugs/223/ that
+ introduces use-after-free memory corruption when an event callback frees
+ the struct event memory.
+4) The directories WIN32-Code and WIN32-Prj are not included.
+5) The configs for android were copied from Linux's which were very close to
+ android one with the exception of HAVE_FD_MASK and HAVE_STRLCPY.
+6) Add files to support building with the PNaCl toolchain. Added
+ libevent_nacl_nonsfi.gyp for build rule. nacl_nonsfi/config.h and
+ nacl_nonsfi/event-config.h are derived from linux/ counterparts.
+ nacl_nonsfi/random.c is also added to provide the random() function,
+ which is missing in the newlib-based PNaCl toolchain.
+7) Stub out signal.c for nacl_helper_nonsfi. socketpair() will be prohibited
+ by sandbox in nacl_helper_nonsfi.
diff --git a/chromium/base/third_party/libevent/android/config.h b/chromium/base/third_party/libevent/android/config.h
new file mode 100644
index 00000000000..91f4ddaf146
--- /dev/null
+++ b/chromium/base/third_party/libevent/android/config.h
@@ -0,0 +1,266 @@
+/* Copied from Linux version and changed the features according Android, which
+ * is close to Linux */
+
+/* Define if clock_gettime is available in libc */
+#define DNS_USE_CPU_CLOCK_FOR_ID 1
+
+/* Define is no secure id variant is available */
+/* #undef DNS_USE_GETTIMEOFDAY_FOR_ID */
+
+/* Define to 1 if you have the `clock_gettime' function. */
+#define HAVE_CLOCK_GETTIME 1
+
+/* Define if /dev/poll is available */
+/* #undef HAVE_DEVPOLL */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define if your system supports the epoll system calls */
+#define HAVE_EPOLL 1
+
+/* Define to 1 if you have the `epoll_ctl' function. */
+#define HAVE_EPOLL_CTL 1
+
+/* Define if your system supports event ports */
+/* #undef HAVE_EVENT_PORTS */
+
+/* Define to 1 if you have the `fcntl' function. */
+#define HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if the system has the type `fd_mask'. */
+/* #undef HAVE_FD_MASK */
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#define HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `getegid' function. */
+#define HAVE_GETEGID 1
+
+/* Define to 1 if you have the `geteuid' function. */
+#define HAVE_GETEUID 1
+
+/* Define to 1 if you have the `getnameinfo' function. */
+#define HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the `inet_ntop' function. */
+#define HAVE_INET_NTOP 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `issetugid' function. */
+/* #undef HAVE_ISSETUGID */
+
+/* Define to 1 if you have the `kqueue' function. */
+/* #undef HAVE_KQUEUE */
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+#define HAVE_LIBNSL 1
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+#define HAVE_LIBRESOLV 1
+
+/* Define to 1 if you have the `rt' library (-lrt). */
+#define HAVE_LIBRT 1
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+/* #undef HAVE_LIBSOCKET */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <netinet/in6.h> header file. */
+/* #undef HAVE_NETINET_IN6_H */
+
+/* Define to 1 if you have the `poll' function. */
+#define HAVE_POLL 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define HAVE_POLL_H 1
+
+/* Define to 1 if you have the `port_create' function. */
+/* #undef HAVE_PORT_CREATE */
+
+/* Define to 1 if you have the <port.h> header file. */
+/* #undef HAVE_PORT_H */
+
+/* Define to 1 if you have the `select' function. */
+#define HAVE_SELECT 1
+
+/* Define if F_SETFD is defined in <fcntl.h> */
+#define HAVE_SETFD 1
+
+/* Define to 1 if you have the `sigaction' function. */
+#define HAVE_SIGACTION 1
+
+/* Define to 1 if you have the `signal' function. */
+#define HAVE_SIGNAL 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#define HAVE_STDARG_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+#define HAVE_STRLCPY 1
+
+/* Define to 1 if you have the `strsep' function. */
+#define HAVE_STRSEP 1
+
+/* Define to 1 if you have the `strtok_r' function. */
+#define HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the `strtoll' function. */
+#define HAVE_STRTOLL 1
+
+/* Define to 1 if the system has the type `struct in6_addr'. */
+#define HAVE_STRUCT_IN6_ADDR 1
+
+/* Define to 1 if you have the <sys/devpoll.h> header file. */
+/* #undef HAVE_SYS_DEVPOLL_H */
+
+/* Define to 1 if you have the <sys/epoll.h> header file. */
+#define HAVE_SYS_EPOLL_H 1
+
+/* Define to 1 if you have the <sys/event.h> header file. */
+/* #undef HAVE_SYS_EVENT_H */
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/queue.h> header file. */
+#define HAVE_SYS_QUEUE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
+#define HAVE_TAILQFOREACH 1
+
+/* Define if timeradd is defined in <sys/time.h> */
+#define HAVE_TIMERADD 1
+
+/* Define if timerclear is defined in <sys/time.h> */
+#define HAVE_TIMERCLEAR 1
+
+/* Define if timercmp is defined in <sys/time.h> */
+#define HAVE_TIMERCMP 1
+
+/* Define if timerisset is defined in <sys/time.h> */
+#define HAVE_TIMERISSET 1
+
+/* Define to 1 if the system has the type `uint16_t'. */
+#define HAVE_UINT16_T 1
+
+/* Define to 1 if the system has the type `uint32_t'. */
+#define HAVE_UINT32_T 1
+
+/* Define to 1 if the system has the type `uint64_t'. */
+#define HAVE_UINT64_T 1
+
+/* Define to 1 if the system has the type `uint8_t'. */
+#define HAVE_UINT8_T 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `vasprintf' function. */
+#define HAVE_VASPRINTF 1
+
+/* Define if kqueue works correctly with pipes */
+/* #undef HAVE_WORKING_KQUEUE */
+
+/* Name of package */
+#define PACKAGE "libevent"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION ""
+
+/* The size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 8
+
+/* The size of `long long', as computed by sizeof. */
+#define SIZEOF_LONG_LONG 8
+
+/* The size of `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Version number of package */
+#define VERSION "1.4.13-stable"
+
+/* Define to appropriate substitue if compiler doesnt have __func__ */
+/* #undef __func__ */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef pid_t */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* Define to unsigned int if you dont have it */
+/* #undef socklen_t */
diff --git a/chromium/base/third_party/libevent/android/event-config.h b/chromium/base/third_party/libevent/android/event-config.h
new file mode 100644
index 00000000000..6563cb78d8a
--- /dev/null
+++ b/chromium/base/third_party/libevent/android/event-config.h
@@ -0,0 +1,281 @@
+/* Copied from Linux version and changed the features according Android, which
+ * is close to Linux */
+#ifndef _EVENT_CONFIG_H_
+#define _EVENT_CONFIG_H_
+/* config.h. Generated from config.h.in by configure. */
+/* config.h.in. Generated from configure.in by autoheader. */
+
+/* Define if clock_gettime is available in libc */
+#define _EVENT_DNS_USE_CPU_CLOCK_FOR_ID 1
+
+/* Define is no secure id variant is available */
+/* #undef _EVENT_DNS_USE_GETTIMEOFDAY_FOR_ID */
+
+/* Define to 1 if you have the `clock_gettime' function. */
+#define _EVENT_HAVE_CLOCK_GETTIME 1
+
+/* Define if /dev/poll is available */
+/* #undef _EVENT_HAVE_DEVPOLL */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define _EVENT_HAVE_DLFCN_H 1
+
+/* Define if your system supports the epoll system calls */
+#define _EVENT_HAVE_EPOLL 1
+
+/* Define to 1 if you have the `epoll_ctl' function. */
+#define _EVENT_HAVE_EPOLL_CTL 1
+
+/* Define if your system supports event ports */
+/* #undef _EVENT_HAVE_EVENT_PORTS */
+
+/* Define to 1 if you have the `fcntl' function. */
+#define _EVENT_HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define _EVENT_HAVE_FCNTL_H 1
+
+/* Define to 1 if the system has the type `fd_mask'. */
+/* #undef _EVENT_HAVE_FD_MASK 1 */
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#define _EVENT_HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `getegid' function. */
+#define _EVENT_HAVE_GETEGID 1
+
+/* Define to 1 if you have the `geteuid' function. */
+#define _EVENT_HAVE_GETEUID 1
+
+/* Define to 1 if you have the `getnameinfo' function. */
+#define _EVENT_HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define _EVENT_HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the `inet_ntop' function. */
+#define _EVENT_HAVE_INET_NTOP 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define _EVENT_HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `issetugid' function. */
+/* #undef _EVENT_HAVE_ISSETUGID */
+
+/* Define to 1 if you have the `kqueue' function. */
+/* #undef _EVENT_HAVE_KQUEUE */
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+#define _EVENT_HAVE_LIBNSL 1
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+#define _EVENT_HAVE_LIBRESOLV 1
+
+/* Define to 1 if you have the `rt' library (-lrt). */
+#define _EVENT_HAVE_LIBRT 1
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+/* #undef _EVENT_HAVE_LIBSOCKET */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define _EVENT_HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <netinet/in6.h> header file. */
+/* #undef _EVENT_HAVE_NETINET_IN6_H */
+
+/* Define to 1 if you have the `poll' function. */
+#define _EVENT_HAVE_POLL 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define _EVENT_HAVE_POLL_H 1
+
+/* Define to 1 if you have the `port_create' function. */
+/* #undef _EVENT_HAVE_PORT_CREATE */
+
+/* Define to 1 if you have the <port.h> header file. */
+/* #undef _EVENT_HAVE_PORT_H */
+
+/* Define to 1 if you have the `select' function. */
+#define _EVENT_HAVE_SELECT 1
+
+/* Define if F_SETFD is defined in <fcntl.h> */
+#define _EVENT_HAVE_SETFD 1
+
+/* Define to 1 if you have the `sigaction' function. */
+#define _EVENT_HAVE_SIGACTION 1
+
+/* Define to 1 if you have the `signal' function. */
+#define _EVENT_HAVE_SIGNAL 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define _EVENT_HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#define _EVENT_HAVE_STDARG_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define _EVENT_HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define _EVENT_HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define _EVENT_HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define _EVENT_HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+#define _EVENT_HAVE_STRLCPY 1
+
+/* Define to 1 if you have the `strsep' function. */
+#define _EVENT_HAVE_STRSEP 1
+
+/* Define to 1 if you have the `strtok_r' function. */
+#define _EVENT_HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the `strtoll' function. */
+#define _EVENT_HAVE_STRTOLL 1
+
+/* Define to 1 if the system has the type `struct in6_addr'. */
+#define _EVENT_HAVE_STRUCT_IN6_ADDR 1
+
+/* Define to 1 if you have the <sys/devpoll.h> header file. */
+/* #undef _EVENT_HAVE_SYS_DEVPOLL_H */
+
+/* Define to 1 if you have the <sys/epoll.h> header file. */
+#define _EVENT_HAVE_SYS_EPOLL_H 1
+
+/* Define to 1 if you have the <sys/event.h> header file. */
+/* #undef _EVENT_HAVE_SYS_EVENT_H */
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define _EVENT_HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define _EVENT_HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/queue.h> header file. */
+#define _EVENT_HAVE_SYS_QUEUE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define _EVENT_HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define _EVENT_HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define _EVENT_HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define _EVENT_HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define _EVENT_HAVE_SYS_TYPES_H 1
+
+/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
+#define _EVENT_HAVE_TAILQFOREACH 1
+
+/* Define if timeradd is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERADD 1
+
+/* Define if timerclear is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERCLEAR 1
+
+/* Define if timercmp is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERCMP 1
+
+/* Define if timerisset is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERISSET 1
+
+/* Define to 1 if the system has the type `uint16_t'. */
+#define _EVENT_HAVE_UINT16_T 1
+
+/* Define to 1 if the system has the type `uint32_t'. */
+#define _EVENT_HAVE_UINT32_T 1
+
+/* Define to 1 if the system has the type `uint64_t'. */
+#define _EVENT_HAVE_UINT64_T 1
+
+/* Define to 1 if the system has the type `uint8_t'. */
+#define _EVENT_HAVE_UINT8_T 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define _EVENT_HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `vasprintf' function. */
+#define _EVENT_HAVE_VASPRINTF 1
+
+/* Define if kqueue works correctly with pipes */
+/* #undef _EVENT_HAVE_WORKING_KQUEUE */
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+#define _EVENT_LT_OBJDIR ".libs/"
+
+/* Numeric representation of the version */
+#define _EVENT_NUMERIC_VERSION 0x01040f00
+
+/* Name of package */
+#define _EVENT_PACKAGE "libevent"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define _EVENT_PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define _EVENT_PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define _EVENT_PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define _EVENT_PACKAGE_TARNAME ""
+
+/* Define to the home page for this package. */
+#define _EVENT_PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define _EVENT_PACKAGE_VERSION ""
+
+/* The size of `int', as computed by sizeof. */
+#define _EVENT_SIZEOF_INT 4
+
+/* The size of `long', as computed by sizeof. */
+#define _EVENT_SIZEOF_LONG 8
+
+/* The size of `long long', as computed by sizeof. */
+#define _EVENT_SIZEOF_LONG_LONG 8
+
+/* The size of `short', as computed by sizeof. */
+#define _EVENT_SIZEOF_SHORT 2
+
+/* Define to 1 if you have the ANSI C header files. */
+#define _EVENT_STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define _EVENT_TIME_WITH_SYS_TIME 1
+
+/* Version number of package */
+#define _EVENT_VERSION "1.4.15"
+
+/* Define to appropriate substitue if compiler doesnt have __func__ */
+/* #undef _EVENT___func__ */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef _EVENT_const */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef _EVENT___cplusplus
+/* #undef _EVENT_inline */
+#endif
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef _EVENT_pid_t */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef _EVENT_size_t */
+
+/* Define to unsigned int if you dont have it */
+/* #undef _EVENT_socklen_t */
+#endif
diff --git a/chromium/base/third_party/libevent/autogen.sh b/chromium/base/third_party/libevent/autogen.sh
new file mode 100755
index 00000000000..099cb30501d
--- /dev/null
+++ b/chromium/base/third_party/libevent/autogen.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+if [ -x "`which autoreconf 2>/dev/null`" ] ; then
+ exec autoreconf -ivf
+fi
+
+LIBTOOLIZE=libtoolize
+SYSNAME=`uname`
+if [ "x$SYSNAME" = "xDarwin" ] ; then
+ LIBTOOLIZE=glibtoolize
+fi
+aclocal && \
+ autoheader && \
+ $LIBTOOLIZE && \
+ autoconf && \
+ automake --add-missing --copy
diff --git a/chromium/base/third_party/libevent/buffer.c b/chromium/base/third_party/libevent/buffer.c
new file mode 100644
index 00000000000..ebf35c9b691
--- /dev/null
+++ b/chromium/base/third_party/libevent/buffer.c
@@ -0,0 +1,554 @@
+/*
+ * Copyright (c) 2002, 2003 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef WIN32
+#include <winsock2.h>
+#include <windows.h>
+#endif
+
+#ifdef HAVE_VASPRINTF
+/* If we have vasprintf, we need to define this before we include stdio.h. */
+#define _GNU_SOURCE
+#endif
+
+#include <sys/types.h>
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_STDARG_H
+#include <stdarg.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "event.h"
+#include "config.h"
+#include "evutil.h"
+#include "./log.h"
+
+struct evbuffer *
+evbuffer_new(void)
+{
+ struct evbuffer *buffer;
+
+ buffer = calloc(1, sizeof(struct evbuffer));
+
+ return (buffer);
+}
+
+void
+evbuffer_free(struct evbuffer *buffer)
+{
+ if (buffer->orig_buffer != NULL)
+ free(buffer->orig_buffer);
+ free(buffer);
+}
+
+/*
+ * This is a destructive add. The data from one buffer moves into
+ * the other buffer.
+ */
+
+#define SWAP(x,y) do { \
+ (x)->buffer = (y)->buffer; \
+ (x)->orig_buffer = (y)->orig_buffer; \
+ (x)->misalign = (y)->misalign; \
+ (x)->totallen = (y)->totallen; \
+ (x)->off = (y)->off; \
+} while (0)
+
+int
+evbuffer_add_buffer(struct evbuffer *outbuf, struct evbuffer *inbuf)
+{
+ int res;
+
+ /* Short cut for better performance */
+ if (outbuf->off == 0) {
+ struct evbuffer tmp;
+ size_t oldoff = inbuf->off;
+
+ /* Swap them directly */
+ SWAP(&tmp, outbuf);
+ SWAP(outbuf, inbuf);
+ SWAP(inbuf, &tmp);
+
+ /*
+ * Optimization comes with a price; we need to notify the
+ * buffer if necessary of the changes. oldoff is the amount
+ * of data that we transfered from inbuf to outbuf
+ */
+ if (inbuf->off != oldoff && inbuf->cb != NULL)
+ (*inbuf->cb)(inbuf, oldoff, inbuf->off, inbuf->cbarg);
+ if (oldoff && outbuf->cb != NULL)
+ (*outbuf->cb)(outbuf, 0, oldoff, outbuf->cbarg);
+
+ return (0);
+ }
+
+ res = evbuffer_add(outbuf, inbuf->buffer, inbuf->off);
+ if (res == 0) {
+ /* We drain the input buffer on success */
+ evbuffer_drain(inbuf, inbuf->off);
+ }
+
+ return (res);
+}
+
+int
+evbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap)
+{
+ char *buffer;
+ size_t space;
+ size_t oldoff = buf->off;
+ int sz;
+ va_list aq;
+
+ /* make sure that at least some space is available */
+ if (evbuffer_expand(buf, 64) < 0)
+ return (-1);
+ for (;;) {
+ size_t used = buf->misalign + buf->off;
+ buffer = (char *)buf->buffer + buf->off;
+ assert(buf->totallen >= used);
+ space = buf->totallen - used;
+
+#ifndef va_copy
+#define va_copy(dst, src) memcpy(&(dst), &(src), sizeof(va_list))
+#endif
+ va_copy(aq, ap);
+
+ sz = evutil_vsnprintf(buffer, space, fmt, aq);
+
+ va_end(aq);
+
+ if (sz < 0)
+ return (-1);
+ if ((size_t)sz < space) {
+ buf->off += sz;
+ if (buf->cb != NULL)
+ (*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
+ return (sz);
+ }
+ if (evbuffer_expand(buf, sz + 1) == -1)
+ return (-1);
+
+ }
+ /* NOTREACHED */
+}
+
+int
+evbuffer_add_printf(struct evbuffer *buf, const char *fmt, ...)
+{
+ int res = -1;
+ va_list ap;
+
+ va_start(ap, fmt);
+ res = evbuffer_add_vprintf(buf, fmt, ap);
+ va_end(ap);
+
+ return (res);
+}
+
+/* Reads data from an event buffer and drains the bytes read */
+
+int
+evbuffer_remove(struct evbuffer *buf, void *data, size_t datlen)
+{
+ size_t nread = datlen;
+ if (nread >= buf->off)
+ nread = buf->off;
+
+ memcpy(data, buf->buffer, nread);
+ evbuffer_drain(buf, nread);
+
+ return (nread);
+}
+
+/*
+ * Reads a line terminated by either '\r\n', '\n\r' or '\r' or '\n'.
+ * The returned buffer needs to be freed by the called.
+ */
+
+char *
+evbuffer_readline(struct evbuffer *buffer)
+{
+ u_char *data = EVBUFFER_DATA(buffer);
+ size_t len = EVBUFFER_LENGTH(buffer);
+ char *line;
+ unsigned int i;
+
+ for (i = 0; i < len; i++) {
+ if (data[i] == '\r' || data[i] == '\n')
+ break;
+ }
+
+ if (i == len)
+ return (NULL);
+
+ if ((line = malloc(i + 1)) == NULL) {
+ fprintf(stderr, "%s: out of memory\n", __func__);
+ return (NULL);
+ }
+
+ memcpy(line, data, i);
+ line[i] = '\0';
+
+ /*
+ * Some protocols terminate a line with '\r\n', so check for
+ * that, too.
+ */
+ if ( i < len - 1 ) {
+ char fch = data[i], sch = data[i+1];
+
+ /* Drain one more character if needed */
+ if ( (sch == '\r' || sch == '\n') && sch != fch )
+ i += 1;
+ }
+
+ evbuffer_drain(buffer, i + 1);
+
+ return (line);
+}
+
+
+char *
+evbuffer_readln(struct evbuffer *buffer, size_t *n_read_out,
+ enum evbuffer_eol_style eol_style)
+{
+ u_char *data = EVBUFFER_DATA(buffer);
+ u_char *start_of_eol, *end_of_eol;
+ size_t len = EVBUFFER_LENGTH(buffer);
+ char *line;
+ unsigned int i, n_to_copy, n_to_drain;
+
+ if (n_read_out)
+ *n_read_out = 0;
+
+ /* depending on eol_style, set start_of_eol to the first character
+ * in the newline, and end_of_eol to one after the last character. */
+ switch (eol_style) {
+ case EVBUFFER_EOL_ANY:
+ for (i = 0; i < len; i++) {
+ if (data[i] == '\r' || data[i] == '\n')
+ break;
+ }
+ if (i == len)
+ return (NULL);
+ start_of_eol = data+i;
+ ++i;
+ for ( ; i < len; i++) {
+ if (data[i] != '\r' && data[i] != '\n')
+ break;
+ }
+ end_of_eol = data+i;
+ break;
+ case EVBUFFER_EOL_CRLF:
+ end_of_eol = memchr(data, '\n', len);
+ if (!end_of_eol)
+ return (NULL);
+ if (end_of_eol > data && *(end_of_eol-1) == '\r')
+ start_of_eol = end_of_eol - 1;
+ else
+ start_of_eol = end_of_eol;
+ end_of_eol++; /*point to one after the LF. */
+ break;
+ case EVBUFFER_EOL_CRLF_STRICT: {
+ u_char *cp = data;
+ while ((cp = memchr(cp, '\r', len-(cp-data)))) {
+ if (cp < data+len-1 && *(cp+1) == '\n')
+ break;
+ if (++cp >= data+len) {
+ cp = NULL;
+ break;
+ }
+ }
+ if (!cp)
+ return (NULL);
+ start_of_eol = cp;
+ end_of_eol = cp+2;
+ break;
+ }
+ case EVBUFFER_EOL_LF:
+ start_of_eol = memchr(data, '\n', len);
+ if (!start_of_eol)
+ return (NULL);
+ end_of_eol = start_of_eol + 1;
+ break;
+ default:
+ return (NULL);
+ }
+
+ n_to_copy = start_of_eol - data;
+ n_to_drain = end_of_eol - data;
+
+ if ((line = malloc(n_to_copy+1)) == NULL) {
+ event_warn("%s: out of memory\n", __func__);
+ return (NULL);
+ }
+
+ memcpy(line, data, n_to_copy);
+ line[n_to_copy] = '\0';
+
+ evbuffer_drain(buffer, n_to_drain);
+ if (n_read_out)
+ *n_read_out = (size_t)n_to_copy;
+
+ return (line);
+}
+
+/* Adds data to an event buffer */
+
+static void
+evbuffer_align(struct evbuffer *buf)
+{
+ memmove(buf->orig_buffer, buf->buffer, buf->off);
+ buf->buffer = buf->orig_buffer;
+ buf->misalign = 0;
+}
+
+#ifndef SIZE_MAX
+#define SIZE_MAX ((size_t)-1)
+#endif
+
+/* Expands the available space in the event buffer to at least datlen */
+
+int
+evbuffer_expand(struct evbuffer *buf, size_t datlen)
+{
+ size_t used = buf->misalign + buf->off;
+
+ assert(buf->totallen >= used);
+
+ /* If we can fit all the data, then we don't have to do anything */
+ if (buf->totallen - used >= datlen)
+ return (0);
+ /* If we would need to overflow to fit this much data, we can't
+ * do anything. */
+ if (datlen > SIZE_MAX - buf->off)
+ return (-1);
+
+ /*
+ * If the misalignment fulfills our data needs, we just force an
+ * alignment to happen. Afterwards, we have enough space.
+ */
+ if (buf->totallen - buf->off >= datlen) {
+ evbuffer_align(buf);
+ } else {
+ void *newbuf;
+ size_t length = buf->totallen;
+ size_t need = buf->off + datlen;
+
+ if (length < 256)
+ length = 256;
+ if (need < SIZE_MAX / 2) {
+ while (length < need) {
+ length <<= 1;
+ }
+ } else {
+ length = need;
+ }
+
+ if (buf->orig_buffer != buf->buffer)
+ evbuffer_align(buf);
+ if ((newbuf = realloc(buf->buffer, length)) == NULL)
+ return (-1);
+
+ buf->orig_buffer = buf->buffer = newbuf;
+ buf->totallen = length;
+ }
+
+ return (0);
+}
+
+int
+evbuffer_add(struct evbuffer *buf, const void *data, size_t datlen)
+{
+ size_t used = buf->misalign + buf->off;
+ size_t oldoff = buf->off;
+
+ if (buf->totallen - used < datlen) {
+ if (evbuffer_expand(buf, datlen) == -1)
+ return (-1);
+ }
+
+ memcpy(buf->buffer + buf->off, data, datlen);
+ buf->off += datlen;
+
+ if (datlen && buf->cb != NULL)
+ (*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
+
+ return (0);
+}
+
+void
+evbuffer_drain(struct evbuffer *buf, size_t len)
+{
+ size_t oldoff = buf->off;
+
+ if (len >= buf->off) {
+ buf->off = 0;
+ buf->buffer = buf->orig_buffer;
+ buf->misalign = 0;
+ goto done;
+ }
+
+ buf->buffer += len;
+ buf->misalign += len;
+
+ buf->off -= len;
+
+ done:
+ /* Tell someone about changes in this buffer */
+ if (buf->off != oldoff && buf->cb != NULL)
+ (*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
+
+}
+
+/*
+ * Reads data from a file descriptor into a buffer.
+ */
+
+#define EVBUFFER_MAX_READ 4096
+
+int
+evbuffer_read(struct evbuffer *buf, int fd, int howmuch)
+{
+ u_char *p;
+ size_t oldoff = buf->off;
+ int n = EVBUFFER_MAX_READ;
+
+#if defined(FIONREAD)
+#ifdef WIN32
+ long lng = n;
+ if (ioctlsocket(fd, FIONREAD, &lng) == -1 || (n=lng) <= 0) {
+#else
+ if (ioctl(fd, FIONREAD, &n) == -1 || n <= 0) {
+#endif
+ n = EVBUFFER_MAX_READ;
+ } else if (n > EVBUFFER_MAX_READ && n > howmuch) {
+ /*
+ * It's possible that a lot of data is available for
+ * reading. We do not want to exhaust resources
+ * before the reader has a chance to do something
+ * about it. If the reader does not tell us how much
+ * data we should read, we artifically limit it.
+ */
+ if ((size_t)n > buf->totallen << 2)
+ n = buf->totallen << 2;
+ if (n < EVBUFFER_MAX_READ)
+ n = EVBUFFER_MAX_READ;
+ }
+#endif
+ if (howmuch < 0 || howmuch > n)
+ howmuch = n;
+
+ /* If we don't have FIONREAD, we might waste some space here */
+ if (evbuffer_expand(buf, howmuch) == -1)
+ return (-1);
+
+ /* We can append new data at this point */
+ p = buf->buffer + buf->off;
+
+#ifndef WIN32
+ n = read(fd, p, howmuch);
+#else
+ n = recv(fd, p, howmuch, 0);
+#endif
+ if (n == -1)
+ return (-1);
+ if (n == 0)
+ return (0);
+
+ buf->off += n;
+
+ /* Tell someone about changes in this buffer */
+ if (buf->off != oldoff && buf->cb != NULL)
+ (*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
+
+ return (n);
+}
+
+int
+evbuffer_write(struct evbuffer *buffer, int fd)
+{
+ int n;
+
+#ifndef WIN32
+ n = write(fd, buffer->buffer, buffer->off);
+#else
+ n = send(fd, buffer->buffer, buffer->off, 0);
+#endif
+ if (n == -1)
+ return (-1);
+ if (n == 0)
+ return (0);
+ evbuffer_drain(buffer, n);
+
+ return (n);
+}
+
+u_char *
+evbuffer_find(struct evbuffer *buffer, const u_char *what, size_t len)
+{
+ u_char *search = buffer->buffer, *end = search + buffer->off;
+ u_char *p;
+
+ while (search < end &&
+ (p = memchr(search, *what, end - search)) != NULL) {
+ if (p + len > end)
+ break;
+ if (memcmp(p, what, len) == 0)
+ return (p);
+ search = p + 1;
+ }
+
+ return (NULL);
+}
+
+void evbuffer_setcb(struct evbuffer *buffer,
+ void (*cb)(struct evbuffer *, size_t, size_t, void *),
+ void *cbarg)
+{
+ buffer->cb = cb;
+ buffer->cbarg = cbarg;
+}
diff --git a/chromium/base/third_party/libevent/chromium.patch b/chromium/base/third_party/libevent/chromium.patch
new file mode 100644
index 00000000000..f6e00e84fa3
--- /dev/null
+++ b/chromium/base/third_party/libevent/chromium.patch
@@ -0,0 +1,200 @@
+diff --git a/third_party/libevent/buffer.c b/third_party/libevent/buffer.c
+index 64324bb..ebf35c9 100644
+--- a/third_party/libevent/buffer.c
++++ b/third_party/libevent/buffer.c
+@@ -356,7 +356,6 @@ int
+ evbuffer_expand(struct evbuffer *buf, size_t datlen)
+ {
+ size_t used = buf->misalign + buf->off;
+- size_t need;
+
+ assert(buf->totallen >= used);
+
+diff --git a/third_party/libevent/evdns.c b/third_party/libevent/evdns.c
+index fa23163..f1c70d0 100644
+--- a/third_party/libevent/evdns.c
++++ b/third_party/libevent/evdns.c
+@@ -55,7 +55,9 @@
+ #endif
+
+ /* #define _POSIX_C_SOURCE 200507 */
++#ifndef _GNU_SOURCE
+ #define _GNU_SOURCE
++#endif
+
+ #ifdef DNS_USE_CPU_CLOCK_FOR_ID
+ #ifdef DNS_USE_OPENSSL_FOR_ID
+@@ -134,7 +136,7 @@
+ typedef ev_uint8_t u_char;
+ typedef unsigned int uint;
+ #endif
+-#include <event.h>
++#include "event.h"
+
+ #define u64 ev_uint64_t
+ #define u32 ev_uint32_t
+diff --git a/third_party/libevent/evdns.h b/third_party/libevent/evdns.h
+index 1eb5c38..fca4ac3 100644
+--- a/third_party/libevent/evdns.h
++++ b/third_party/libevent/evdns.h
+@@ -165,7 +165,7 @@ extern "C" {
+ #endif
+
+ /* For integer types. */
+-#include <evutil.h>
++#include "evutil.h"
+
+ /** Error codes 0-5 are as described in RFC 1035. */
+ #define DNS_ERR_NONE 0
+diff --git a/third_party/libevent/event.c b/third_party/libevent/event.c
+index da6cd42..36b1c51 100644
+--- a/third_party/libevent/event.c
++++ b/third_party/libevent/event.c
+@@ -107,7 +107,7 @@ static const struct eventop *eventops[] = {
+ /* Global state */
+ struct event_base *current_base = NULL;
+ extern struct event_base *evsignal_base;
+-static int use_monotonic;
++static int use_monotonic = 1;
+
+ /* Handle signals - This is a deprecated interface */
+ int (*event_sigcb)(void); /* Signal callback when gotsig is set */
+@@ -124,17 +124,6 @@ static int timeout_next(struct event_base *, struct timeval **);
+ static void timeout_process(struct event_base *);
+ static void timeout_correct(struct event_base *, struct timeval *);
+
+-static void
+-detect_monotonic(void)
+-{
+-#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
+- struct timespec ts;
+-
+- if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
+- use_monotonic = 1;
+-#endif
+-}
+-
+ static int
+ gettime(struct event_base *base, struct timeval *tp)
+ {
+@@ -144,18 +133,18 @@ gettime(struct event_base *base, struct timeval *tp)
+ }
+
+ #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
+- if (use_monotonic) {
+- struct timespec ts;
+-
+- if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
+- return (-1);
++ struct timespec ts;
+
++ if (use_monotonic &&
++ clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
+ tp->tv_sec = ts.tv_sec;
+ tp->tv_usec = ts.tv_nsec / 1000;
+ return (0);
+ }
+ #endif
+
++ use_monotonic = 0;
++
+ return (evutil_gettimeofday(tp, NULL));
+ }
+
+@@ -182,7 +171,6 @@ event_base_new(void)
+ event_sigcb = NULL;
+ event_gotsig = 0;
+
+- detect_monotonic();
+ gettime(base, &base->event_tv);
+
+ min_heap_ctor(&base->timeheap);
+@@ -398,12 +386,9 @@ event_process_active(struct event_base *base)
+ ncalls--;
+ ev->ev_ncalls = ncalls;
+ (*ev->ev_callback)((int)ev->ev_fd, ev->ev_res, ev->ev_arg);
+- if (event_gotsig || base->event_break) {
+- ev->ev_pncalls = NULL;
++ if (event_gotsig || base->event_break)
+ return;
+- }
+ }
+- ev->ev_pncalls = NULL;
+ }
+ }
+
+@@ -808,8 +793,6 @@ int
+ event_del(struct event *ev)
+ {
+ struct event_base *base;
+- const struct eventop *evsel;
+- void *evbase;
+
+ event_debug(("event_del: %p, callback %p",
+ ev, ev->ev_callback));
+@@ -819,8 +802,6 @@ event_del(struct event *ev)
+ return (-1);
+
+ base = ev->ev_base;
+- evsel = base->evsel;
+- evbase = base->evbase;
+
+ assert(!(ev->ev_flags & ~EVLIST_ALL));
+
+@@ -838,7 +819,7 @@ event_del(struct event *ev)
+
+ if (ev->ev_flags & EVLIST_INSERTED) {
+ event_queue_remove(base, ev, EVLIST_INSERTED);
+- return (evsel->del(evbase, ev));
++ return (base->evsel->del(base->evbase, ev));
+ }
+
+ return (0);
+diff --git a/third_party/libevent/event.h b/third_party/libevent/event.h
+index d1f5d9e..f0887b9 100644
+--- a/third_party/libevent/event.h
++++ b/third_party/libevent/event.h
+@@ -159,7 +159,7 @@
+ extern "C" {
+ #endif
+
+-#include <event-config.h>
++#include "event-config.h"
+ #ifdef _EVENT_HAVE_SYS_TYPES_H
+ #include <sys/types.h>
+ #endif
+@@ -172,7 +172,7 @@ extern "C" {
+ #include <stdarg.h>
+
+ /* For int types. */
+-#include <evutil.h>
++#include "evutil.h"
+
+ #ifdef WIN32
+ #define WIN32_LEAN_AND_MEAN
+diff --git a/third_party/libevent/evhttp.h b/third_party/libevent/evhttp.h
+index cba8be1..48c1d91 100644
+--- a/third_party/libevent/evhttp.h
++++ b/third_party/libevent/evhttp.h
+@@ -27,7 +27,7 @@
+ #ifndef _EVHTTP_H_
+ #define _EVHTTP_H_
+
+-#include <event.h>
++#include "event.h"
+
+ #ifdef __cplusplus
+ extern "C" {
+diff --git a/third_party/libevent/evutil.h b/third_party/libevent/evutil.h
+index dcb0013..8b664b9 100644
+--- a/third_party/libevent/evutil.h
++++ b/third_party/libevent/evutil.h
+@@ -38,7 +38,7 @@
+ extern "C" {
+ #endif
+
+-#include <event-config.h>
++#include "event-config.h"
+ #ifdef _EVENT_HAVE_SYS_TIME_H
+ #include <sys/time.h>
+ #endif
diff --git a/chromium/base/third_party/libevent/compat/sys/_libevent_time.h b/chromium/base/third_party/libevent/compat/sys/_libevent_time.h
new file mode 100644
index 00000000000..8cabb0d55e7
--- /dev/null
+++ b/chromium/base/third_party/libevent/compat/sys/_libevent_time.h
@@ -0,0 +1,163 @@
+/* $OpenBSD: time.h,v 1.11 2000/10/10 13:36:48 itojun Exp $ */
+/* $NetBSD: time.h,v 1.18 1996/04/23 10:29:33 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1982, 1986, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)time.h 8.2 (Berkeley) 7/10/94
+ */
+
+#ifndef _SYS_TIME_H_
+#define _SYS_TIME_H_
+
+#include <sys/types.h>
+
+/*
+ * Structure returned by gettimeofday(2) system call,
+ * and used in other calls.
+ */
+struct timeval {
+ long tv_sec; /* seconds */
+ long tv_usec; /* and microseconds */
+};
+
+/*
+ * Structure defined by POSIX.1b to be like a timeval.
+ */
+struct timespec {
+ time_t tv_sec; /* seconds */
+ long tv_nsec; /* and nanoseconds */
+};
+
+#define TIMEVAL_TO_TIMESPEC(tv, ts) { \
+ (ts)->tv_sec = (tv)->tv_sec; \
+ (ts)->tv_nsec = (tv)->tv_usec * 1000; \
+}
+#define TIMESPEC_TO_TIMEVAL(tv, ts) { \
+ (tv)->tv_sec = (ts)->tv_sec; \
+ (tv)->tv_usec = (ts)->tv_nsec / 1000; \
+}
+
+struct timezone {
+ int tz_minuteswest; /* minutes west of Greenwich */
+ int tz_dsttime; /* type of dst correction */
+};
+#define DST_NONE 0 /* not on dst */
+#define DST_USA 1 /* USA style dst */
+#define DST_AUST 2 /* Australian style dst */
+#define DST_WET 3 /* Western European dst */
+#define DST_MET 4 /* Middle European dst */
+#define DST_EET 5 /* Eastern European dst */
+#define DST_CAN 6 /* Canada */
+
+/* Operations on timevals. */
+#define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0
+#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec)
+#define timercmp(tvp, uvp, cmp) \
+ (((tvp)->tv_sec == (uvp)->tv_sec) ? \
+ ((tvp)->tv_usec cmp (uvp)->tv_usec) : \
+ ((tvp)->tv_sec cmp (uvp)->tv_sec))
+#define timeradd(tvp, uvp, vvp) \
+ do { \
+ (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \
+ (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \
+ if ((vvp)->tv_usec >= 1000000) { \
+ (vvp)->tv_sec++; \
+ (vvp)->tv_usec -= 1000000; \
+ } \
+ } while (0)
+#define timersub(tvp, uvp, vvp) \
+ do { \
+ (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \
+ (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \
+ if ((vvp)->tv_usec < 0) { \
+ (vvp)->tv_sec--; \
+ (vvp)->tv_usec += 1000000; \
+ } \
+ } while (0)
+
+/* Operations on timespecs. */
+#define timespecclear(tsp) (tsp)->tv_sec = (tsp)->tv_nsec = 0
+#define timespecisset(tsp) ((tsp)->tv_sec || (tsp)->tv_nsec)
+#define timespeccmp(tsp, usp, cmp) \
+ (((tsp)->tv_sec == (usp)->tv_sec) ? \
+ ((tsp)->tv_nsec cmp (usp)->tv_nsec) : \
+ ((tsp)->tv_sec cmp (usp)->tv_sec))
+#define timespecadd(tsp, usp, vsp) \
+ do { \
+ (vsp)->tv_sec = (tsp)->tv_sec + (usp)->tv_sec; \
+ (vsp)->tv_nsec = (tsp)->tv_nsec + (usp)->tv_nsec; \
+ if ((vsp)->tv_nsec >= 1000000000L) { \
+ (vsp)->tv_sec++; \
+ (vsp)->tv_nsec -= 1000000000L; \
+ } \
+ } while (0)
+#define timespecsub(tsp, usp, vsp) \
+ do { \
+ (vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec; \
+ (vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec; \
+ if ((vsp)->tv_nsec < 0) { \
+ (vsp)->tv_sec--; \
+ (vsp)->tv_nsec += 1000000000L; \
+ } \
+ } while (0)
+
+/*
+ * Names of the interval timers, and structure
+ * defining a timer setting.
+ */
+#define ITIMER_REAL 0
+#define ITIMER_VIRTUAL 1
+#define ITIMER_PROF 2
+
+struct itimerval {
+ struct timeval it_interval; /* timer interval */
+ struct timeval it_value; /* current value */
+};
+
+/*
+ * Getkerninfo clock information structure
+ */
+struct clockinfo {
+ int hz; /* clock frequency */
+ int tick; /* micro-seconds per hz tick */
+ int tickadj; /* clock skew rate for adjtime() */
+ int stathz; /* statistics clock frequency */
+ int profhz; /* profiling clock frequency */
+};
+
+#define CLOCK_REALTIME 0
+#define CLOCK_VIRTUAL 1
+#define CLOCK_PROF 2
+
+#define TIMER_RELTIME 0x0 /* relative timer */
+#define TIMER_ABSTIME 0x1 /* absolute timer */
+
+/* --- stuff got cut here - niels --- */
+
+#endif /* !_SYS_TIME_H_ */
diff --git a/chromium/base/third_party/libevent/compat/sys/queue.h b/chromium/base/third_party/libevent/compat/sys/queue.h
new file mode 100644
index 00000000000..c0956ddce43
--- /dev/null
+++ b/chromium/base/third_party/libevent/compat/sys/queue.h
@@ -0,0 +1,488 @@
+/* $OpenBSD: queue.h,v 1.16 2000/09/07 19:47:59 art Exp $ */
+/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)queue.h 8.5 (Berkeley) 8/20/94
+ */
+
+#ifndef _SYS_QUEUE_H_
+#define _SYS_QUEUE_H_
+
+/*
+ * This file defines five types of data structures: singly-linked lists,
+ * lists, simple queues, tail queues, and circular queues.
+ *
+ *
+ * A singly-linked list is headed by a single forward pointer. The elements
+ * are singly linked for minimum space and pointer manipulation overhead at
+ * the expense of O(n) removal for arbitrary elements. New elements can be
+ * added to the list after an existing element or at the head of the list.
+ * Elements being removed from the head of the list should use the explicit
+ * macro for this purpose for optimum efficiency. A singly-linked list may
+ * only be traversed in the forward direction. Singly-linked lists are ideal
+ * for applications with large datasets and few or no removals or for
+ * implementing a LIFO queue.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A simple queue is headed by a pair of pointers, one the head of the
+ * list and the other to the tail of the list. The elements are singly
+ * linked to save space, so elements can only be removed from the
+ * head of the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the
+ * list. A simple queue may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * A circle queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the list.
+ * A circle queue may be traversed in either direction, but has a more
+ * complex end of list detection.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ */
+
+/*
+ * Singly-linked List definitions.
+ */
+#define SLIST_HEAD(name, type) \
+struct name { \
+ struct type *slh_first; /* first element */ \
+}
+
+#define SLIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+#ifndef WIN32
+#define SLIST_ENTRY(type) \
+struct { \
+ struct type *sle_next; /* next element */ \
+}
+#endif
+
+/*
+ * Singly-linked List access methods.
+ */
+#define SLIST_FIRST(head) ((head)->slh_first)
+#define SLIST_END(head) NULL
+#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head))
+#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
+
+#define SLIST_FOREACH(var, head, field) \
+ for((var) = SLIST_FIRST(head); \
+ (var) != SLIST_END(head); \
+ (var) = SLIST_NEXT(var, field))
+
+/*
+ * Singly-linked List functions.
+ */
+#define SLIST_INIT(head) { \
+ SLIST_FIRST(head) = SLIST_END(head); \
+}
+
+#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
+ (elm)->field.sle_next = (slistelm)->field.sle_next; \
+ (slistelm)->field.sle_next = (elm); \
+} while (0)
+
+#define SLIST_INSERT_HEAD(head, elm, field) do { \
+ (elm)->field.sle_next = (head)->slh_first; \
+ (head)->slh_first = (elm); \
+} while (0)
+
+#define SLIST_REMOVE_HEAD(head, field) do { \
+ (head)->slh_first = (head)->slh_first->field.sle_next; \
+} while (0)
+
+/*
+ * List definitions.
+ */
+#define LIST_HEAD(name, type) \
+struct name { \
+ struct type *lh_first; /* first element */ \
+}
+
+#define LIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+#define LIST_ENTRY(type) \
+struct { \
+ struct type *le_next; /* next element */ \
+ struct type **le_prev; /* address of previous next element */ \
+}
+
+/*
+ * List access methods
+ */
+#define LIST_FIRST(head) ((head)->lh_first)
+#define LIST_END(head) NULL
+#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head))
+#define LIST_NEXT(elm, field) ((elm)->field.le_next)
+
+#define LIST_FOREACH(var, head, field) \
+ for((var) = LIST_FIRST(head); \
+ (var)!= LIST_END(head); \
+ (var) = LIST_NEXT(var, field))
+
+/*
+ * List functions.
+ */
+#define LIST_INIT(head) do { \
+ LIST_FIRST(head) = LIST_END(head); \
+} while (0)
+
+#define LIST_INSERT_AFTER(listelm, elm, field) do { \
+ if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
+ (listelm)->field.le_next->field.le_prev = \
+ &(elm)->field.le_next; \
+ (listelm)->field.le_next = (elm); \
+ (elm)->field.le_prev = &(listelm)->field.le_next; \
+} while (0)
+
+#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
+ (elm)->field.le_prev = (listelm)->field.le_prev; \
+ (elm)->field.le_next = (listelm); \
+ *(listelm)->field.le_prev = (elm); \
+ (listelm)->field.le_prev = &(elm)->field.le_next; \
+} while (0)
+
+#define LIST_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.le_next = (head)->lh_first) != NULL) \
+ (head)->lh_first->field.le_prev = &(elm)->field.le_next;\
+ (head)->lh_first = (elm); \
+ (elm)->field.le_prev = &(head)->lh_first; \
+} while (0)
+
+#define LIST_REMOVE(elm, field) do { \
+ if ((elm)->field.le_next != NULL) \
+ (elm)->field.le_next->field.le_prev = \
+ (elm)->field.le_prev; \
+ *(elm)->field.le_prev = (elm)->field.le_next; \
+} while (0)
+
+#define LIST_REPLACE(elm, elm2, field) do { \
+ if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
+ (elm2)->field.le_next->field.le_prev = \
+ &(elm2)->field.le_next; \
+ (elm2)->field.le_prev = (elm)->field.le_prev; \
+ *(elm2)->field.le_prev = (elm2); \
+} while (0)
+
+/*
+ * Simple queue definitions.
+ */
+#define SIMPLEQ_HEAD(name, type) \
+struct name { \
+ struct type *sqh_first; /* first element */ \
+ struct type **sqh_last; /* addr of last next element */ \
+}
+
+#define SIMPLEQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).sqh_first }
+
+#define SIMPLEQ_ENTRY(type) \
+struct { \
+ struct type *sqe_next; /* next element */ \
+}
+
+/*
+ * Simple queue access methods.
+ */
+#define SIMPLEQ_FIRST(head) ((head)->sqh_first)
+#define SIMPLEQ_END(head) NULL
+#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
+#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
+
+#define SIMPLEQ_FOREACH(var, head, field) \
+ for((var) = SIMPLEQ_FIRST(head); \
+ (var) != SIMPLEQ_END(head); \
+ (var) = SIMPLEQ_NEXT(var, field))
+
+/*
+ * Simple queue functions.
+ */
+#define SIMPLEQ_INIT(head) do { \
+ (head)->sqh_first = NULL; \
+ (head)->sqh_last = &(head)->sqh_first; \
+} while (0)
+
+#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+ (head)->sqh_first = (elm); \
+} while (0)
+
+#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.sqe_next = NULL; \
+ *(head)->sqh_last = (elm); \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+} while (0)
+
+#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+ (listelm)->field.sqe_next = (elm); \
+} while (0)
+
+#define SIMPLEQ_REMOVE_HEAD(head, elm, field) do { \
+ if (((head)->sqh_first = (elm)->field.sqe_next) == NULL) \
+ (head)->sqh_last = &(head)->sqh_first; \
+} while (0)
+
+/*
+ * Tail queue definitions.
+ */
+#define TAILQ_HEAD(name, type) \
+struct name { \
+ struct type *tqh_first; /* first element */ \
+ struct type **tqh_last; /* addr of last next element */ \
+}
+
+#define TAILQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).tqh_first }
+
+#define TAILQ_ENTRY(type) \
+struct { \
+ struct type *tqe_next; /* next element */ \
+ struct type **tqe_prev; /* address of previous next element */ \
+}
+
+/*
+ * tail queue access methods
+ */
+#define TAILQ_FIRST(head) ((head)->tqh_first)
+#define TAILQ_END(head) NULL
+#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
+#define TAILQ_LAST(head, headname) \
+ (*(((struct headname *)((head)->tqh_last))->tqh_last))
+/* XXX */
+#define TAILQ_PREV(elm, headname, field) \
+ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+#define TAILQ_EMPTY(head) \
+ (TAILQ_FIRST(head) == TAILQ_END(head))
+
+#define TAILQ_FOREACH(var, head, field) \
+ for((var) = TAILQ_FIRST(head); \
+ (var) != TAILQ_END(head); \
+ (var) = TAILQ_NEXT(var, field))
+
+#define TAILQ_FOREACH_REVERSE(var, head, field, headname) \
+ for((var) = TAILQ_LAST(head, headname); \
+ (var) != TAILQ_END(head); \
+ (var) = TAILQ_PREV(var, headname, field))
+
+/*
+ * Tail queue functions.
+ */
+#define TAILQ_INIT(head) do { \
+ (head)->tqh_first = NULL; \
+ (head)->tqh_last = &(head)->tqh_first; \
+} while (0)
+
+#define TAILQ_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
+ (head)->tqh_first->field.tqe_prev = \
+ &(elm)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+ (head)->tqh_first = (elm); \
+ (elm)->field.tqe_prev = &(head)->tqh_first; \
+} while (0)
+
+#define TAILQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.tqe_next = NULL; \
+ (elm)->field.tqe_prev = (head)->tqh_last; \
+ *(head)->tqh_last = (elm); \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+} while (0)
+
+#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
+ (elm)->field.tqe_next->field.tqe_prev = \
+ &(elm)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+ (listelm)->field.tqe_next = (elm); \
+ (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
+} while (0)
+
+#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
+ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
+ (elm)->field.tqe_next = (listelm); \
+ *(listelm)->field.tqe_prev = (elm); \
+ (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
+} while (0)
+
+#define TAILQ_REMOVE(head, elm, field) do { \
+ if (((elm)->field.tqe_next) != NULL) \
+ (elm)->field.tqe_next->field.tqe_prev = \
+ (elm)->field.tqe_prev; \
+ else \
+ (head)->tqh_last = (elm)->field.tqe_prev; \
+ *(elm)->field.tqe_prev = (elm)->field.tqe_next; \
+} while (0)
+
+#define TAILQ_REPLACE(head, elm, elm2, field) do { \
+ if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
+ (elm2)->field.tqe_next->field.tqe_prev = \
+ &(elm2)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm2)->field.tqe_next; \
+ (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
+ *(elm2)->field.tqe_prev = (elm2); \
+} while (0)
+
+/*
+ * Circular queue definitions.
+ */
+#define CIRCLEQ_HEAD(name, type) \
+struct name { \
+ struct type *cqh_first; /* first element */ \
+ struct type *cqh_last; /* last element */ \
+}
+
+#define CIRCLEQ_HEAD_INITIALIZER(head) \
+ { CIRCLEQ_END(&head), CIRCLEQ_END(&head) }
+
+#define CIRCLEQ_ENTRY(type) \
+struct { \
+ struct type *cqe_next; /* next element */ \
+ struct type *cqe_prev; /* previous element */ \
+}
+
+/*
+ * Circular queue access methods
+ */
+#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
+#define CIRCLEQ_LAST(head) ((head)->cqh_last)
+#define CIRCLEQ_END(head) ((void *)(head))
+#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
+#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
+#define CIRCLEQ_EMPTY(head) \
+ (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head))
+
+#define CIRCLEQ_FOREACH(var, head, field) \
+ for((var) = CIRCLEQ_FIRST(head); \
+ (var) != CIRCLEQ_END(head); \
+ (var) = CIRCLEQ_NEXT(var, field))
+
+#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
+ for((var) = CIRCLEQ_LAST(head); \
+ (var) != CIRCLEQ_END(head); \
+ (var) = CIRCLEQ_PREV(var, field))
+
+/*
+ * Circular queue functions.
+ */
+#define CIRCLEQ_INIT(head) do { \
+ (head)->cqh_first = CIRCLEQ_END(head); \
+ (head)->cqh_last = CIRCLEQ_END(head); \
+} while (0)
+
+#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ (elm)->field.cqe_next = (listelm)->field.cqe_next; \
+ (elm)->field.cqe_prev = (listelm); \
+ if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \
+ (head)->cqh_last = (elm); \
+ else \
+ (listelm)->field.cqe_next->field.cqe_prev = (elm); \
+ (listelm)->field.cqe_next = (elm); \
+} while (0)
+
+#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
+ (elm)->field.cqe_next = (listelm); \
+ (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
+ if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \
+ (head)->cqh_first = (elm); \
+ else \
+ (listelm)->field.cqe_prev->field.cqe_next = (elm); \
+ (listelm)->field.cqe_prev = (elm); \
+} while (0)
+
+#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
+ (elm)->field.cqe_next = (head)->cqh_first; \
+ (elm)->field.cqe_prev = CIRCLEQ_END(head); \
+ if ((head)->cqh_last == CIRCLEQ_END(head)) \
+ (head)->cqh_last = (elm); \
+ else \
+ (head)->cqh_first->field.cqe_prev = (elm); \
+ (head)->cqh_first = (elm); \
+} while (0)
+
+#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.cqe_next = CIRCLEQ_END(head); \
+ (elm)->field.cqe_prev = (head)->cqh_last; \
+ if ((head)->cqh_first == CIRCLEQ_END(head)) \
+ (head)->cqh_first = (elm); \
+ else \
+ (head)->cqh_last->field.cqe_next = (elm); \
+ (head)->cqh_last = (elm); \
+} while (0)
+
+#define CIRCLEQ_REMOVE(head, elm, field) do { \
+ if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \
+ (head)->cqh_last = (elm)->field.cqe_prev; \
+ else \
+ (elm)->field.cqe_next->field.cqe_prev = \
+ (elm)->field.cqe_prev; \
+ if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \
+ (head)->cqh_first = (elm)->field.cqe_next; \
+ else \
+ (elm)->field.cqe_prev->field.cqe_next = \
+ (elm)->field.cqe_next; \
+} while (0)
+
+#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \
+ if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \
+ CIRCLEQ_END(head)) \
+ (head).cqh_last = (elm2); \
+ else \
+ (elm2)->field.cqe_next->field.cqe_prev = (elm2); \
+ if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \
+ CIRCLEQ_END(head)) \
+ (head).cqh_first = (elm2); \
+ else \
+ (elm2)->field.cqe_prev->field.cqe_next = (elm2); \
+} while (0)
+
+#endif /* !_SYS_QUEUE_H_ */
diff --git a/chromium/base/third_party/libevent/configure.in b/chromium/base/third_party/libevent/configure.in
new file mode 100644
index 00000000000..468d774407f
--- /dev/null
+++ b/chromium/base/third_party/libevent/configure.in
@@ -0,0 +1,421 @@
+dnl configure.in for libevent
+dnl Dug Song <dugsong@monkey.org>
+AC_INIT(event.c)
+
+AM_INIT_AUTOMAKE(libevent,1.4.15)
+AM_CONFIG_HEADER(config.h)
+dnl AM_MAINTAINER_MODE
+
+AC_CONFIG_MACRO_DIR([m4])
+
+AC_CANONICAL_HOST
+
+AC_DEFINE(NUMERIC_VERSION, 0x01040f00, [Numeric representation of the version])
+
+dnl Initialize prefix.
+if test "$prefix" = "NONE"; then
+ prefix="/usr/local"
+fi
+
+dnl Checks for programs.
+AC_PROG_CC
+AC_PROG_INSTALL
+AC_PROG_LN_S
+
+AC_PROG_GCC_TRADITIONAL
+if test "$GCC" = yes ; then
+ CFLAGS="$CFLAGS -Wall"
+ # And disable the strict-aliasing optimization, since it breaks
+ # our sockaddr-handling code in strange ways.
+ CFLAGS="$CFLAGS -fno-strict-aliasing"
+fi
+
+dnl Libevent 1.4 isn't multithreaded, but some of its functions are
+dnl documented to be reentrant. If you don't define the right macros
+dnl on some platforms, you get non-reentrant versions of the libc
+dnl functinos (like an errno that's shared by all threads).
+AC_MSG_CHECKING([whether we need extra flags to make libc reentrant])
+case $host in
+ *solaris* | *-osf* | *-hpux* )
+ AC_MSG_RESULT([-D_REENTRANT])
+ CFLAGS="$CFLAGS -D_REENTRANT"
+ ;;
+ *-aix* | *-freebsd* | *-darwin* )
+ AC_MSG_RESULT([-D_THREAD_SAFE])
+ CFLAGS="$CFLAGS -D_THREAD_SAFE"
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ ;;
+esac
+
+AC_ARG_ENABLE(gcc-warnings,
+ AS_HELP_STRING(--enable-gcc-warnings, enable verbose warnings with GCC))
+
+AC_PROG_LIBTOOL
+
+dnl Uncomment "AC_DISABLE_SHARED" to make shared librraries not get
+dnl built by default. You can also turn shared libs on and off from
+dnl the command line with --enable-shared and --disable-shared.
+dnl AC_DISABLE_SHARED
+AC_SUBST(LIBTOOL_DEPS)
+
+dnl Checks for libraries.
+AC_CHECK_LIB(socket, socket)
+AC_CHECK_LIB(resolv, inet_aton)
+AC_CHECK_LIB(rt, clock_gettime)
+AC_CHECK_LIB(nsl, inet_ntoa)
+
+dnl Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS(fcntl.h stdarg.h inttypes.h stdint.h poll.h signal.h unistd.h sys/epoll.h sys/time.h sys/queue.h sys/event.h sys/param.h sys/ioctl.h sys/select.h sys/devpoll.h port.h netinet/in6.h sys/socket.h)
+if test "x$ac_cv_header_sys_queue_h" = "xyes"; then
+ AC_MSG_CHECKING(for TAILQ_FOREACH in sys/queue.h)
+ AC_EGREP_CPP(yes,
+[
+#include <sys/queue.h>
+#ifdef TAILQ_FOREACH
+ yes
+#endif
+], [AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_TAILQFOREACH, 1,
+ [Define if TAILQ_FOREACH is defined in <sys/queue.h>])],
+ AC_MSG_RESULT(no)
+ )
+fi
+
+if test "x$ac_cv_header_sys_time_h" = "xyes"; then
+ AC_MSG_CHECKING(for timeradd in sys/time.h)
+ AC_EGREP_CPP(yes,
+[
+#include <sys/time.h>
+#ifdef timeradd
+ yes
+#endif
+], [ AC_DEFINE(HAVE_TIMERADD, 1,
+ [Define if timeradd is defined in <sys/time.h>])
+ AC_MSG_RESULT(yes)] ,AC_MSG_RESULT(no)
+)
+fi
+
+if test "x$ac_cv_header_sys_time_h" = "xyes"; then
+ AC_MSG_CHECKING(for timercmp in sys/time.h)
+ AC_EGREP_CPP(yes,
+[
+#include <sys/time.h>
+#ifdef timercmp
+ yes
+#endif
+], [ AC_DEFINE(HAVE_TIMERCMP, 1,
+ [Define if timercmp is defined in <sys/time.h>])
+ AC_MSG_RESULT(yes)] ,AC_MSG_RESULT(no)
+)
+fi
+
+if test "x$ac_cv_header_sys_time_h" = "xyes"; then
+ AC_MSG_CHECKING(for timerclear in sys/time.h)
+ AC_EGREP_CPP(yes,
+[
+#include <sys/time.h>
+#ifdef timerclear
+ yes
+#endif
+], [ AC_DEFINE(HAVE_TIMERCLEAR, 1,
+ [Define if timerclear is defined in <sys/time.h>])
+ AC_MSG_RESULT(yes)] ,AC_MSG_RESULT(no)
+)
+fi
+
+if test "x$ac_cv_header_sys_time_h" = "xyes"; then
+ AC_MSG_CHECKING(for timerisset in sys/time.h)
+ AC_EGREP_CPP(yes,
+[
+#include <sys/time.h>
+#ifdef timerisset
+ yes
+#endif
+], [ AC_DEFINE(HAVE_TIMERISSET, 1,
+ [Define if timerisset is defined in <sys/time.h>])
+ AC_MSG_RESULT(yes)] ,AC_MSG_RESULT(no)
+)
+fi
+
+dnl - check if the macro WIN32 is defined on this compiler.
+dnl - (this is how we check for a windows version of GCC)
+AC_MSG_CHECKING(for WIN32)
+AC_TRY_COMPILE(,
+ [
+#ifndef WIN32
+die horribly
+#endif
+ ],
+ bwin32=true; AC_MSG_RESULT(yes),
+ bwin32=false; AC_MSG_RESULT(no),
+)
+
+AM_CONDITIONAL(BUILD_WIN32, test x$bwin32 = xtrue)
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_C_INLINE
+AC_HEADER_TIME
+
+dnl Checks for library functions.
+AC_CHECK_FUNCS(gettimeofday vasprintf fcntl clock_gettime strtok_r strsep getaddrinfo getnameinfo strlcpy inet_ntop signal sigaction strtoll issetugid geteuid getegid)
+
+AC_CHECK_SIZEOF(long)
+
+if test "x$ac_cv_func_clock_gettime" = "xyes"; then
+ AC_DEFINE(DNS_USE_CPU_CLOCK_FOR_ID, 1, [Define if clock_gettime is available in libc])
+else
+ AC_DEFINE(DNS_USE_GETTIMEOFDAY_FOR_ID, 1, [Define is no secure id variant is available])
+fi
+
+AC_MSG_CHECKING(for F_SETFD in fcntl.h)
+AC_EGREP_CPP(yes,
+[
+#define _GNU_SOURCE
+#include <fcntl.h>
+#ifdef F_SETFD
+yes
+#endif
+], [ AC_DEFINE(HAVE_SETFD, 1,
+ [Define if F_SETFD is defined in <fcntl.h>])
+ AC_MSG_RESULT(yes) ], AC_MSG_RESULT(no))
+
+needsignal=no
+haveselect=no
+AC_CHECK_FUNCS(select, [haveselect=yes], )
+if test "x$haveselect" = "xyes" ; then
+ AC_LIBOBJ(select)
+ needsignal=yes
+fi
+
+havepoll=no
+AC_CHECK_FUNCS(poll, [havepoll=yes], )
+if test "x$havepoll" = "xyes" ; then
+ AC_LIBOBJ(poll)
+ needsignal=yes
+fi
+
+haveepoll=no
+AC_CHECK_FUNCS(epoll_ctl, [haveepoll=yes], )
+if test "x$haveepoll" = "xyes" ; then
+ AC_DEFINE(HAVE_EPOLL, 1,
+ [Define if your system supports the epoll system calls])
+ AC_LIBOBJ(epoll)
+ needsignal=yes
+fi
+
+havedevpoll=no
+if test "x$ac_cv_header_sys_devpoll_h" = "xyes"; then
+ AC_DEFINE(HAVE_DEVPOLL, 1,
+ [Define if /dev/poll is available])
+ AC_LIBOBJ(devpoll)
+fi
+
+havekqueue=no
+if test "x$ac_cv_header_sys_event_h" = "xyes"; then
+ AC_CHECK_FUNCS(kqueue, [havekqueue=yes], )
+ if test "x$havekqueue" = "xyes" ; then
+ AC_MSG_CHECKING(for working kqueue)
+ AC_TRY_RUN(
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/event.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+int
+main(int argc, char **argv)
+{
+ int kq;
+ int n;
+ int fd[[2]];
+ struct kevent ev;
+ struct timespec ts;
+ char buf[[8000]];
+
+ if (pipe(fd) == -1)
+ exit(1);
+ if (fcntl(fd[[1]], F_SETFL, O_NONBLOCK) == -1)
+ exit(1);
+
+ while ((n = write(fd[[1]], buf, sizeof(buf))) == sizeof(buf))
+ ;
+
+ if ((kq = kqueue()) == -1)
+ exit(1);
+
+ memset(&ev, 0, sizeof(ev));
+ ev.ident = fd[[1]];
+ ev.filter = EVFILT_WRITE;
+ ev.flags = EV_ADD | EV_ENABLE;
+ n = kevent(kq, &ev, 1, NULL, 0, NULL);
+ if (n == -1)
+ exit(1);
+
+ read(fd[[0]], buf, sizeof(buf));
+
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+ n = kevent(kq, NULL, 0, &ev, 1, &ts);
+ if (n == -1 || n == 0)
+ exit(1);
+
+ exit(0);
+}, [AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_WORKING_KQUEUE, 1,
+ [Define if kqueue works correctly with pipes])
+ AC_LIBOBJ(kqueue)], AC_MSG_RESULT(no), AC_MSG_RESULT(no))
+ fi
+fi
+
+haveepollsyscall=no
+if test "x$ac_cv_header_sys_epoll_h" = "xyes"; then
+ if test "x$haveepoll" = "xno" ; then
+ AC_MSG_CHECKING(for epoll system call)
+ AC_TRY_RUN(
+#include <stdint.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <sys/epoll.h>
+#include <unistd.h>
+
+int
+epoll_create(int size)
+{
+ return (syscall(__NR_epoll_create, size));
+}
+
+int
+main(int argc, char **argv)
+{
+ int epfd;
+
+ epfd = epoll_create(256);
+ exit (epfd == -1 ? 1 : 0);
+}, [AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_EPOLL, 1,
+ [Define if your system supports the epoll system calls])
+ needsignal=yes
+ AC_LIBOBJ(epoll_sub)
+ AC_LIBOBJ(epoll)], AC_MSG_RESULT(no), AC_MSG_RESULT(no))
+ fi
+fi
+
+haveeventports=no
+AC_CHECK_FUNCS(port_create, [haveeventports=yes], )
+if test "x$haveeventports" = "xyes" ; then
+ AC_DEFINE(HAVE_EVENT_PORTS, 1,
+ [Define if your system supports event ports])
+ AC_LIBOBJ(evport)
+ needsignal=yes
+fi
+if test "x$bwin32" = "xtrue"; then
+ needsignal=yes
+fi
+if test "x$bwin32" = "xtrue"; then
+ needsignal=yes
+fi
+if test "x$needsignal" = "xyes" ; then
+ AC_LIBOBJ(signal)
+fi
+
+AC_TYPE_PID_T
+AC_TYPE_SIZE_T
+AC_CHECK_TYPES([uint64_t, uint32_t, uint16_t, uint8_t], , ,
+[#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#elif defined(HAVE_INTTYPES_H)
+#include <inttypes.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif])
+AC_CHECK_TYPES([fd_mask], , ,
+[#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SELECT_H
+#include <select.h>
+#endif])
+
+AC_CHECK_SIZEOF(long long)
+AC_CHECK_SIZEOF(int)
+AC_CHECK_SIZEOF(short)
+AC_CHECK_TYPES([struct in6_addr], , ,
+[#ifdef WIN32
+#include <winsock2.h>
+#else
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN6_H
+#include <netinet/in6.h>
+#endif])
+
+AC_MSG_CHECKING([for socklen_t])
+AC_TRY_COMPILE([
+ #include <sys/types.h>
+ #include <sys/socket.h>],
+ [socklen_t x;],
+ AC_MSG_RESULT([yes]),
+ [AC_MSG_RESULT([no])
+ AC_DEFINE(socklen_t, unsigned int,
+ [Define to unsigned int if you dont have it])]
+)
+
+AC_MSG_CHECKING([whether our compiler supports __func__])
+AC_TRY_COMPILE([],
+ [ const char *cp = __func__; ],
+ AC_MSG_RESULT([yes]),
+ AC_MSG_RESULT([no])
+ AC_MSG_CHECKING([whether our compiler supports __FUNCTION__])
+ AC_TRY_COMPILE([],
+ [ const char *cp = __FUNCTION__; ],
+ AC_MSG_RESULT([yes])
+ AC_DEFINE(__func__, __FUNCTION__,
+ [Define to appropriate substitue if compiler doesnt have __func__]),
+ AC_MSG_RESULT([no])
+ AC_DEFINE(__func__, __FILE__,
+ [Define to appropriate substitue if compiler doesnt have __func__])))
+
+
+# Add some more warnings which we use in development but not in the
+# released versions. (Some relevant gcc versions can't handle these.)
+if test x$enable_gcc_warnings = xyes; then
+
+ AC_COMPILE_IFELSE(AC_LANG_PROGRAM([], [
+#if !defined(__GNUC__) || (__GNUC__ < 4)
+#error
+#endif]), have_gcc4=yes, have_gcc4=no)
+
+ AC_COMPILE_IFELSE(AC_LANG_PROGRAM([], [
+#if !defined(__GNUC__) || (__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 2)
+#error
+#endif]), have_gcc42=yes, have_gcc42=no)
+
+ CFLAGS="$CFLAGS -W -Wfloat-equal -Wundef -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes -Wwrite-strings -Wredundant-decls -Wchar-subscripts -Wcomment -Wformat=2 -Wwrite-strings -Wmissing-declarations -Wredundant-decls -Wnested-externs -Wbad-function-cast -Wswitch-enum -Werror"
+ CFLAGS="$CFLAGS -Wno-unused-parameter -Wno-sign-compare -Wstrict-aliasing"
+
+ if test x$have_gcc4 = xyes ; then
+ # These warnings break gcc 3.3.5 and work on gcc 4.0.2
+ CFLAGS="$CFLAGS -Winit-self -Wmissing-field-initializers -Wdeclaration-after-statement"
+ #CFLAGS="$CFLAGS -Wold-style-definition"
+ fi
+
+ if test x$have_gcc42 = xyes ; then
+ # These warnings break gcc 4.0.2 and work on gcc 4.2
+ CFLAGS="$CFLAGS -Waddress -Wnormalized=id -Woverride-init"
+ fi
+
+##This will break the world on some 64-bit architectures
+# CFLAGS="$CFLAGS -Winline"
+
+fi
+
+AC_OUTPUT(Makefile test/Makefile sample/Makefile)
diff --git a/chromium/base/third_party/libevent/devpoll.c b/chromium/base/third_party/libevent/devpoll.c
new file mode 100644
index 00000000000..2d34ae3400c
--- /dev/null
+++ b/chromium/base/third_party/libevent/devpoll.c
@@ -0,0 +1,417 @@
+/*
+ * Copyright 2000-2004 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/resource.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <sys/_libevent_time.h>
+#endif
+#include <sys/queue.h>
+#include <sys/devpoll.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <assert.h>
+
+#include "event.h"
+#include "event-internal.h"
+#include "evsignal.h"
+#include "log.h"
+
+/* due to limitations in the devpoll interface, we need to keep track of
+ * all file descriptors outself.
+ */
+struct evdevpoll {
+ struct event *evread;
+ struct event *evwrite;
+};
+
+struct devpollop {
+ struct evdevpoll *fds;
+ int nfds;
+ struct pollfd *events;
+ int nevents;
+ int dpfd;
+ struct pollfd *changes;
+ int nchanges;
+};
+
+static void *devpoll_init (struct event_base *);
+static int devpoll_add (void *, struct event *);
+static int devpoll_del (void *, struct event *);
+static int devpoll_dispatch (struct event_base *, void *, struct timeval *);
+static void devpoll_dealloc (struct event_base *, void *);
+
+const struct eventop devpollops = {
+ "devpoll",
+ devpoll_init,
+ devpoll_add,
+ devpoll_del,
+ devpoll_dispatch,
+ devpoll_dealloc,
+ 1 /* need reinit */
+};
+
+#define NEVENT 32000
+
+static int
+devpoll_commit(struct devpollop *devpollop)
+{
+ /*
+ * Due to a bug in Solaris, we have to use pwrite with an offset of 0.
+ * Write is limited to 2GB of data, until it will fail.
+ */
+ if (pwrite(devpollop->dpfd, devpollop->changes,
+ sizeof(struct pollfd) * devpollop->nchanges, 0) == -1)
+ return(-1);
+
+ devpollop->nchanges = 0;
+ return(0);
+}
+
+static int
+devpoll_queue(struct devpollop *devpollop, int fd, int events) {
+ struct pollfd *pfd;
+
+ if (devpollop->nchanges >= devpollop->nevents) {
+ /*
+ * Change buffer is full, must commit it to /dev/poll before
+ * adding more
+ */
+ if (devpoll_commit(devpollop) != 0)
+ return(-1);
+ }
+
+ pfd = &devpollop->changes[devpollop->nchanges++];
+ pfd->fd = fd;
+ pfd->events = events;
+ pfd->revents = 0;
+
+ return(0);
+}
+
+static void *
+devpoll_init(struct event_base *base)
+{
+ int dpfd, nfiles = NEVENT;
+ struct rlimit rl;
+ struct devpollop *devpollop;
+
+ /* Disable devpoll when this environment variable is set */
+ if (evutil_getenv("EVENT_NODEVPOLL"))
+ return (NULL);
+
+ if (!(devpollop = calloc(1, sizeof(struct devpollop))))
+ return (NULL);
+
+ if (getrlimit(RLIMIT_NOFILE, &rl) == 0 &&
+ rl.rlim_cur != RLIM_INFINITY)
+ nfiles = rl.rlim_cur;
+
+ /* Initialize the kernel queue */
+ if ((dpfd = open("/dev/poll", O_RDWR)) == -1) {
+ event_warn("open: /dev/poll");
+ free(devpollop);
+ return (NULL);
+ }
+
+ devpollop->dpfd = dpfd;
+
+ /* Initialize fields */
+ devpollop->events = calloc(nfiles, sizeof(struct pollfd));
+ if (devpollop->events == NULL) {
+ free(devpollop);
+ close(dpfd);
+ return (NULL);
+ }
+ devpollop->nevents = nfiles;
+
+ devpollop->fds = calloc(nfiles, sizeof(struct evdevpoll));
+ if (devpollop->fds == NULL) {
+ free(devpollop->events);
+ free(devpollop);
+ close(dpfd);
+ return (NULL);
+ }
+ devpollop->nfds = nfiles;
+
+ devpollop->changes = calloc(nfiles, sizeof(struct pollfd));
+ if (devpollop->changes == NULL) {
+ free(devpollop->fds);
+ free(devpollop->events);
+ free(devpollop);
+ close(dpfd);
+ return (NULL);
+ }
+
+ evsignal_init(base);
+
+ return (devpollop);
+}
+
+static int
+devpoll_recalc(struct event_base *base, void *arg, int max)
+{
+ struct devpollop *devpollop = arg;
+
+ if (max >= devpollop->nfds) {
+ struct evdevpoll *fds;
+ int nfds;
+
+ nfds = devpollop->nfds;
+ while (nfds <= max)
+ nfds <<= 1;
+
+ fds = realloc(devpollop->fds, nfds * sizeof(struct evdevpoll));
+ if (fds == NULL) {
+ event_warn("realloc");
+ return (-1);
+ }
+ devpollop->fds = fds;
+ memset(fds + devpollop->nfds, 0,
+ (nfds - devpollop->nfds) * sizeof(struct evdevpoll));
+ devpollop->nfds = nfds;
+ }
+
+ return (0);
+}
+
+static int
+devpoll_dispatch(struct event_base *base, void *arg, struct timeval *tv)
+{
+ struct devpollop *devpollop = arg;
+ struct pollfd *events = devpollop->events;
+ struct dvpoll dvp;
+ struct evdevpoll *evdp;
+ int i, res, timeout = -1;
+
+ if (devpollop->nchanges)
+ devpoll_commit(devpollop);
+
+ if (tv != NULL)
+ timeout = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000;
+
+ dvp.dp_fds = devpollop->events;
+ dvp.dp_nfds = devpollop->nevents;
+ dvp.dp_timeout = timeout;
+
+ res = ioctl(devpollop->dpfd, DP_POLL, &dvp);
+
+ if (res == -1) {
+ if (errno != EINTR) {
+ event_warn("ioctl: DP_POLL");
+ return (-1);
+ }
+
+ evsignal_process(base);
+ return (0);
+ } else if (base->sig.evsignal_caught) {
+ evsignal_process(base);
+ }
+
+ event_debug(("%s: devpoll_wait reports %d", __func__, res));
+
+ for (i = 0; i < res; i++) {
+ int which = 0;
+ int what = events[i].revents;
+ struct event *evread = NULL, *evwrite = NULL;
+
+ assert(events[i].fd < devpollop->nfds);
+ evdp = &devpollop->fds[events[i].fd];
+
+ if (what & POLLHUP)
+ what |= POLLIN | POLLOUT;
+ else if (what & POLLERR)
+ what |= POLLIN | POLLOUT;
+
+ if (what & POLLIN) {
+ evread = evdp->evread;
+ which |= EV_READ;
+ }
+
+ if (what & POLLOUT) {
+ evwrite = evdp->evwrite;
+ which |= EV_WRITE;
+ }
+
+ if (!which)
+ continue;
+
+ if (evread != NULL && !(evread->ev_events & EV_PERSIST))
+ event_del(evread);
+ if (evwrite != NULL && evwrite != evread &&
+ !(evwrite->ev_events & EV_PERSIST))
+ event_del(evwrite);
+
+ if (evread != NULL)
+ event_active(evread, EV_READ, 1);
+ if (evwrite != NULL)
+ event_active(evwrite, EV_WRITE, 1);
+ }
+
+ return (0);
+}
+
+
+static int
+devpoll_add(void *arg, struct event *ev)
+{
+ struct devpollop *devpollop = arg;
+ struct evdevpoll *evdp;
+ int fd, events;
+
+ if (ev->ev_events & EV_SIGNAL)
+ return (evsignal_add(ev));
+
+ fd = ev->ev_fd;
+ if (fd >= devpollop->nfds) {
+ /* Extend the file descriptor array as necessary */
+ if (devpoll_recalc(ev->ev_base, devpollop, fd) == -1)
+ return (-1);
+ }
+ evdp = &devpollop->fds[fd];
+
+ /*
+ * It's not necessary to OR the existing read/write events that we
+ * are currently interested in with the new event we are adding.
+ * The /dev/poll driver ORs any new events with the existing events
+ * that it has cached for the fd.
+ */
+
+ events = 0;
+ if (ev->ev_events & EV_READ) {
+ if (evdp->evread && evdp->evread != ev) {
+ /* There is already a different read event registered */
+ return(-1);
+ }
+ events |= POLLIN;
+ }
+
+ if (ev->ev_events & EV_WRITE) {
+ if (evdp->evwrite && evdp->evwrite != ev) {
+ /* There is already a different write event registered */
+ return(-1);
+ }
+ events |= POLLOUT;
+ }
+
+ if (devpoll_queue(devpollop, fd, events) != 0)
+ return(-1);
+
+ /* Update events responsible */
+ if (ev->ev_events & EV_READ)
+ evdp->evread = ev;
+ if (ev->ev_events & EV_WRITE)
+ evdp->evwrite = ev;
+
+ return (0);
+}
+
+static int
+devpoll_del(void *arg, struct event *ev)
+{
+ struct devpollop *devpollop = arg;
+ struct evdevpoll *evdp;
+ int fd, events;
+ int needwritedelete = 1, needreaddelete = 1;
+
+ if (ev->ev_events & EV_SIGNAL)
+ return (evsignal_del(ev));
+
+ fd = ev->ev_fd;
+ if (fd >= devpollop->nfds)
+ return (0);
+ evdp = &devpollop->fds[fd];
+
+ events = 0;
+ if (ev->ev_events & EV_READ)
+ events |= POLLIN;
+ if (ev->ev_events & EV_WRITE)
+ events |= POLLOUT;
+
+ /*
+ * The only way to remove an fd from the /dev/poll monitored set is
+ * to use POLLREMOVE by itself. This removes ALL events for the fd
+ * provided so if we care about two events and are only removing one
+ * we must re-add the other event after POLLREMOVE.
+ */
+
+ if (devpoll_queue(devpollop, fd, POLLREMOVE) != 0)
+ return(-1);
+
+ if ((events & (POLLIN|POLLOUT)) != (POLLIN|POLLOUT)) {
+ /*
+ * We're not deleting all events, so we must resubmit the
+ * event that we are still interested in if one exists.
+ */
+
+ if ((events & POLLIN) && evdp->evwrite != NULL) {
+ /* Deleting read, still care about write */
+ devpoll_queue(devpollop, fd, POLLOUT);
+ needwritedelete = 0;
+ } else if ((events & POLLOUT) && evdp->evread != NULL) {
+ /* Deleting write, still care about read */
+ devpoll_queue(devpollop, fd, POLLIN);
+ needreaddelete = 0;
+ }
+ }
+
+ if (needreaddelete)
+ evdp->evread = NULL;
+ if (needwritedelete)
+ evdp->evwrite = NULL;
+
+ return (0);
+}
+
+static void
+devpoll_dealloc(struct event_base *base, void *arg)
+{
+ struct devpollop *devpollop = arg;
+
+ evsignal_dealloc(base);
+ if (devpollop->fds)
+ free(devpollop->fds);
+ if (devpollop->events)
+ free(devpollop->events);
+ if (devpollop->changes)
+ free(devpollop->changes);
+ if (devpollop->dpfd >= 0)
+ close(devpollop->dpfd);
+
+ memset(devpollop, 0, sizeof(struct devpollop));
+ free(devpollop);
+}
diff --git a/chromium/base/third_party/libevent/epoll.c b/chromium/base/third_party/libevent/epoll.c
new file mode 100644
index 00000000000..4387ef896df
--- /dev/null
+++ b/chromium/base/third_party/libevent/epoll.c
@@ -0,0 +1,377 @@
+/*
+ * Copyright 2000-2003 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <sys/_libevent_time.h>
+#endif
+#include <sys/queue.h>
+#include <sys/epoll.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#include "event.h"
+#include "event-internal.h"
+#include "evsignal.h"
+#include "log.h"
+
+/* due to limitations in the epoll interface, we need to keep track of
+ * all file descriptors outself.
+ */
+struct evepoll {
+ struct event *evread;
+ struct event *evwrite;
+};
+
+struct epollop {
+ struct evepoll *fds;
+ int nfds;
+ struct epoll_event *events;
+ int nevents;
+ int epfd;
+};
+
+static void *epoll_init (struct event_base *);
+static int epoll_add (void *, struct event *);
+static int epoll_del (void *, struct event *);
+static int epoll_dispatch (struct event_base *, void *, struct timeval *);
+static void epoll_dealloc (struct event_base *, void *);
+
+const struct eventop epollops = {
+ "epoll",
+ epoll_init,
+ epoll_add,
+ epoll_del,
+ epoll_dispatch,
+ epoll_dealloc,
+ 1 /* need reinit */
+};
+
+#ifdef HAVE_SETFD
+#define FD_CLOSEONEXEC(x) do { \
+ if (fcntl(x, F_SETFD, 1) == -1) \
+ event_warn("fcntl(%d, F_SETFD)", x); \
+} while (0)
+#else
+#define FD_CLOSEONEXEC(x)
+#endif
+
+/* On Linux kernels at least up to 2.6.24.4, epoll can't handle timeout
+ * values bigger than (LONG_MAX - 999ULL)/HZ. HZ in the wild can be
+ * as big as 1000, and LONG_MAX can be as small as (1<<31)-1, so the
+ * largest number of msec we can support here is 2147482. Let's
+ * round that down by 47 seconds.
+ */
+#define MAX_EPOLL_TIMEOUT_MSEC (35*60*1000)
+
+#define INITIAL_NFILES 32
+#define INITIAL_NEVENTS 32
+#define MAX_NEVENTS 4096
+
+static void *
+epoll_init(struct event_base *base)
+{
+ int epfd;
+ struct epollop *epollop;
+
+ /* Disable epollueue when this environment variable is set */
+ if (evutil_getenv("EVENT_NOEPOLL"))
+ return (NULL);
+
+ /* Initalize the kernel queue */
+ if ((epfd = epoll_create(32000)) == -1) {
+ if (errno != ENOSYS)
+ event_warn("epoll_create");
+ return (NULL);
+ }
+
+ FD_CLOSEONEXEC(epfd);
+
+ if (!(epollop = calloc(1, sizeof(struct epollop))))
+ return (NULL);
+
+ epollop->epfd = epfd;
+
+ /* Initalize fields */
+ epollop->events = malloc(INITIAL_NEVENTS * sizeof(struct epoll_event));
+ if (epollop->events == NULL) {
+ free(epollop);
+ return (NULL);
+ }
+ epollop->nevents = INITIAL_NEVENTS;
+
+ epollop->fds = calloc(INITIAL_NFILES, sizeof(struct evepoll));
+ if (epollop->fds == NULL) {
+ free(epollop->events);
+ free(epollop);
+ return (NULL);
+ }
+ epollop->nfds = INITIAL_NFILES;
+
+ evsignal_init(base);
+
+ return (epollop);
+}
+
+static int
+epoll_recalc(struct event_base *base, void *arg, int max)
+{
+ struct epollop *epollop = arg;
+
+ if (max >= epollop->nfds) {
+ struct evepoll *fds;
+ int nfds;
+
+ nfds = epollop->nfds;
+ while (nfds <= max)
+ nfds <<= 1;
+
+ fds = realloc(epollop->fds, nfds * sizeof(struct evepoll));
+ if (fds == NULL) {
+ event_warn("realloc");
+ return (-1);
+ }
+ epollop->fds = fds;
+ memset(fds + epollop->nfds, 0,
+ (nfds - epollop->nfds) * sizeof(struct evepoll));
+ epollop->nfds = nfds;
+ }
+
+ return (0);
+}
+
+static int
+epoll_dispatch(struct event_base *base, void *arg, struct timeval *tv)
+{
+ struct epollop *epollop = arg;
+ struct epoll_event *events = epollop->events;
+ struct evepoll *evep;
+ int i, res, timeout = -1;
+
+ if (tv != NULL)
+ timeout = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000;
+
+ if (timeout > MAX_EPOLL_TIMEOUT_MSEC) {
+ /* Linux kernels can wait forever if the timeout is too big;
+ * see comment on MAX_EPOLL_TIMEOUT_MSEC. */
+ timeout = MAX_EPOLL_TIMEOUT_MSEC;
+ }
+
+ res = epoll_wait(epollop->epfd, events, epollop->nevents, timeout);
+
+ if (res == -1) {
+ if (errno != EINTR) {
+ event_warn("epoll_wait");
+ return (-1);
+ }
+
+ evsignal_process(base);
+ return (0);
+ } else if (base->sig.evsignal_caught) {
+ evsignal_process(base);
+ }
+
+ event_debug(("%s: epoll_wait reports %d", __func__, res));
+
+ for (i = 0; i < res; i++) {
+ int what = events[i].events;
+ struct event *evread = NULL, *evwrite = NULL;
+ int fd = events[i].data.fd;
+
+ if (fd < 0 || fd >= epollop->nfds)
+ continue;
+ evep = &epollop->fds[fd];
+
+ if (what & (EPOLLHUP|EPOLLERR)) {
+ evread = evep->evread;
+ evwrite = evep->evwrite;
+ } else {
+ if (what & EPOLLIN) {
+ evread = evep->evread;
+ }
+
+ if (what & EPOLLOUT) {
+ evwrite = evep->evwrite;
+ }
+ }
+
+ if (!(evread||evwrite))
+ continue;
+
+ if (evread != NULL)
+ event_active(evread, EV_READ, 1);
+ if (evwrite != NULL)
+ event_active(evwrite, EV_WRITE, 1);
+ }
+
+ if (res == epollop->nevents && epollop->nevents < MAX_NEVENTS) {
+ /* We used all of the event space this time. We should
+ be ready for more events next time. */
+ int new_nevents = epollop->nevents * 2;
+ struct epoll_event *new_events;
+
+ new_events = realloc(epollop->events,
+ new_nevents * sizeof(struct epoll_event));
+ if (new_events) {
+ epollop->events = new_events;
+ epollop->nevents = new_nevents;
+ }
+ }
+
+ return (0);
+}
+
+
+static int
+epoll_add(void *arg, struct event *ev)
+{
+ struct epollop *epollop = arg;
+ struct epoll_event epev = {0, {0}};
+ struct evepoll *evep;
+ int fd, op, events;
+
+ if (ev->ev_events & EV_SIGNAL)
+ return (evsignal_add(ev));
+
+ fd = ev->ev_fd;
+ if (fd >= epollop->nfds) {
+ /* Extent the file descriptor array as necessary */
+ if (epoll_recalc(ev->ev_base, epollop, fd) == -1)
+ return (-1);
+ }
+ evep = &epollop->fds[fd];
+ op = EPOLL_CTL_ADD;
+ events = 0;
+ if (evep->evread != NULL) {
+ events |= EPOLLIN;
+ op = EPOLL_CTL_MOD;
+ }
+ if (evep->evwrite != NULL) {
+ events |= EPOLLOUT;
+ op = EPOLL_CTL_MOD;
+ }
+
+ if (ev->ev_events & EV_READ)
+ events |= EPOLLIN;
+ if (ev->ev_events & EV_WRITE)
+ events |= EPOLLOUT;
+
+ epev.data.fd = fd;
+ epev.events = events;
+ if (epoll_ctl(epollop->epfd, op, ev->ev_fd, &epev) == -1)
+ return (-1);
+
+ /* Update events responsible */
+ if (ev->ev_events & EV_READ)
+ evep->evread = ev;
+ if (ev->ev_events & EV_WRITE)
+ evep->evwrite = ev;
+
+ return (0);
+}
+
+static int
+epoll_del(void *arg, struct event *ev)
+{
+ struct epollop *epollop = arg;
+ struct epoll_event epev = {0, {0}};
+ struct evepoll *evep;
+ int fd, events, op;
+ int needwritedelete = 1, needreaddelete = 1;
+
+ if (ev->ev_events & EV_SIGNAL)
+ return (evsignal_del(ev));
+
+ fd = ev->ev_fd;
+ if (fd >= epollop->nfds)
+ return (0);
+ evep = &epollop->fds[fd];
+
+ op = EPOLL_CTL_DEL;
+ events = 0;
+
+ if (ev->ev_events & EV_READ)
+ events |= EPOLLIN;
+ if (ev->ev_events & EV_WRITE)
+ events |= EPOLLOUT;
+
+ if ((events & (EPOLLIN|EPOLLOUT)) != (EPOLLIN|EPOLLOUT)) {
+ if ((events & EPOLLIN) && evep->evwrite != NULL) {
+ needwritedelete = 0;
+ events = EPOLLOUT;
+ op = EPOLL_CTL_MOD;
+ } else if ((events & EPOLLOUT) && evep->evread != NULL) {
+ needreaddelete = 0;
+ events = EPOLLIN;
+ op = EPOLL_CTL_MOD;
+ }
+ }
+
+ epev.events = events;
+ epev.data.fd = fd;
+
+ if (needreaddelete)
+ evep->evread = NULL;
+ if (needwritedelete)
+ evep->evwrite = NULL;
+
+ if (epoll_ctl(epollop->epfd, op, fd, &epev) == -1)
+ return (-1);
+
+ return (0);
+}
+
+static void
+epoll_dealloc(struct event_base *base, void *arg)
+{
+ struct epollop *epollop = arg;
+
+ evsignal_dealloc(base);
+ if (epollop->fds)
+ free(epollop->fds);
+ if (epollop->events)
+ free(epollop->events);
+ if (epollop->epfd >= 0)
+ close(epollop->epfd);
+
+ memset(epollop, 0, sizeof(struct epollop));
+ free(epollop);
+}
diff --git a/chromium/base/third_party/libevent/epoll_sub.c b/chromium/base/third_party/libevent/epoll_sub.c
new file mode 100644
index 00000000000..431970c73a6
--- /dev/null
+++ b/chromium/base/third_party/libevent/epoll_sub.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2003 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdint.h>
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <sys/epoll.h>
+#include <unistd.h>
+
+int
+epoll_create(int size)
+{
+ return (syscall(__NR_epoll_create, size));
+}
+
+int
+epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
+{
+
+ return (syscall(__NR_epoll_ctl, epfd, op, fd, event));
+}
+
+int
+epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)
+{
+ return (syscall(__NR_epoll_wait, epfd, events, maxevents, timeout));
+}
diff --git a/chromium/base/third_party/libevent/evbuffer.c b/chromium/base/third_party/libevent/evbuffer.c
new file mode 100644
index 00000000000..f2179a5044f
--- /dev/null
+++ b/chromium/base/third_party/libevent/evbuffer.c
@@ -0,0 +1,455 @@
+/*
+ * Copyright (c) 2002-2004 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_STDARG_H
+#include <stdarg.h>
+#endif
+
+#ifdef WIN32
+#include <winsock2.h>
+#endif
+
+#include "evutil.h"
+#include "event.h"
+
+/* prototypes */
+
+void bufferevent_read_pressure_cb(struct evbuffer *, size_t, size_t, void *);
+
+static int
+bufferevent_add(struct event *ev, int timeout)
+{
+ struct timeval tv, *ptv = NULL;
+
+ if (timeout) {
+ evutil_timerclear(&tv);
+ tv.tv_sec = timeout;
+ ptv = &tv;
+ }
+
+ return (event_add(ev, ptv));
+}
+
+/*
+ * This callback is executed when the size of the input buffer changes.
+ * We use it to apply back pressure on the reading side.
+ */
+
+void
+bufferevent_read_pressure_cb(struct evbuffer *buf, size_t old, size_t now,
+ void *arg) {
+ struct bufferevent *bufev = arg;
+ /*
+ * If we are below the watermark then reschedule reading if it's
+ * still enabled.
+ */
+ if (bufev->wm_read.high == 0 || now < bufev->wm_read.high) {
+ evbuffer_setcb(buf, NULL, NULL);
+
+ if (bufev->enabled & EV_READ)
+ bufferevent_add(&bufev->ev_read, bufev->timeout_read);
+ }
+}
+
+static void
+bufferevent_readcb(int fd, short event, void *arg)
+{
+ struct bufferevent *bufev = arg;
+ int res = 0;
+ short what = EVBUFFER_READ;
+ size_t len;
+ int howmuch = -1;
+
+ if (event == EV_TIMEOUT) {
+ what |= EVBUFFER_TIMEOUT;
+ goto error;
+ }
+
+ /*
+ * If we have a high watermark configured then we don't want to
+ * read more data than would make us reach the watermark.
+ */
+ if (bufev->wm_read.high != 0) {
+ howmuch = bufev->wm_read.high - EVBUFFER_LENGTH(bufev->input);
+ /* we might have lowered the watermark, stop reading */
+ if (howmuch <= 0) {
+ struct evbuffer *buf = bufev->input;
+ event_del(&bufev->ev_read);
+ evbuffer_setcb(buf,
+ bufferevent_read_pressure_cb, bufev);
+ return;
+ }
+ }
+
+ res = evbuffer_read(bufev->input, fd, howmuch);
+ if (res == -1) {
+ if (errno == EAGAIN || errno == EINTR)
+ goto reschedule;
+ /* error case */
+ what |= EVBUFFER_ERROR;
+ } else if (res == 0) {
+ /* eof case */
+ what |= EVBUFFER_EOF;
+ }
+
+ if (res <= 0)
+ goto error;
+
+ bufferevent_add(&bufev->ev_read, bufev->timeout_read);
+
+ /* See if this callbacks meets the water marks */
+ len = EVBUFFER_LENGTH(bufev->input);
+ if (bufev->wm_read.low != 0 && len < bufev->wm_read.low)
+ return;
+ if (bufev->wm_read.high != 0 && len >= bufev->wm_read.high) {
+ struct evbuffer *buf = bufev->input;
+ event_del(&bufev->ev_read);
+
+ /* Now schedule a callback for us when the buffer changes */
+ evbuffer_setcb(buf, bufferevent_read_pressure_cb, bufev);
+ }
+
+ /* Invoke the user callback - must always be called last */
+ if (bufev->readcb != NULL)
+ (*bufev->readcb)(bufev, bufev->cbarg);
+ return;
+
+ reschedule:
+ bufferevent_add(&bufev->ev_read, bufev->timeout_read);
+ return;
+
+ error:
+ (*bufev->errorcb)(bufev, what, bufev->cbarg);
+}
+
+static void
+bufferevent_writecb(int fd, short event, void *arg)
+{
+ struct bufferevent *bufev = arg;
+ int res = 0;
+ short what = EVBUFFER_WRITE;
+
+ if (event == EV_TIMEOUT) {
+ what |= EVBUFFER_TIMEOUT;
+ goto error;
+ }
+
+ if (EVBUFFER_LENGTH(bufev->output)) {
+ res = evbuffer_write(bufev->output, fd);
+ if (res == -1) {
+#ifndef WIN32
+/*todo. evbuffer uses WriteFile when WIN32 is set. WIN32 system calls do not
+ *set errno. thus this error checking is not portable*/
+ if (errno == EAGAIN ||
+ errno == EINTR ||
+ errno == EINPROGRESS)
+ goto reschedule;
+ /* error case */
+ what |= EVBUFFER_ERROR;
+
+#else
+ goto reschedule;
+#endif
+
+ } else if (res == 0) {
+ /* eof case */
+ what |= EVBUFFER_EOF;
+ }
+ if (res <= 0)
+ goto error;
+ }
+
+ if (EVBUFFER_LENGTH(bufev->output) != 0)
+ bufferevent_add(&bufev->ev_write, bufev->timeout_write);
+
+ /*
+ * Invoke the user callback if our buffer is drained or below the
+ * low watermark.
+ */
+ if (bufev->writecb != NULL &&
+ EVBUFFER_LENGTH(bufev->output) <= bufev->wm_write.low)
+ (*bufev->writecb)(bufev, bufev->cbarg);
+
+ return;
+
+ reschedule:
+ if (EVBUFFER_LENGTH(bufev->output) != 0)
+ bufferevent_add(&bufev->ev_write, bufev->timeout_write);
+ return;
+
+ error:
+ (*bufev->errorcb)(bufev, what, bufev->cbarg);
+}
+
+/*
+ * Create a new buffered event object.
+ *
+ * The read callback is invoked whenever we read new data.
+ * The write callback is invoked whenever the output buffer is drained.
+ * The error callback is invoked on a write/read error or on EOF.
+ *
+ * Both read and write callbacks maybe NULL. The error callback is not
+ * allowed to be NULL and have to be provided always.
+ */
+
+struct bufferevent *
+bufferevent_new(int fd, evbuffercb readcb, evbuffercb writecb,
+ everrorcb errorcb, void *cbarg)
+{
+ struct bufferevent *bufev;
+
+ if ((bufev = calloc(1, sizeof(struct bufferevent))) == NULL)
+ return (NULL);
+
+ if ((bufev->input = evbuffer_new()) == NULL) {
+ free(bufev);
+ return (NULL);
+ }
+
+ if ((bufev->output = evbuffer_new()) == NULL) {
+ evbuffer_free(bufev->input);
+ free(bufev);
+ return (NULL);
+ }
+
+ event_set(&bufev->ev_read, fd, EV_READ, bufferevent_readcb, bufev);
+ event_set(&bufev->ev_write, fd, EV_WRITE, bufferevent_writecb, bufev);
+
+ bufferevent_setcb(bufev, readcb, writecb, errorcb, cbarg);
+
+ /*
+ * Set to EV_WRITE so that using bufferevent_write is going to
+ * trigger a callback. Reading needs to be explicitly enabled
+ * because otherwise no data will be available.
+ */
+ bufev->enabled = EV_WRITE;
+
+ return (bufev);
+}
+
+void
+bufferevent_setcb(struct bufferevent *bufev,
+ evbuffercb readcb, evbuffercb writecb, everrorcb errorcb, void *cbarg)
+{
+ bufev->readcb = readcb;
+ bufev->writecb = writecb;
+ bufev->errorcb = errorcb;
+
+ bufev->cbarg = cbarg;
+}
+
+void
+bufferevent_setfd(struct bufferevent *bufev, int fd)
+{
+ event_del(&bufev->ev_read);
+ event_del(&bufev->ev_write);
+
+ event_set(&bufev->ev_read, fd, EV_READ, bufferevent_readcb, bufev);
+ event_set(&bufev->ev_write, fd, EV_WRITE, bufferevent_writecb, bufev);
+ if (bufev->ev_base != NULL) {
+ event_base_set(bufev->ev_base, &bufev->ev_read);
+ event_base_set(bufev->ev_base, &bufev->ev_write);
+ }
+
+ /* might have to manually trigger event registration */
+}
+
+int
+bufferevent_priority_set(struct bufferevent *bufev, int priority)
+{
+ if (event_priority_set(&bufev->ev_read, priority) == -1)
+ return (-1);
+ if (event_priority_set(&bufev->ev_write, priority) == -1)
+ return (-1);
+
+ return (0);
+}
+
+/* Closing the file descriptor is the responsibility of the caller */
+
+void
+bufferevent_free(struct bufferevent *bufev)
+{
+ event_del(&bufev->ev_read);
+ event_del(&bufev->ev_write);
+
+ evbuffer_free(bufev->input);
+ evbuffer_free(bufev->output);
+
+ free(bufev);
+}
+
+/*
+ * Returns 0 on success;
+ * -1 on failure.
+ */
+
+int
+bufferevent_write(struct bufferevent *bufev, const void *data, size_t size)
+{
+ int res;
+
+ res = evbuffer_add(bufev->output, data, size);
+
+ if (res == -1)
+ return (res);
+
+ /* If everything is okay, we need to schedule a write */
+ if (size > 0 && (bufev->enabled & EV_WRITE))
+ bufferevent_add(&bufev->ev_write, bufev->timeout_write);
+
+ return (res);
+}
+
+int
+bufferevent_write_buffer(struct bufferevent *bufev, struct evbuffer *buf)
+{
+ int res;
+
+ res = bufferevent_write(bufev, buf->buffer, buf->off);
+ if (res != -1)
+ evbuffer_drain(buf, buf->off);
+
+ return (res);
+}
+
+size_t
+bufferevent_read(struct bufferevent *bufev, void *data, size_t size)
+{
+ struct evbuffer *buf = bufev->input;
+
+ if (buf->off < size)
+ size = buf->off;
+
+ /* Copy the available data to the user buffer */
+ memcpy(data, buf->buffer, size);
+
+ if (size)
+ evbuffer_drain(buf, size);
+
+ return (size);
+}
+
+int
+bufferevent_enable(struct bufferevent *bufev, short event)
+{
+ if (event & EV_READ) {
+ if (bufferevent_add(&bufev->ev_read, bufev->timeout_read) == -1)
+ return (-1);
+ }
+ if (event & EV_WRITE) {
+ if (bufferevent_add(&bufev->ev_write, bufev->timeout_write) == -1)
+ return (-1);
+ }
+
+ bufev->enabled |= event;
+ return (0);
+}
+
+int
+bufferevent_disable(struct bufferevent *bufev, short event)
+{
+ if (event & EV_READ) {
+ if (event_del(&bufev->ev_read) == -1)
+ return (-1);
+ }
+ if (event & EV_WRITE) {
+ if (event_del(&bufev->ev_write) == -1)
+ return (-1);
+ }
+
+ bufev->enabled &= ~event;
+ return (0);
+}
+
+/*
+ * Sets the read and write timeout for a buffered event.
+ */
+
+void
+bufferevent_settimeout(struct bufferevent *bufev,
+ int timeout_read, int timeout_write) {
+ bufev->timeout_read = timeout_read;
+ bufev->timeout_write = timeout_write;
+
+ if (event_pending(&bufev->ev_read, EV_READ, NULL))
+ bufferevent_add(&bufev->ev_read, timeout_read);
+ if (event_pending(&bufev->ev_write, EV_WRITE, NULL))
+ bufferevent_add(&bufev->ev_write, timeout_write);
+}
+
+/*
+ * Sets the water marks
+ */
+
+void
+bufferevent_setwatermark(struct bufferevent *bufev, short events,
+ size_t lowmark, size_t highmark)
+{
+ if (events & EV_READ) {
+ bufev->wm_read.low = lowmark;
+ bufev->wm_read.high = highmark;
+ }
+
+ if (events & EV_WRITE) {
+ bufev->wm_write.low = lowmark;
+ bufev->wm_write.high = highmark;
+ }
+
+ /* If the watermarks changed then see if we should call read again */
+ bufferevent_read_pressure_cb(bufev->input,
+ 0, EVBUFFER_LENGTH(bufev->input), bufev);
+}
+
+int
+bufferevent_base_set(struct event_base *base, struct bufferevent *bufev)
+{
+ int res;
+
+ bufev->ev_base = base;
+
+ res = event_base_set(base, &bufev->ev_read);
+ if (res == -1)
+ return (res);
+
+ res = event_base_set(base, &bufev->ev_write);
+ return (res);
+}
diff --git a/chromium/base/third_party/libevent/evdns.3 b/chromium/base/third_party/libevent/evdns.3
new file mode 100644
index 00000000000..10414fa2efb
--- /dev/null
+++ b/chromium/base/third_party/libevent/evdns.3
@@ -0,0 +1,322 @@
+.\"
+.\" Copyright (c) 2006 Niels Provos <provos@citi.umich.edu>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+.\" AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+.\" THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+.\" EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+.\" PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+.\" OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd October 7, 2006
+.Dt EVDNS 3
+.Os
+.Sh NAME
+.Nm evdns_init
+.Nm evdns_shutdown
+.Nm evdns_err_to_string
+.Nm evdns_nameserver_add
+.Nm evdns_count_nameservers
+.Nm evdns_clear_nameservers_and_suspend
+.Nm evdns_resume
+.Nm evdns_nameserver_ip_add
+.Nm evdns_resolve_ipv4
+.Nm evdns_resolve_reverse
+.Nm evdns_resolv_conf_parse
+.Nm evdns_config_windows_nameservers
+.Nm evdns_search_clear
+.Nm evdns_search_add
+.Nm evdns_search_ndots_set
+.Nm evdns_set_log_fn
+.Nd asynchronous functions for DNS resolution.
+.Sh SYNOPSIS
+.Fd #include <sys/time.h>
+.Fd #include <event.h>
+.Fd #include <evdns.h>
+.Ft int
+.Fn evdns_init
+.Ft void
+.Fn evdns_shutdown "int fail_requests"
+.Ft "const char *"
+.Fn evdns_err_to_string "int err"
+.Ft int
+.Fn evdns_nameserver_add "unsigned long int address"
+.Ft int
+.Fn evdns_count_nameservers
+.Ft int
+.Fn evdns_clear_nameservers_and_suspend
+.Ft int
+.Fn evdns_resume
+.Ft int
+.Fn evdns_nameserver_ip_add(const char *ip_as_string);
+.Ft int
+.Fn evdns_resolve_ipv4 "const char *name" "int flags" "evdns_callback_type callback" "void *ptr"
+.Ft int
+.Fn evdns_resolve_reverse "struct in_addr *in" "int flags" "evdns_callback_type callback" "void *ptr"
+.Ft int
+.Fn evdns_resolv_conf_parse "int flags" "const char *"
+.Ft void
+.Fn evdns_search_clear
+.Ft void
+.Fn evdns_search_add "const char *domain"
+.Ft void
+.Fn evdns_search_ndots_set "const int ndots"
+.Ft void
+.Fn evdns_set_log_fn "evdns_debug_log_fn_type fn"
+.Ft int
+.Fn evdns_config_windows_nameservers
+.Sh DESCRIPTION
+Welcome, gentle reader
+.Pp
+Async DNS lookups are really a whole lot harder than they should be,
+mostly stemming from the fact that the libc resolver has never been
+very good at them. Before you use this library you should see if libc
+can do the job for you with the modern async call getaddrinfo_a
+(see http://www.imperialviolet.org/page25.html#e498). Otherwise,
+please continue.
+.Pp
+This code is based on libevent and you must call event_init before
+any of the APIs in this file. You must also seed the OpenSSL random
+source if you are using OpenSSL for ids (see below).
+.Pp
+This library is designed to be included and shipped with your source
+code. You statically link with it. You should also test for the
+existence of strtok_r and define HAVE_STRTOK_R if you have it.
+.Pp
+The DNS protocol requires a good source of id numbers and these
+numbers should be unpredictable for spoofing reasons. There are
+three methods for generating them here and you must define exactly
+one of them. In increasing order of preference:
+.Pp
+.Bl -tag -width "DNS_USE_GETTIMEOFDAY_FOR_ID" -compact -offset indent
+.It DNS_USE_GETTIMEOFDAY_FOR_ID
+Using the bottom 16 bits of the usec result from gettimeofday. This
+is a pretty poor solution but should work anywhere.
+.It DNS_USE_CPU_CLOCK_FOR_ID
+Using the bottom 16 bits of the nsec result from the CPU's time
+counter. This is better, but may not work everywhere. Requires
+POSIX realtime support and you'll need to link against -lrt on
+glibc systems at least.
+.It DNS_USE_OPENSSL_FOR_ID
+Uses the OpenSSL RAND_bytes call to generate the data. You must
+have seeded the pool before making any calls to this library.
+.El
+.Pp
+The library keeps track of the state of nameservers and will avoid
+them when they go down. Otherwise it will round robin between them.
+.Pp
+Quick start guide:
+ #include "evdns.h"
+ void callback(int result, char type, int count, int ttl,
+ void *addresses, void *arg);
+ evdns_resolv_conf_parse(DNS_OPTIONS_ALL, "/etc/resolv.conf");
+ evdns_resolve("www.hostname.com", 0, callback, NULL);
+.Pp
+When the lookup is complete the callback function is called. The
+first argument will be one of the DNS_ERR_* defines in evdns.h.
+Hopefully it will be DNS_ERR_NONE, in which case type will be
+DNS_IPv4_A, count will be the number of IP addresses, ttl is the time
+which the data can be cached for (in seconds), addresses will point
+to an array of uint32_t's and arg will be whatever you passed to
+evdns_resolve.
+.Pp
+Searching:
+.Pp
+In order for this library to be a good replacement for glibc's resolver it
+supports searching. This involves setting a list of default domains, in
+which names will be queried for. The number of dots in the query name
+determines the order in which this list is used.
+.Pp
+Searching appears to be a single lookup from the point of view of the API,
+although many DNS queries may be generated from a single call to
+evdns_resolve. Searching can also drastically slow down the resolution
+of names.
+.Pp
+To disable searching:
+.Bl -enum -compact -offset indent
+.It
+Never set it up. If you never call
+.Fn evdns_resolv_conf_parse,
+.Fn evdns_init,
+or
+.Fn evdns_search_add
+then no searching will occur.
+.It
+If you do call
+.Fn evdns_resolv_conf_parse
+then don't pass
+.Va DNS_OPTION_SEARCH
+(or
+.Va DNS_OPTIONS_ALL,
+which implies it).
+.It
+When calling
+.Fn evdns_resolve,
+pass the
+.Va DNS_QUERY_NO_SEARCH
+flag.
+.El
+.Pp
+The order of searches depends on the number of dots in the name. If the
+number is greater than the ndots setting then the names is first tried
+globally. Otherwise each search domain is appended in turn.
+.Pp
+The ndots setting can either be set from a resolv.conf, or by calling
+evdns_search_ndots_set.
+.Pp
+For example, with ndots set to 1 (the default) and a search domain list of
+["myhome.net"]:
+ Query: www
+ Order: www.myhome.net, www.
+.Pp
+ Query: www.abc
+ Order: www.abc., www.abc.myhome.net
+.Pp
+.Sh API reference
+.Pp
+.Bl -tag -width 0123456
+.It Ft int Fn evdns_init
+Initializes support for non-blocking name resolution by calling
+.Fn evdns_resolv_conf_parse
+on UNIX and
+.Fn evdns_config_windows_nameservers
+on Windows.
+.It Ft int Fn evdns_nameserver_add "unsigned long int address"
+Add a nameserver. The address should be an IP address in
+network byte order. The type of address is chosen so that
+it matches in_addr.s_addr.
+Returns non-zero on error.
+.It Ft int Fn evdns_nameserver_ip_add "const char *ip_as_string"
+This wraps the above function by parsing a string as an IP
+address and adds it as a nameserver.
+Returns non-zero on error
+.It Ft int Fn evdns_resolve "const char *name" "int flags" "evdns_callback_type callback" "void *ptr"
+Resolve a name. The name parameter should be a DNS name.
+The flags parameter should be 0, or DNS_QUERY_NO_SEARCH
+which disables searching for this query. (see defn of
+searching above).
+.Pp
+The callback argument is a function which is called when
+this query completes and ptr is an argument which is passed
+to that callback function.
+.Pp
+Returns non-zero on error
+.It Ft void Fn evdns_search_clear
+Clears the list of search domains
+.It Ft void Fn evdns_search_add "const char *domain"
+Add a domain to the list of search domains
+.It Ft void Fn evdns_search_ndots_set "int ndots"
+Set the number of dots which, when found in a name, causes
+the first query to be without any search domain.
+.It Ft int Fn evdns_count_nameservers "void"
+Return the number of configured nameservers (not necessarily the
+number of running nameservers). This is useful for double-checking
+whether our calls to the various nameserver configuration functions
+have been successful.
+.It Ft int Fn evdns_clear_nameservers_and_suspend "void"
+Remove all currently configured nameservers, and suspend all pending
+resolves. Resolves will not necessarily be re-attempted until
+evdns_resume() is called.
+.It Ft int Fn evdns_resume "void"
+Re-attempt resolves left in limbo after an earlier call to
+evdns_clear_nameservers_and_suspend().
+.It Ft int Fn evdns_config_windows_nameservers "void"
+Attempt to configure a set of nameservers based on platform settings on
+a win32 host. Preferentially tries to use GetNetworkParams; if that fails,
+looks in the registry. Returns 0 on success, nonzero on failure.
+.It Ft int Fn evdns_resolv_conf_parse "int flags" "const char *filename"
+Parse a resolv.conf like file from the given filename.
+.Pp
+See the man page for resolv.conf for the format of this file.
+The flags argument determines what information is parsed from
+this file:
+.Bl -tag -width "DNS_OPTION_NAMESERVERS" -offset indent -compact -nested
+.It DNS_OPTION_SEARCH
+domain, search and ndots options
+.It DNS_OPTION_NAMESERVERS
+nameserver lines
+.It DNS_OPTION_MISC
+timeout and attempts options
+.It DNS_OPTIONS_ALL
+all of the above
+.El
+.Pp
+The following directives are not parsed from the file:
+ sortlist, rotate, no-check-names, inet6, debug
+.Pp
+Returns non-zero on error:
+.Bl -tag -width "0" -offset indent -compact -nested
+.It 0
+no errors
+.It 1
+failed to open file
+.It 2
+failed to stat file
+.It 3
+file too large
+.It 4
+out of memory
+.It 5
+short read from file
+.El
+.El
+.Sh Internals:
+Requests are kept in two queues. The first is the inflight queue. In
+this queue requests have an allocated transaction id and nameserver.
+They will soon be transmitted if they haven't already been.
+.Pp
+The second is the waiting queue. The size of the inflight ring is
+limited and all other requests wait in waiting queue for space. This
+bounds the number of concurrent requests so that we don't flood the
+nameserver. Several algorithms require a full walk of the inflight
+queue and so bounding its size keeps thing going nicely under huge
+(many thousands of requests) loads.
+.Pp
+If a nameserver loses too many requests it is considered down and we
+try not to use it. After a while we send a probe to that nameserver
+(a lookup for google.com) and, if it replies, we consider it working
+again. If the nameserver fails a probe we wait longer to try again
+with the next probe.
+.Sh SEE ALSO
+.Xr event 3 ,
+.Xr gethostbyname 3 ,
+.Xr resolv.conf 5
+.Sh HISTORY
+The
+.Nm evdns
+API was developed by Adam Langley on top of the
+.Nm libevent
+API.
+The code was integrate into
+.Nm Tor
+by Nick Mathewson and finally put into
+.Nm libevent
+itself by Niels Provos.
+.Sh AUTHORS
+The
+.Nm evdns
+API and code was written by Adam Langley with significant
+contributions by Nick Mathewson.
+.Sh BUGS
+This documentation is neither complete nor authoritative.
+If you are in doubt about the usage of this API then
+check the source code to find out how it works, write
+up the missing piece of documentation and send it to
+me for inclusion in this man page.
diff --git a/chromium/base/third_party/libevent/evdns.c b/chromium/base/third_party/libevent/evdns.c
new file mode 100644
index 00000000000..05fe594bc75
--- /dev/null
+++ b/chromium/base/third_party/libevent/evdns.c
@@ -0,0 +1,3192 @@
+/* $Id: evdns.c 6979 2006-08-04 18:31:13Z nickm $ */
+
+/* The original version of this module was written by Adam Langley; for
+ * a history of modifications, check out the subversion logs.
+ *
+ * When editing this module, try to keep it re-mergeable by Adam. Don't
+ * reformat the whitespace, add Tor dependencies, or so on.
+ *
+ * TODO:
+ * - Support IPv6 and PTR records.
+ * - Replace all externally visible magic numbers with #defined constants.
+ * - Write doccumentation for APIs of all external functions.
+ */
+
+/* Async DNS Library
+ * Adam Langley <agl@imperialviolet.org>
+ * http://www.imperialviolet.org/eventdns.html
+ * Public Domain code
+ *
+ * This software is Public Domain. To view a copy of the public domain dedication,
+ * visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
+ * Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
+ *
+ * I ask and expect, but do not require, that all derivative works contain an
+ * attribution similar to:
+ * Parts developed by Adam Langley <agl@imperialviolet.org>
+ *
+ * You may wish to replace the word "Parts" with something else depending on
+ * the amount of original code.
+ *
+ * (Derivative works does not include programs which link against, run or include
+ * the source verbatim in their source distributions)
+ *
+ * Version: 0.1b
+ */
+
+#include <sys/types.h>
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef DNS_USE_FTIME_FOR_ID
+#include <sys/timeb.h>
+#endif
+
+#ifndef DNS_USE_CPU_CLOCK_FOR_ID
+#ifndef DNS_USE_GETTIMEOFDAY_FOR_ID
+#ifndef DNS_USE_OPENSSL_FOR_ID
+#ifndef DNS_USE_FTIME_FOR_ID
+#error Must configure at least one id generation method.
+#error Please see the documentation.
+#endif
+#endif
+#endif
+#endif
+
+/* #define _POSIX_C_SOURCE 200507 */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#ifdef DNS_USE_CPU_CLOCK_FOR_ID
+#ifdef DNS_USE_OPENSSL_FOR_ID
+#error Multiple id options selected
+#endif
+#ifdef DNS_USE_GETTIMEOFDAY_FOR_ID
+#error Multiple id options selected
+#endif
+#include <time.h>
+#endif
+
+#ifdef DNS_USE_OPENSSL_FOR_ID
+#ifdef DNS_USE_GETTIMEOFDAY_FOR_ID
+#error Multiple id options selected
+#endif
+#include <openssl/rand.h>
+#endif
+
+#ifndef _FORTIFY_SOURCE
+#define _FORTIFY_SOURCE 3
+#endif
+
+#include <string.h>
+#include <fcntl.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <limits.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "evdns.h"
+#include "evutil.h"
+#include "log.h"
+#ifdef WIN32
+#include <winsock2.h>
+#include <windows.h>
+#include <iphlpapi.h>
+#include <io.h>
+#else
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+
+#ifdef HAVE_NETINET_IN6_H
+#include <netinet/in6.h>
+#endif
+
+#define EVDNS_LOG_DEBUG 0
+#define EVDNS_LOG_WARN 1
+
+#ifndef HOST_NAME_MAX
+#define HOST_NAME_MAX 255
+#endif
+
+#include <stdio.h>
+
+#undef MIN
+#define MIN(a,b) ((a)<(b)?(a):(b))
+
+#ifdef __USE_ISOC99B
+/* libevent doesn't work without this */
+typedef ev_uint8_t u_char;
+typedef unsigned int uint;
+#endif
+#include "event.h"
+
+#define u64 ev_uint64_t
+#define u32 ev_uint32_t
+#define u16 ev_uint16_t
+#define u8 ev_uint8_t
+
+#ifdef WIN32
+#define open _open
+#define read _read
+#define close _close
+#define strdup _strdup
+#endif
+
+#define MAX_ADDRS 32 /* maximum number of addresses from a single packet */
+/* which we bother recording */
+
+#define TYPE_A EVDNS_TYPE_A
+#define TYPE_CNAME 5
+#define TYPE_PTR EVDNS_TYPE_PTR
+#define TYPE_AAAA EVDNS_TYPE_AAAA
+
+#define CLASS_INET EVDNS_CLASS_INET
+
+#ifdef HAVE_SETFD
+#define FD_CLOSEONEXEC(x) do { \
+ if (fcntl(x, F_SETFD, 1) == -1) \
+ event_warn("fcntl(%d, F_SETFD)", x); \
+ } while (0)
+#else
+#define FD_CLOSEONEXEC(x) (void)0
+#endif
+
+struct request {
+ u8 *request; /* the dns packet data */
+ unsigned int request_len;
+ int reissue_count;
+ int tx_count; /* the number of times that this packet has been sent */
+ unsigned int request_type; /* TYPE_PTR or TYPE_A */
+ void *user_pointer; /* the pointer given to us for this request */
+ evdns_callback_type user_callback;
+ struct nameserver *ns; /* the server which we last sent it */
+
+ /* elements used by the searching code */
+ int search_index;
+ struct search_state *search_state;
+ char *search_origname; /* needs to be free()ed */
+ int search_flags;
+
+ /* these objects are kept in a circular list */
+ struct request *next, *prev;
+
+ struct event timeout_event;
+
+ u16 trans_id; /* the transaction id */
+ char request_appended; /* true if the request pointer is data which follows this struct */
+ char transmit_me; /* needs to be transmitted */
+};
+
+#ifndef HAVE_STRUCT_IN6_ADDR
+struct in6_addr {
+ u8 s6_addr[16];
+};
+#endif
+
+struct reply {
+ unsigned int type;
+ unsigned int have_answer;
+ union {
+ struct {
+ u32 addrcount;
+ u32 addresses[MAX_ADDRS];
+ } a;
+ struct {
+ u32 addrcount;
+ struct in6_addr addresses[MAX_ADDRS];
+ } aaaa;
+ struct {
+ char name[HOST_NAME_MAX];
+ } ptr;
+ } data;
+};
+
+struct nameserver {
+ int socket; /* a connected UDP socket */
+ u32 address;
+ u16 port;
+ int failed_times; /* number of times which we have given this server a chance */
+ int timedout; /* number of times in a row a request has timed out */
+ struct event event;
+ /* these objects are kept in a circular list */
+ struct nameserver *next, *prev;
+ struct event timeout_event; /* used to keep the timeout for */
+ /* when we next probe this server. */
+ /* Valid if state == 0 */
+ char state; /* zero if we think that this server is down */
+ char choked; /* true if we have an EAGAIN from this server's socket */
+ char write_waiting; /* true if we are waiting for EV_WRITE events */
+};
+
+static struct request *req_head = NULL, *req_waiting_head = NULL;
+static struct nameserver *server_head = NULL;
+
+/* Represents a local port where we're listening for DNS requests. Right now, */
+/* only UDP is supported. */
+struct evdns_server_port {
+ int socket; /* socket we use to read queries and write replies. */
+ int refcnt; /* reference count. */
+ char choked; /* Are we currently blocked from writing? */
+ char closing; /* Are we trying to close this port, pending writes? */
+ evdns_request_callback_fn_type user_callback; /* Fn to handle requests */
+ void *user_data; /* Opaque pointer passed to user_callback */
+ struct event event; /* Read/write event */
+ /* circular list of replies that we want to write. */
+ struct server_request *pending_replies;
+};
+
+/* Represents part of a reply being built. (That is, a single RR.) */
+struct server_reply_item {
+ struct server_reply_item *next; /* next item in sequence. */
+ char *name; /* name part of the RR */
+ u16 type : 16; /* The RR type */
+ u16 class : 16; /* The RR class (usually CLASS_INET) */
+ u32 ttl; /* The RR TTL */
+ char is_name; /* True iff data is a label */
+ u16 datalen; /* Length of data; -1 if data is a label */
+ void *data; /* The contents of the RR */
+};
+
+/* Represents a request that we've received as a DNS server, and holds */
+/* the components of the reply as we're constructing it. */
+struct server_request {
+ /* Pointers to the next and previous entries on the list of replies */
+ /* that we're waiting to write. Only set if we have tried to respond */
+ /* and gotten EAGAIN. */
+ struct server_request *next_pending;
+ struct server_request *prev_pending;
+
+ u16 trans_id; /* Transaction id. */
+ struct evdns_server_port *port; /* Which port received this request on? */
+ struct sockaddr_storage addr; /* Where to send the response */
+ socklen_t addrlen; /* length of addr */
+
+ int n_answer; /* how many answer RRs have been set? */
+ int n_authority; /* how many authority RRs have been set? */
+ int n_additional; /* how many additional RRs have been set? */
+
+ struct server_reply_item *answer; /* linked list of answer RRs */
+ struct server_reply_item *authority; /* linked list of authority RRs */
+ struct server_reply_item *additional; /* linked list of additional RRs */
+
+ /* Constructed response. Only set once we're ready to send a reply. */
+ /* Once this is set, the RR fields are cleared, and no more should be set. */
+ char *response;
+ size_t response_len;
+
+ /* Caller-visible fields: flags, questions. */
+ struct evdns_server_request base;
+};
+
+/* helper macro */
+#define OFFSET_OF(st, member) ((off_t) (((char*)&((st*)0)->member)-(char*)0))
+
+/* Given a pointer to an evdns_server_request, get the corresponding */
+/* server_request. */
+#define TO_SERVER_REQUEST(base_ptr) \
+ ((struct server_request*) \
+ (((char*)(base_ptr) - OFFSET_OF(struct server_request, base))))
+
+/* The number of good nameservers that we have */
+static int global_good_nameservers = 0;
+
+/* inflight requests are contained in the req_head list */
+/* and are actually going out across the network */
+static int global_requests_inflight = 0;
+/* requests which aren't inflight are in the waiting list */
+/* and are counted here */
+static int global_requests_waiting = 0;
+
+static int global_max_requests_inflight = 64;
+
+static struct timeval global_timeout = {5, 0}; /* 5 seconds */
+static int global_max_reissues = 1; /* a reissue occurs when we get some errors from the server */
+static int global_max_retransmits = 3; /* number of times we'll retransmit a request which timed out */
+/* number of timeouts in a row before we consider this server to be down */
+static int global_max_nameserver_timeout = 3;
+
+/* These are the timeout values for nameservers. If we find a nameserver is down */
+/* we try to probe it at intervals as given below. Values are in seconds. */
+static const struct timeval global_nameserver_timeouts[] = {{10, 0}, {60, 0}, {300, 0}, {900, 0}, {3600, 0}};
+static const int global_nameserver_timeouts_length = sizeof(global_nameserver_timeouts)/sizeof(struct timeval);
+
+static struct nameserver *nameserver_pick(void);
+static void evdns_request_insert(struct request *req, struct request **head);
+static void nameserver_ready_callback(int fd, short events, void *arg);
+static int evdns_transmit(void);
+static int evdns_request_transmit(struct request *req);
+static void nameserver_send_probe(struct nameserver *const ns);
+static void search_request_finished(struct request *const);
+static int search_try_next(struct request *const req);
+static int search_request_new(int type, const char *const name, int flags, evdns_callback_type user_callback, void *user_arg);
+static void evdns_requests_pump_waiting_queue(void);
+static u16 transaction_id_pick(void);
+static struct request *request_new(int type, const char *name, int flags, evdns_callback_type callback, void *ptr);
+static void request_submit(struct request *const req);
+
+static int server_request_free(struct server_request *req);
+static void server_request_free_answers(struct server_request *req);
+static void server_port_free(struct evdns_server_port *port);
+static void server_port_ready_callback(int fd, short events, void *arg);
+
+static int strtoint(const char *const str);
+
+#ifdef WIN32
+static int
+last_error(int sock)
+{
+ int optval, optvallen=sizeof(optval);
+ int err = WSAGetLastError();
+ if (err == WSAEWOULDBLOCK && sock >= 0) {
+ if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (void*)&optval,
+ &optvallen))
+ return err;
+ if (optval)
+ return optval;
+ }
+ return err;
+
+}
+static int
+error_is_eagain(int err)
+{
+ return err == EAGAIN || err == WSAEWOULDBLOCK;
+}
+static int
+inet_aton(const char *c, struct in_addr *addr)
+{
+ ev_uint32_t r;
+ if (strcmp(c, "255.255.255.255") == 0) {
+ addr->s_addr = 0xffffffffu;
+ } else {
+ r = inet_addr(c);
+ if (r == INADDR_NONE)
+ return 0;
+ addr->s_addr = r;
+ }
+ return 1;
+}
+#else
+#define last_error(sock) (errno)
+#define error_is_eagain(err) ((err) == EAGAIN)
+#endif
+#define CLOSE_SOCKET(s) EVUTIL_CLOSESOCKET(s)
+
+#define ISSPACE(c) isspace((int)(unsigned char)(c))
+#define ISDIGIT(c) isdigit((int)(unsigned char)(c))
+
+static const char *
+debug_ntoa(u32 address)
+{
+ static char buf[32];
+ u32 a = ntohl(address);
+ evutil_snprintf(buf, sizeof(buf), "%d.%d.%d.%d",
+ (int)(u8)((a>>24)&0xff),
+ (int)(u8)((a>>16)&0xff),
+ (int)(u8)((a>>8 )&0xff),
+ (int)(u8)((a )&0xff));
+ return buf;
+}
+
+static evdns_debug_log_fn_type evdns_log_fn = NULL;
+
+void
+evdns_set_log_fn(evdns_debug_log_fn_type fn)
+{
+ evdns_log_fn = fn;
+}
+
+#ifdef __GNUC__
+#define EVDNS_LOG_CHECK __attribute__ ((format(printf, 2, 3)))
+#else
+#define EVDNS_LOG_CHECK
+#endif
+
+static void _evdns_log(int warn, const char *fmt, ...) EVDNS_LOG_CHECK;
+static void
+_evdns_log(int warn, const char *fmt, ...)
+{
+ va_list args;
+ static char buf[512];
+ if (!evdns_log_fn)
+ return;
+ va_start(args,fmt);
+ evutil_vsnprintf(buf, sizeof(buf), fmt, args);
+ buf[sizeof(buf)-1] = '\0';
+ evdns_log_fn(warn, buf);
+ va_end(args);
+}
+
+#define log _evdns_log
+
+/* This walks the list of inflight requests to find the */
+/* one with a matching transaction id. Returns NULL on */
+/* failure */
+static struct request *
+request_find_from_trans_id(u16 trans_id) {
+ struct request *req = req_head, *const started_at = req_head;
+
+ if (req) {
+ do {
+ if (req->trans_id == trans_id) return req;
+ req = req->next;
+ } while (req != started_at);
+ }
+
+ return NULL;
+}
+
+/* a libevent callback function which is called when a nameserver */
+/* has gone down and we want to test if it has came back to life yet */
+static void
+nameserver_prod_callback(int fd, short events, void *arg) {
+ struct nameserver *const ns = (struct nameserver *) arg;
+ (void)fd;
+ (void)events;
+
+ nameserver_send_probe(ns);
+}
+
+/* a libevent callback which is called when a nameserver probe (to see if */
+/* it has come back to life) times out. We increment the count of failed_times */
+/* and wait longer to send the next probe packet. */
+static void
+nameserver_probe_failed(struct nameserver *const ns) {
+ const struct timeval * timeout;
+ (void) evtimer_del(&ns->timeout_event);
+ if (ns->state == 1) {
+ /* This can happen if the nameserver acts in a way which makes us mark */
+ /* it as bad and then starts sending good replies. */
+ return;
+ }
+
+ timeout =
+ &global_nameserver_timeouts[MIN(ns->failed_times,
+ global_nameserver_timeouts_length - 1)];
+ ns->failed_times++;
+
+ if (evtimer_add(&ns->timeout_event, (struct timeval *) timeout) < 0) {
+ log(EVDNS_LOG_WARN,
+ "Error from libevent when adding timer event for %s",
+ debug_ntoa(ns->address));
+ /* ???? Do more? */
+ }
+}
+
+/* called when a nameserver has been deemed to have failed. For example, too */
+/* many packets have timed out etc */
+static void
+nameserver_failed(struct nameserver *const ns, const char *msg) {
+ struct request *req, *started_at;
+ /* if this nameserver has already been marked as failed */
+ /* then don't do anything */
+ if (!ns->state) return;
+
+ log(EVDNS_LOG_WARN, "Nameserver %s has failed: %s",
+ debug_ntoa(ns->address), msg);
+ global_good_nameservers--;
+ assert(global_good_nameservers >= 0);
+ if (global_good_nameservers == 0) {
+ log(EVDNS_LOG_WARN, "All nameservers have failed");
+ }
+
+ ns->state = 0;
+ ns->failed_times = 1;
+
+ if (evtimer_add(&ns->timeout_event, (struct timeval *) &global_nameserver_timeouts[0]) < 0) {
+ log(EVDNS_LOG_WARN,
+ "Error from libevent when adding timer event for %s",
+ debug_ntoa(ns->address));
+ /* ???? Do more? */
+ }
+
+ /* walk the list of inflight requests to see if any can be reassigned to */
+ /* a different server. Requests in the waiting queue don't have a */
+ /* nameserver assigned yet */
+
+ /* if we don't have *any* good nameservers then there's no point */
+ /* trying to reassign requests to one */
+ if (!global_good_nameservers) return;
+
+ req = req_head;
+ started_at = req_head;
+ if (req) {
+ do {
+ if (req->tx_count == 0 && req->ns == ns) {
+ /* still waiting to go out, can be moved */
+ /* to another server */
+ req->ns = nameserver_pick();
+ }
+ req = req->next;
+ } while (req != started_at);
+ }
+}
+
+static void
+nameserver_up(struct nameserver *const ns) {
+ if (ns->state) return;
+ log(EVDNS_LOG_WARN, "Nameserver %s is back up",
+ debug_ntoa(ns->address));
+ evtimer_del(&ns->timeout_event);
+ ns->state = 1;
+ ns->failed_times = 0;
+ ns->timedout = 0;
+ global_good_nameservers++;
+}
+
+static void
+request_trans_id_set(struct request *const req, const u16 trans_id) {
+ req->trans_id = trans_id;
+ *((u16 *) req->request) = htons(trans_id);
+}
+
+/* Called to remove a request from a list and dealloc it. */
+/* head is a pointer to the head of the list it should be */
+/* removed from or NULL if the request isn't in a list. */
+static void
+request_finished(struct request *const req, struct request **head) {
+ if (head) {
+ if (req->next == req) {
+ /* only item in the list */
+ *head = NULL;
+ } else {
+ req->next->prev = req->prev;
+ req->prev->next = req->next;
+ if (*head == req) *head = req->next;
+ }
+ }
+
+ log(EVDNS_LOG_DEBUG, "Removing timeout for request %lx",
+ (unsigned long) req);
+ evtimer_del(&req->timeout_event);
+
+ search_request_finished(req);
+ global_requests_inflight--;
+
+ if (!req->request_appended) {
+ /* need to free the request data on it's own */
+ free(req->request);
+ } else {
+ /* the request data is appended onto the header */
+ /* so everything gets free()ed when we: */
+ }
+
+ free(req);
+
+ evdns_requests_pump_waiting_queue();
+}
+
+/* This is called when a server returns a funny error code. */
+/* We try the request again with another server. */
+/* */
+/* return: */
+/* 0 ok */
+/* 1 failed/reissue is pointless */
+static int
+request_reissue(struct request *req) {
+ const struct nameserver *const last_ns = req->ns;
+ /* the last nameserver should have been marked as failing */
+ /* by the caller of this function, therefore pick will try */
+ /* not to return it */
+ req->ns = nameserver_pick();
+ if (req->ns == last_ns) {
+ /* ... but pick did return it */
+ /* not a lot of point in trying again with the */
+ /* same server */
+ return 1;
+ }
+
+ req->reissue_count++;
+ req->tx_count = 0;
+ req->transmit_me = 1;
+
+ return 0;
+}
+
+/* this function looks for space on the inflight queue and promotes */
+/* requests from the waiting queue if it can. */
+static void
+evdns_requests_pump_waiting_queue(void) {
+ while (global_requests_inflight < global_max_requests_inflight &&
+ global_requests_waiting) {
+ struct request *req;
+ /* move a request from the waiting queue to the inflight queue */
+ assert(req_waiting_head);
+ if (req_waiting_head->next == req_waiting_head) {
+ /* only one item in the queue */
+ req = req_waiting_head;
+ req_waiting_head = NULL;
+ } else {
+ req = req_waiting_head;
+ req->next->prev = req->prev;
+ req->prev->next = req->next;
+ req_waiting_head = req->next;
+ }
+
+ global_requests_waiting--;
+ global_requests_inflight++;
+
+ req->ns = nameserver_pick();
+ request_trans_id_set(req, transaction_id_pick());
+
+ evdns_request_insert(req, &req_head);
+ evdns_request_transmit(req);
+ evdns_transmit();
+ }
+}
+
+static void
+reply_callback(struct request *const req, u32 ttl, u32 err, struct reply *reply) {
+ switch (req->request_type) {
+ case TYPE_A:
+ if (reply)
+ req->user_callback(DNS_ERR_NONE, DNS_IPv4_A,
+ reply->data.a.addrcount, ttl,
+ reply->data.a.addresses,
+ req->user_pointer);
+ else
+ req->user_callback(err, 0, 0, 0, NULL, req->user_pointer);
+ return;
+ case TYPE_PTR:
+ if (reply) {
+ char *name = reply->data.ptr.name;
+ req->user_callback(DNS_ERR_NONE, DNS_PTR, 1, ttl,
+ &name, req->user_pointer);
+ } else {
+ req->user_callback(err, 0, 0, 0, NULL,
+ req->user_pointer);
+ }
+ return;
+ case TYPE_AAAA:
+ if (reply)
+ req->user_callback(DNS_ERR_NONE, DNS_IPv6_AAAA,
+ reply->data.aaaa.addrcount, ttl,
+ reply->data.aaaa.addresses,
+ req->user_pointer);
+ else
+ req->user_callback(err, 0, 0, 0, NULL, req->user_pointer);
+ return;
+ }
+ assert(0);
+}
+
+/* this processes a parsed reply packet */
+static void
+reply_handle(struct request *const req, u16 flags, u32 ttl, struct reply *reply) {
+ int error;
+ static const int error_codes[] = {
+ DNS_ERR_FORMAT, DNS_ERR_SERVERFAILED, DNS_ERR_NOTEXIST,
+ DNS_ERR_NOTIMPL, DNS_ERR_REFUSED
+ };
+
+ if (flags & 0x020f || !reply || !reply->have_answer) {
+ /* there was an error */
+ if (flags & 0x0200) {
+ error = DNS_ERR_TRUNCATED;
+ } else {
+ u16 error_code = (flags & 0x000f) - 1;
+ if (error_code > 4) {
+ error = DNS_ERR_UNKNOWN;
+ } else {
+ error = error_codes[error_code];
+ }
+ }
+
+ switch(error) {
+ case DNS_ERR_NOTIMPL:
+ case DNS_ERR_REFUSED:
+ /* we regard these errors as marking a bad nameserver */
+ if (req->reissue_count < global_max_reissues) {
+ char msg[64];
+ evutil_snprintf(msg, sizeof(msg),
+ "Bad response %d (%s)",
+ error, evdns_err_to_string(error));
+ nameserver_failed(req->ns, msg);
+ if (!request_reissue(req)) return;
+ }
+ break;
+ case DNS_ERR_SERVERFAILED:
+ /* rcode 2 (servfailed) sometimes means "we
+ * are broken" and sometimes (with some binds)
+ * means "that request was very confusing."
+ * Treat this as a timeout, not a failure.
+ */
+ log(EVDNS_LOG_DEBUG, "Got a SERVERFAILED from nameserver %s; "
+ "will allow the request to time out.",
+ debug_ntoa(req->ns->address));
+ break;
+ default:
+ /* we got a good reply from the nameserver */
+ nameserver_up(req->ns);
+ }
+
+ if (req->search_state && req->request_type != TYPE_PTR) {
+ /* if we have a list of domains to search in,
+ * try the next one */
+ if (!search_try_next(req)) {
+ /* a new request was issued so this
+ * request is finished and */
+ /* the user callback will be made when
+ * that request (or a */
+ /* child of it) finishes. */
+ request_finished(req, &req_head);
+ return;
+ }
+ }
+
+ /* all else failed. Pass the failure up */
+ reply_callback(req, 0, error, NULL);
+ request_finished(req, &req_head);
+ } else {
+ /* all ok, tell the user */
+ reply_callback(req, ttl, 0, reply);
+ nameserver_up(req->ns);
+ request_finished(req, &req_head);
+ }
+}
+
+static int
+name_parse(u8 *packet, int length, int *idx, char *name_out, int name_out_len) {
+ int name_end = -1;
+ int j = *idx;
+ int ptr_count = 0;
+#define GET32(x) do { if (j + 4 > length) goto err; memcpy(&_t32, packet + j, 4); j += 4; x = ntohl(_t32); } while(0)
+#define GET16(x) do { if (j + 2 > length) goto err; memcpy(&_t, packet + j, 2); j += 2; x = ntohs(_t); } while(0)
+#define GET8(x) do { if (j >= length) goto err; x = packet[j++]; } while(0)
+
+ char *cp = name_out;
+ const char *const end = name_out + name_out_len;
+
+ /* Normally, names are a series of length prefixed strings terminated */
+ /* with a length of 0 (the lengths are u8's < 63). */
+ /* However, the length can start with a pair of 1 bits and that */
+ /* means that the next 14 bits are a pointer within the current */
+ /* packet. */
+
+ for(;;) {
+ u8 label_len;
+ if (j >= length) return -1;
+ GET8(label_len);
+ if (!label_len) break;
+ if (label_len & 0xc0) {
+ u8 ptr_low;
+ GET8(ptr_low);
+ if (name_end < 0) name_end = j;
+ j = (((int)label_len & 0x3f) << 8) + ptr_low;
+ /* Make sure that the target offset is in-bounds. */
+ if (j < 0 || j >= length) return -1;
+ /* If we've jumped more times than there are characters in the
+ * message, we must have a loop. */
+ if (++ptr_count > length) return -1;
+ continue;
+ }
+ if (label_len > 63) return -1;
+ if (cp != name_out) {
+ if (cp + 1 >= end) return -1;
+ *cp++ = '.';
+ }
+ if (cp + label_len >= end) return -1;
+ memcpy(cp, packet + j, label_len);
+ cp += label_len;
+ j += label_len;
+ }
+ if (cp >= end) return -1;
+ *cp = '\0';
+ if (name_end < 0)
+ *idx = j;
+ else
+ *idx = name_end;
+ return 0;
+ err:
+ return -1;
+}
+
+/* parses a raw request from a nameserver */
+static int
+reply_parse(u8 *packet, int length) {
+ int j = 0, k = 0; /* index into packet */
+ u16 _t; /* used by the macros */
+ u32 _t32; /* used by the macros */
+ char tmp_name[256], cmp_name[256]; /* used by the macros */
+
+ u16 trans_id, questions, answers, authority, additional, datalength;
+ u16 flags = 0;
+ u32 ttl, ttl_r = 0xffffffff;
+ struct reply reply;
+ struct request *req = NULL;
+ unsigned int i;
+
+ GET16(trans_id);
+ GET16(flags);
+ GET16(questions);
+ GET16(answers);
+ GET16(authority);
+ GET16(additional);
+ (void) authority; /* suppress "unused variable" warnings. */
+ (void) additional; /* suppress "unused variable" warnings. */
+
+ req = request_find_from_trans_id(trans_id);
+ if (!req) return -1;
+
+ memset(&reply, 0, sizeof(reply));
+
+ /* If it's not an answer, it doesn't correspond to any request. */
+ if (!(flags & 0x8000)) return -1; /* must be an answer */
+ if (flags & 0x020f) {
+ /* there was an error */
+ goto err;
+ }
+ /* if (!answers) return; */ /* must have an answer of some form */
+
+ /* This macro skips a name in the DNS reply. */
+#define SKIP_NAME \
+ do { tmp_name[0] = '\0'; \
+ if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name))<0)\
+ goto err; \
+ } while(0)
+#define TEST_NAME \
+ do { tmp_name[0] = '\0'; \
+ cmp_name[0] = '\0'; \
+ k = j; \
+ if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name))<0)\
+ goto err; \
+ if (name_parse(req->request, req->request_len, &k, cmp_name, sizeof(cmp_name))<0) \
+ goto err; \
+ if (memcmp(tmp_name, cmp_name, strlen (tmp_name)) != 0) \
+ return (-1); /* we ignore mismatching names */ \
+ } while(0)
+
+ reply.type = req->request_type;
+
+ /* skip over each question in the reply */
+ for (i = 0; i < questions; ++i) {
+ /* the question looks like
+ * <label:name><u16:type><u16:class>
+ */
+ TEST_NAME;
+ j += 4;
+ if (j > length) goto err;
+ }
+
+ /* now we have the answer section which looks like
+ * <label:name><u16:type><u16:class><u32:ttl><u16:len><data...>
+ */
+
+ for (i = 0; i < answers; ++i) {
+ u16 type, class;
+
+ SKIP_NAME;
+ GET16(type);
+ GET16(class);
+ GET32(ttl);
+ GET16(datalength);
+
+ if (type == TYPE_A && class == CLASS_INET) {
+ int addrcount, addrtocopy;
+ if (req->request_type != TYPE_A) {
+ j += datalength; continue;
+ }
+ if ((datalength & 3) != 0) /* not an even number of As. */
+ goto err;
+ addrcount = datalength >> 2;
+ addrtocopy = MIN(MAX_ADDRS - reply.data.a.addrcount, (unsigned)addrcount);
+
+ ttl_r = MIN(ttl_r, ttl);
+ /* we only bother with the first four addresses. */
+ if (j + 4*addrtocopy > length) goto err;
+ memcpy(&reply.data.a.addresses[reply.data.a.addrcount],
+ packet + j, 4*addrtocopy);
+ j += 4*addrtocopy;
+ reply.data.a.addrcount += addrtocopy;
+ reply.have_answer = 1;
+ if (reply.data.a.addrcount == MAX_ADDRS) break;
+ } else if (type == TYPE_PTR && class == CLASS_INET) {
+ if (req->request_type != TYPE_PTR) {
+ j += datalength; continue;
+ }
+ if (name_parse(packet, length, &j, reply.data.ptr.name,
+ sizeof(reply.data.ptr.name))<0)
+ goto err;
+ ttl_r = MIN(ttl_r, ttl);
+ reply.have_answer = 1;
+ break;
+ } else if (type == TYPE_AAAA && class == CLASS_INET) {
+ int addrcount, addrtocopy;
+ if (req->request_type != TYPE_AAAA) {
+ j += datalength; continue;
+ }
+ if ((datalength & 15) != 0) /* not an even number of AAAAs. */
+ goto err;
+ addrcount = datalength >> 4; /* each address is 16 bytes long */
+ addrtocopy = MIN(MAX_ADDRS - reply.data.aaaa.addrcount, (unsigned)addrcount);
+ ttl_r = MIN(ttl_r, ttl);
+
+ /* we only bother with the first four addresses. */
+ if (j + 16*addrtocopy > length) goto err;
+ memcpy(&reply.data.aaaa.addresses[reply.data.aaaa.addrcount],
+ packet + j, 16*addrtocopy);
+ reply.data.aaaa.addrcount += addrtocopy;
+ j += 16*addrtocopy;
+ reply.have_answer = 1;
+ if (reply.data.aaaa.addrcount == MAX_ADDRS) break;
+ } else {
+ /* skip over any other type of resource */
+ j += datalength;
+ }
+ }
+
+ reply_handle(req, flags, ttl_r, &reply);
+ return 0;
+ err:
+ if (req)
+ reply_handle(req, flags, 0, NULL);
+ return -1;
+}
+
+/* Parse a raw request (packet,length) sent to a nameserver port (port) from */
+/* a DNS client (addr,addrlen), and if it's well-formed, call the corresponding */
+/* callback. */
+static int
+request_parse(u8 *packet, int length, struct evdns_server_port *port, struct sockaddr *addr, socklen_t addrlen)
+{
+ int j = 0; /* index into packet */
+ u16 _t; /* used by the macros */
+ char tmp_name[256]; /* used by the macros */
+
+ int i;
+ u16 trans_id, flags, questions, answers, authority, additional;
+ struct server_request *server_req = NULL;
+
+ /* Get the header fields */
+ GET16(trans_id);
+ GET16(flags);
+ GET16(questions);
+ GET16(answers);
+ GET16(authority);
+ GET16(additional);
+
+ if (flags & 0x8000) return -1; /* Must not be an answer. */
+ flags &= 0x0110; /* Only RD and CD get preserved. */
+
+ server_req = malloc(sizeof(struct server_request));
+ if (server_req == NULL) return -1;
+ memset(server_req, 0, sizeof(struct server_request));
+
+ server_req->trans_id = trans_id;
+ memcpy(&server_req->addr, addr, addrlen);
+ server_req->addrlen = addrlen;
+
+ server_req->base.flags = flags;
+ server_req->base.nquestions = 0;
+ server_req->base.questions = malloc(sizeof(struct evdns_server_question *) * questions);
+ if (server_req->base.questions == NULL)
+ goto err;
+
+ for (i = 0; i < questions; ++i) {
+ u16 type, class;
+ struct evdns_server_question *q;
+ int namelen;
+ if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name))<0)
+ goto err;
+ GET16(type);
+ GET16(class);
+ namelen = strlen(tmp_name);
+ q = malloc(sizeof(struct evdns_server_question) + namelen);
+ if (!q)
+ goto err;
+ q->type = type;
+ q->dns_question_class = class;
+ memcpy(q->name, tmp_name, namelen+1);
+ server_req->base.questions[server_req->base.nquestions++] = q;
+ }
+
+ /* Ignore answers, authority, and additional. */
+
+ server_req->port = port;
+ port->refcnt++;
+
+ /* Only standard queries are supported. */
+ if (flags & 0x7800) {
+ evdns_server_request_respond(&(server_req->base), DNS_ERR_NOTIMPL);
+ return -1;
+ }
+
+ port->user_callback(&(server_req->base), port->user_data);
+
+ return 0;
+err:
+ if (server_req) {
+ if (server_req->base.questions) {
+ for (i = 0; i < server_req->base.nquestions; ++i)
+ free(server_req->base.questions[i]);
+ free(server_req->base.questions);
+ }
+ free(server_req);
+ }
+ return -1;
+
+#undef SKIP_NAME
+#undef GET32
+#undef GET16
+#undef GET8
+}
+
+static u16
+default_transaction_id_fn(void)
+{
+ u16 trans_id;
+#ifdef DNS_USE_CPU_CLOCK_FOR_ID
+ struct timespec ts;
+ static int clkid = -1;
+ if (clkid == -1) {
+ clkid = CLOCK_REALTIME;
+#ifdef CLOCK_MONOTONIC
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) != -1)
+ clkid = CLOCK_MONOTONIC;
+#endif
+ }
+ if (clock_gettime(clkid, &ts) == -1)
+ event_err(1, "clock_gettime");
+ trans_id = ts.tv_nsec & 0xffff;
+#endif
+
+#ifdef DNS_USE_FTIME_FOR_ID
+ struct _timeb tb;
+ _ftime(&tb);
+ trans_id = tb.millitm & 0xffff;
+#endif
+
+#ifdef DNS_USE_GETTIMEOFDAY_FOR_ID
+ struct timeval tv;
+ evutil_gettimeofday(&tv, NULL);
+ trans_id = tv.tv_usec & 0xffff;
+#endif
+
+#ifdef DNS_USE_OPENSSL_FOR_ID
+ if (RAND_pseudo_bytes((u8 *) &trans_id, 2) == -1) {
+ /* in the case that the RAND call fails we back */
+ /* down to using gettimeofday. */
+ /*
+ struct timeval tv;
+ evutil_gettimeofday(&tv, NULL);
+ trans_id = tv.tv_usec & 0xffff;
+ */
+ abort();
+ }
+#endif
+ return trans_id;
+}
+
+static ev_uint16_t (*trans_id_function)(void) = default_transaction_id_fn;
+
+void
+evdns_set_transaction_id_fn(ev_uint16_t (*fn)(void))
+{
+ if (fn)
+ trans_id_function = fn;
+ else
+ trans_id_function = default_transaction_id_fn;
+}
+
+/* Try to choose a strong transaction id which isn't already in flight */
+static u16
+transaction_id_pick(void) {
+ for (;;) {
+ u16 trans_id = trans_id_function();
+
+ if (trans_id == 0xffff) continue;
+
+ if (request_find_from_trans_id(trans_id) == NULL)
+ return trans_id;
+ }
+}
+
+/* choose a namesever to use. This function will try to ignore */
+/* nameservers which we think are down and load balance across the rest */
+/* by updating the server_head global each time. */
+static struct nameserver *
+nameserver_pick(void) {
+ struct nameserver *started_at = server_head, *picked;
+ if (!server_head) return NULL;
+
+ /* if we don't have any good nameservers then there's no */
+ /* point in trying to find one. */
+ if (!global_good_nameservers) {
+ server_head = server_head->next;
+ return server_head;
+ }
+
+ /* remember that nameservers are in a circular list */
+ for (;;) {
+ if (server_head->state) {
+ /* we think this server is currently good */
+ picked = server_head;
+ server_head = server_head->next;
+ return picked;
+ }
+
+ server_head = server_head->next;
+ if (server_head == started_at) {
+ /* all the nameservers seem to be down */
+ /* so we just return this one and hope for the */
+ /* best */
+ assert(global_good_nameservers == 0);
+ picked = server_head;
+ server_head = server_head->next;
+ return picked;
+ }
+ }
+}
+
+static int
+address_is_correct(struct nameserver *ns, struct sockaddr *sa, socklen_t slen)
+{
+ struct sockaddr_in *sin = (struct sockaddr_in*) sa;
+ if (sa->sa_family != AF_INET || slen != sizeof(struct sockaddr_in))
+ return 0;
+ if (sin->sin_addr.s_addr != ns->address)
+ return 0;
+ return 1;
+}
+
+/* this is called when a namesever socket is ready for reading */
+static void
+nameserver_read(struct nameserver *ns) {
+ u8 packet[1500];
+ struct sockaddr_storage ss;
+ socklen_t addrlen = sizeof(ss);
+
+ for (;;) {
+ const int r = recvfrom(ns->socket, packet, sizeof(packet), 0,
+ (struct sockaddr*)&ss, &addrlen);
+ if (r < 0) {
+ int err = last_error(ns->socket);
+ if (error_is_eagain(err)) return;
+ nameserver_failed(ns, strerror(err));
+ return;
+ }
+ if (!address_is_correct(ns, (struct sockaddr*)&ss, addrlen)) {
+ log(EVDNS_LOG_WARN, "Address mismatch on received "
+ "DNS packet.");
+ return;
+ }
+ ns->timedout = 0;
+ reply_parse(packet, r);
+ }
+}
+
+/* Read a packet from a DNS client on a server port s, parse it, and */
+/* act accordingly. */
+static void
+server_port_read(struct evdns_server_port *s) {
+ u8 packet[1500];
+ struct sockaddr_storage addr;
+ socklen_t addrlen;
+ int r;
+
+ for (;;) {
+ addrlen = sizeof(struct sockaddr_storage);
+ r = recvfrom(s->socket, packet, sizeof(packet), 0,
+ (struct sockaddr*) &addr, &addrlen);
+ if (r < 0) {
+ int err = last_error(s->socket);
+ if (error_is_eagain(err)) return;
+ log(EVDNS_LOG_WARN, "Error %s (%d) while reading request.",
+ strerror(err), err);
+ return;
+ }
+ request_parse(packet, r, s, (struct sockaddr*) &addr, addrlen);
+ }
+}
+
+/* Try to write all pending replies on a given DNS server port. */
+static void
+server_port_flush(struct evdns_server_port *port)
+{
+ while (port->pending_replies) {
+ struct server_request *req = port->pending_replies;
+ int r = sendto(port->socket, req->response, req->response_len, 0,
+ (struct sockaddr*) &req->addr, req->addrlen);
+ if (r < 0) {
+ int err = last_error(port->socket);
+ if (error_is_eagain(err))
+ return;
+ log(EVDNS_LOG_WARN, "Error %s (%d) while writing response to port; dropping", strerror(err), err);
+ }
+ if (server_request_free(req)) {
+ /* we released the last reference to req->port. */
+ return;
+ }
+ }
+
+ /* We have no more pending requests; stop listening for 'writeable' events. */
+ (void) event_del(&port->event);
+ event_set(&port->event, port->socket, EV_READ | EV_PERSIST,
+ server_port_ready_callback, port);
+ if (event_add(&port->event, NULL) < 0) {
+ log(EVDNS_LOG_WARN, "Error from libevent when adding event for DNS server.");
+ /* ???? Do more? */
+ }
+}
+
+/* set if we are waiting for the ability to write to this server. */
+/* if waiting is true then we ask libevent for EV_WRITE events, otherwise */
+/* we stop these events. */
+static void
+nameserver_write_waiting(struct nameserver *ns, char waiting) {
+ if (ns->write_waiting == waiting) return;
+
+ ns->write_waiting = waiting;
+ (void) event_del(&ns->event);
+ event_set(&ns->event, ns->socket, EV_READ | (waiting ? EV_WRITE : 0) | EV_PERSIST,
+ nameserver_ready_callback, ns);
+ if (event_add(&ns->event, NULL) < 0) {
+ log(EVDNS_LOG_WARN, "Error from libevent when adding event for %s",
+ debug_ntoa(ns->address));
+ /* ???? Do more? */
+ }
+}
+
+/* a callback function. Called by libevent when the kernel says that */
+/* a nameserver socket is ready for writing or reading */
+static void
+nameserver_ready_callback(int fd, short events, void *arg) {
+ struct nameserver *ns = (struct nameserver *) arg;
+ (void)fd;
+
+ if (events & EV_WRITE) {
+ ns->choked = 0;
+ if (!evdns_transmit()) {
+ nameserver_write_waiting(ns, 0);
+ }
+ }
+ if (events & EV_READ) {
+ nameserver_read(ns);
+ }
+}
+
+/* a callback function. Called by libevent when the kernel says that */
+/* a server socket is ready for writing or reading. */
+static void
+server_port_ready_callback(int fd, short events, void *arg) {
+ struct evdns_server_port *port = (struct evdns_server_port *) arg;
+ (void) fd;
+
+ if (events & EV_WRITE) {
+ port->choked = 0;
+ server_port_flush(port);
+ }
+ if (events & EV_READ) {
+ server_port_read(port);
+ }
+}
+
+/* This is an inefficient representation; only use it via the dnslabel_table_*
+ * functions, so that is can be safely replaced with something smarter later. */
+#define MAX_LABELS 128
+/* Structures used to implement name compression */
+struct dnslabel_entry { char *v; off_t pos; };
+struct dnslabel_table {
+ int n_labels; /* number of current entries */
+ /* map from name to position in message */
+ struct dnslabel_entry labels[MAX_LABELS];
+};
+
+/* Initialize dnslabel_table. */
+static void
+dnslabel_table_init(struct dnslabel_table *table)
+{
+ table->n_labels = 0;
+}
+
+/* Free all storage held by table, but not the table itself. */
+static void
+dnslabel_clear(struct dnslabel_table *table)
+{
+ int i;
+ for (i = 0; i < table->n_labels; ++i)
+ free(table->labels[i].v);
+ table->n_labels = 0;
+}
+
+/* return the position of the label in the current message, or -1 if the label */
+/* hasn't been used yet. */
+static int
+dnslabel_table_get_pos(const struct dnslabel_table *table, const char *label)
+{
+ int i;
+ for (i = 0; i < table->n_labels; ++i) {
+ if (!strcmp(label, table->labels[i].v))
+ return table->labels[i].pos;
+ }
+ return -1;
+}
+
+/* remember that we've used the label at position pos */
+static int
+dnslabel_table_add(struct dnslabel_table *table, const char *label, off_t pos)
+{
+ char *v;
+ int p;
+ if (table->n_labels == MAX_LABELS)
+ return (-1);
+ v = strdup(label);
+ if (v == NULL)
+ return (-1);
+ p = table->n_labels++;
+ table->labels[p].v = v;
+ table->labels[p].pos = pos;
+
+ return (0);
+}
+
+/* Converts a string to a length-prefixed set of DNS labels, starting */
+/* at buf[j]. name and buf must not overlap. name_len should be the length */
+/* of name. table is optional, and is used for compression. */
+/* */
+/* Input: abc.def */
+/* Output: <3>abc<3>def<0> */
+/* */
+/* Returns the first index after the encoded name, or negative on error. */
+/* -1 label was > 63 bytes */
+/* -2 name too long to fit in buffer. */
+/* */
+static off_t
+dnsname_to_labels(u8 *const buf, size_t buf_len, off_t j,
+ const char *name, const int name_len,
+ struct dnslabel_table *table) {
+ const char *end = name + name_len;
+ int ref = 0;
+ u16 _t;
+
+#define APPEND16(x) do { \
+ if (j + 2 > (off_t)buf_len) \
+ goto overflow; \
+ _t = htons(x); \
+ memcpy(buf + j, &_t, 2); \
+ j += 2; \
+ } while (0)
+#define APPEND32(x) do { \
+ if (j + 4 > (off_t)buf_len) \
+ goto overflow; \
+ _t32 = htonl(x); \
+ memcpy(buf + j, &_t32, 4); \
+ j += 4; \
+ } while (0)
+
+ if (name_len > 255) return -2;
+
+ for (;;) {
+ const char *const start = name;
+ if (table && (ref = dnslabel_table_get_pos(table, name)) >= 0) {
+ APPEND16(ref | 0xc000);
+ return j;
+ }
+ name = strchr(name, '.');
+ if (!name) {
+ const unsigned int label_len = end - start;
+ if (label_len > 63) return -1;
+ if ((size_t)(j+label_len+1) > buf_len) return -2;
+ if (table) dnslabel_table_add(table, start, j);
+ buf[j++] = label_len;
+
+ memcpy(buf + j, start, end - start);
+ j += end - start;
+ break;
+ } else {
+ /* append length of the label. */
+ const unsigned int label_len = name - start;
+ if (label_len > 63) return -1;
+ if ((size_t)(j+label_len+1) > buf_len) return -2;
+ if (table) dnslabel_table_add(table, start, j);
+ buf[j++] = label_len;
+
+ memcpy(buf + j, start, name - start);
+ j += name - start;
+ /* hop over the '.' */
+ name++;
+ }
+ }
+
+ /* the labels must be terminated by a 0. */
+ /* It's possible that the name ended in a . */
+ /* in which case the zero is already there */
+ if (!j || buf[j-1]) buf[j++] = 0;
+ return j;
+ overflow:
+ return (-2);
+}
+
+/* Finds the length of a dns request for a DNS name of the given */
+/* length. The actual request may be smaller than the value returned */
+/* here */
+static int
+evdns_request_len(const int name_len) {
+ return 96 + /* length of the DNS standard header */
+ name_len + 2 +
+ 4; /* space for the resource type */
+}
+
+/* build a dns request packet into buf. buf should be at least as long */
+/* as evdns_request_len told you it should be. */
+/* */
+/* Returns the amount of space used. Negative on error. */
+static int
+evdns_request_data_build(const char *const name, const int name_len,
+ const u16 trans_id, const u16 type, const u16 class,
+ u8 *const buf, size_t buf_len) {
+ off_t j = 0; /* current offset into buf */
+ u16 _t; /* used by the macros */
+
+ APPEND16(trans_id);
+ APPEND16(0x0100); /* standard query, recusion needed */
+ APPEND16(1); /* one question */
+ APPEND16(0); /* no answers */
+ APPEND16(0); /* no authority */
+ APPEND16(0); /* no additional */
+
+ j = dnsname_to_labels(buf, buf_len, j, name, name_len, NULL);
+ if (j < 0) {
+ return (int)j;
+ }
+
+ APPEND16(type);
+ APPEND16(class);
+
+ return (int)j;
+ overflow:
+ return (-1);
+}
+
+/* exported function */
+struct evdns_server_port *
+evdns_add_server_port(int socket, int is_tcp, evdns_request_callback_fn_type cb, void *user_data)
+{
+ struct evdns_server_port *port;
+ if (!(port = malloc(sizeof(struct evdns_server_port))))
+ return NULL;
+ memset(port, 0, sizeof(struct evdns_server_port));
+
+ assert(!is_tcp); /* TCP sockets not yet implemented */
+ port->socket = socket;
+ port->refcnt = 1;
+ port->choked = 0;
+ port->closing = 0;
+ port->user_callback = cb;
+ port->user_data = user_data;
+ port->pending_replies = NULL;
+
+ event_set(&port->event, port->socket, EV_READ | EV_PERSIST,
+ server_port_ready_callback, port);
+ event_add(&port->event, NULL); /* check return. */
+ return port;
+}
+
+/* exported function */
+void
+evdns_close_server_port(struct evdns_server_port *port)
+{
+ if (--port->refcnt == 0)
+ server_port_free(port);
+ port->closing = 1;
+}
+
+/* exported function */
+int
+evdns_server_request_add_reply(struct evdns_server_request *_req, int section, const char *name, int type, int class, int ttl, int datalen, int is_name, const char *data)
+{
+ struct server_request *req = TO_SERVER_REQUEST(_req);
+ struct server_reply_item **itemp, *item;
+ int *countp;
+
+ if (req->response) /* have we already answered? */
+ return (-1);
+
+ switch (section) {
+ case EVDNS_ANSWER_SECTION:
+ itemp = &req->answer;
+ countp = &req->n_answer;
+ break;
+ case EVDNS_AUTHORITY_SECTION:
+ itemp = &req->authority;
+ countp = &req->n_authority;
+ break;
+ case EVDNS_ADDITIONAL_SECTION:
+ itemp = &req->additional;
+ countp = &req->n_additional;
+ break;
+ default:
+ return (-1);
+ }
+ while (*itemp) {
+ itemp = &((*itemp)->next);
+ }
+ item = malloc(sizeof(struct server_reply_item));
+ if (!item)
+ return -1;
+ item->next = NULL;
+ if (!(item->name = strdup(name))) {
+ free(item);
+ return -1;
+ }
+ item->type = type;
+ item->dns_question_class = class;
+ item->ttl = ttl;
+ item->is_name = is_name != 0;
+ item->datalen = 0;
+ item->data = NULL;
+ if (data) {
+ if (item->is_name) {
+ if (!(item->data = strdup(data))) {
+ free(item->name);
+ free(item);
+ return -1;
+ }
+ item->datalen = (u16)-1;
+ } else {
+ if (!(item->data = malloc(datalen))) {
+ free(item->name);
+ free(item);
+ return -1;
+ }
+ item->datalen = datalen;
+ memcpy(item->data, data, datalen);
+ }
+ }
+
+ *itemp = item;
+ ++(*countp);
+ return 0;
+}
+
+/* exported function */
+int
+evdns_server_request_add_a_reply(struct evdns_server_request *req, const char *name, int n, void *addrs, int ttl)
+{
+ return evdns_server_request_add_reply(
+ req, EVDNS_ANSWER_SECTION, name, TYPE_A, CLASS_INET,
+ ttl, n*4, 0, addrs);
+}
+
+/* exported function */
+int
+evdns_server_request_add_aaaa_reply(struct evdns_server_request *req, const char *name, int n, void *addrs, int ttl)
+{
+ return evdns_server_request_add_reply(
+ req, EVDNS_ANSWER_SECTION, name, TYPE_AAAA, CLASS_INET,
+ ttl, n*16, 0, addrs);
+}
+
+/* exported function */
+int
+evdns_server_request_add_ptr_reply(struct evdns_server_request *req, struct in_addr *in, const char *inaddr_name, const char *hostname, int ttl)
+{
+ u32 a;
+ char buf[32];
+ assert(in || inaddr_name);
+ assert(!(in && inaddr_name));
+ if (in) {
+ a = ntohl(in->s_addr);
+ evutil_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa",
+ (int)(u8)((a )&0xff),
+ (int)(u8)((a>>8 )&0xff),
+ (int)(u8)((a>>16)&0xff),
+ (int)(u8)((a>>24)&0xff));
+ inaddr_name = buf;
+ }
+ return evdns_server_request_add_reply(
+ req, EVDNS_ANSWER_SECTION, inaddr_name, TYPE_PTR, CLASS_INET,
+ ttl, -1, 1, hostname);
+}
+
+/* exported function */
+int
+evdns_server_request_add_cname_reply(struct evdns_server_request *req, const char *name, const char *cname, int ttl)
+{
+ return evdns_server_request_add_reply(
+ req, EVDNS_ANSWER_SECTION, name, TYPE_CNAME, CLASS_INET,
+ ttl, -1, 1, cname);
+}
+
+
+static int
+evdns_server_request_format_response(struct server_request *req, int err)
+{
+ unsigned char buf[1500];
+ size_t buf_len = sizeof(buf);
+ off_t j = 0, r;
+ u16 _t;
+ u32 _t32;
+ int i;
+ u16 flags;
+ struct dnslabel_table table;
+
+ if (err < 0 || err > 15) return -1;
+
+ /* Set response bit and error code; copy OPCODE and RD fields from
+ * question; copy RA and AA if set by caller. */
+ flags = req->base.flags;
+ flags |= (0x8000 | err);
+
+ dnslabel_table_init(&table);
+ APPEND16(req->trans_id);
+ APPEND16(flags);
+ APPEND16(req->base.nquestions);
+ APPEND16(req->n_answer);
+ APPEND16(req->n_authority);
+ APPEND16(req->n_additional);
+
+ /* Add questions. */
+ for (i=0; i < req->base.nquestions; ++i) {
+ const char *s = req->base.questions[i]->name;
+ j = dnsname_to_labels(buf, buf_len, j, s, strlen(s), &table);
+ if (j < 0) {
+ dnslabel_clear(&table);
+ return (int) j;
+ }
+ APPEND16(req->base.questions[i]->type);
+ APPEND16(req->base.questions[i]->dns_question_class);
+ }
+
+ /* Add answer, authority, and additional sections. */
+ for (i=0; i<3; ++i) {
+ struct server_reply_item *item;
+ if (i==0)
+ item = req->answer;
+ else if (i==1)
+ item = req->authority;
+ else
+ item = req->additional;
+ while (item) {
+ r = dnsname_to_labels(buf, buf_len, j, item->name, strlen(item->name), &table);
+ if (r < 0)
+ goto overflow;
+ j = r;
+
+ APPEND16(item->type);
+ APPEND16(item->dns_question_class);
+ APPEND32(item->ttl);
+ if (item->is_name) {
+ off_t len_idx = j, name_start;
+ j += 2;
+ name_start = j;
+ r = dnsname_to_labels(buf, buf_len, j, item->data, strlen(item->data), &table);
+ if (r < 0)
+ goto overflow;
+ j = r;
+ _t = htons( (short) (j-name_start) );
+ memcpy(buf+len_idx, &_t, 2);
+ } else {
+ APPEND16(item->datalen);
+ if (j+item->datalen > (off_t)buf_len)
+ goto overflow;
+ memcpy(buf+j, item->data, item->datalen);
+ j += item->datalen;
+ }
+ item = item->next;
+ }
+ }
+
+ if (j > 512) {
+overflow:
+ j = 512;
+ buf[2] |= 0x02; /* set the truncated bit. */
+ }
+
+ req->response_len = j;
+
+ if (!(req->response = malloc(req->response_len))) {
+ server_request_free_answers(req);
+ dnslabel_clear(&table);
+ return (-1);
+ }
+ memcpy(req->response, buf, req->response_len);
+ server_request_free_answers(req);
+ dnslabel_clear(&table);
+ return (0);
+}
+
+/* exported function */
+int
+evdns_server_request_respond(struct evdns_server_request *_req, int err)
+{
+ struct server_request *req = TO_SERVER_REQUEST(_req);
+ struct evdns_server_port *port = req->port;
+ int r;
+ if (!req->response) {
+ if ((r = evdns_server_request_format_response(req, err))<0)
+ return r;
+ }
+
+ r = sendto(port->socket, req->response, req->response_len, 0,
+ (struct sockaddr*) &req->addr, req->addrlen);
+ if (r<0) {
+ int sock_err = last_error(port->socket);
+ if (! error_is_eagain(sock_err))
+ return -1;
+
+ if (port->pending_replies) {
+ req->prev_pending = port->pending_replies->prev_pending;
+ req->next_pending = port->pending_replies;
+ req->prev_pending->next_pending =
+ req->next_pending->prev_pending = req;
+ } else {
+ req->prev_pending = req->next_pending = req;
+ port->pending_replies = req;
+ port->choked = 1;
+
+ (void) event_del(&port->event);
+ event_set(&port->event, port->socket, (port->closing?0:EV_READ) | EV_WRITE | EV_PERSIST, server_port_ready_callback, port);
+
+ if (event_add(&port->event, NULL) < 0) {
+ log(EVDNS_LOG_WARN, "Error from libevent when adding event for DNS server");
+ }
+
+ }
+
+ return 1;
+ }
+ if (server_request_free(req))
+ return 0;
+
+ if (port->pending_replies)
+ server_port_flush(port);
+
+ return 0;
+}
+
+/* Free all storage held by RRs in req. */
+static void
+server_request_free_answers(struct server_request *req)
+{
+ struct server_reply_item *victim, *next, **list;
+ int i;
+ for (i = 0; i < 3; ++i) {
+ if (i==0)
+ list = &req->answer;
+ else if (i==1)
+ list = &req->authority;
+ else
+ list = &req->additional;
+
+ victim = *list;
+ while (victim) {
+ next = victim->next;
+ free(victim->name);
+ if (victim->data)
+ free(victim->data);
+ free(victim);
+ victim = next;
+ }
+ *list = NULL;
+ }
+}
+
+/* Free all storage held by req, and remove links to it. */
+/* return true iff we just wound up freeing the server_port. */
+static int
+server_request_free(struct server_request *req)
+{
+ int i, rc=1;
+ if (req->base.questions) {
+ for (i = 0; i < req->base.nquestions; ++i)
+ free(req->base.questions[i]);
+ free(req->base.questions);
+ }
+
+ if (req->port) {
+ if (req->port->pending_replies == req) {
+ if (req->next_pending)
+ req->port->pending_replies = req->next_pending;
+ else
+ req->port->pending_replies = NULL;
+ }
+ rc = --req->port->refcnt;
+ }
+
+ if (req->response) {
+ free(req->response);
+ }
+
+ server_request_free_answers(req);
+
+ if (req->next_pending && req->next_pending != req) {
+ req->next_pending->prev_pending = req->prev_pending;
+ req->prev_pending->next_pending = req->next_pending;
+ }
+
+ if (rc == 0) {
+ server_port_free(req->port);
+ free(req);
+ return (1);
+ }
+ free(req);
+ return (0);
+}
+
+/* Free all storage held by an evdns_server_port. Only called when */
+static void
+server_port_free(struct evdns_server_port *port)
+{
+ assert(port);
+ assert(!port->refcnt);
+ assert(!port->pending_replies);
+ if (port->socket > 0) {
+ CLOSE_SOCKET(port->socket);
+ port->socket = -1;
+ }
+ (void) event_del(&port->event);
+ /* XXXX actually free the port? -NM */
+}
+
+/* exported function */
+int
+evdns_server_request_drop(struct evdns_server_request *_req)
+{
+ struct server_request *req = TO_SERVER_REQUEST(_req);
+ server_request_free(req);
+ return 0;
+}
+
+/* exported function */
+int
+evdns_server_request_get_requesting_addr(struct evdns_server_request *_req, struct sockaddr *sa, int addr_len)
+{
+ struct server_request *req = TO_SERVER_REQUEST(_req);
+ if (addr_len < (int)req->addrlen)
+ return -1;
+ memcpy(sa, &(req->addr), req->addrlen);
+ return req->addrlen;
+}
+
+#undef APPEND16
+#undef APPEND32
+
+/* this is a libevent callback function which is called when a request */
+/* has timed out. */
+static void
+evdns_request_timeout_callback(int fd, short events, void *arg) {
+ struct request *const req = (struct request *) arg;
+ (void) fd;
+ (void) events;
+
+ log(EVDNS_LOG_DEBUG, "Request %lx timed out", (unsigned long) arg);
+
+ req->ns->timedout++;
+ if (req->ns->timedout > global_max_nameserver_timeout) {
+ req->ns->timedout = 0;
+ nameserver_failed(req->ns, "request timed out.");
+ }
+
+ (void) evtimer_del(&req->timeout_event);
+ if (req->tx_count >= global_max_retransmits) {
+ /* this request has failed */
+ reply_callback(req, 0, DNS_ERR_TIMEOUT, NULL);
+ request_finished(req, &req_head);
+ } else {
+ /* retransmit it */
+ evdns_request_transmit(req);
+ }
+}
+
+/* try to send a request to a given server. */
+/* */
+/* return: */
+/* 0 ok */
+/* 1 temporary failure */
+/* 2 other failure */
+static int
+evdns_request_transmit_to(struct request *req, struct nameserver *server) {
+ struct sockaddr_in sin;
+ int r;
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_addr.s_addr = req->ns->address;
+ sin.sin_port = req->ns->port;
+ sin.sin_family = AF_INET;
+
+ r = sendto(server->socket, req->request, req->request_len, 0,
+ (struct sockaddr*)&sin, sizeof(sin));
+ if (r < 0) {
+ int err = last_error(server->socket);
+ if (error_is_eagain(err)) return 1;
+ nameserver_failed(req->ns, strerror(err));
+ return 2;
+ } else if (r != (int)req->request_len) {
+ return 1; /* short write */
+ } else {
+ return 0;
+ }
+}
+
+/* try to send a request, updating the fields of the request */
+/* as needed */
+/* */
+/* return: */
+/* 0 ok */
+/* 1 failed */
+static int
+evdns_request_transmit(struct request *req) {
+ int retcode = 0, r;
+
+ /* if we fail to send this packet then this flag marks it */
+ /* for evdns_transmit */
+ req->transmit_me = 1;
+ if (req->trans_id == 0xffff) abort();
+
+ if (req->ns->choked) {
+ /* don't bother trying to write to a socket */
+ /* which we have had EAGAIN from */
+ return 1;
+ }
+
+ r = evdns_request_transmit_to(req, req->ns);
+ switch (r) {
+ case 1:
+ /* temp failure */
+ req->ns->choked = 1;
+ nameserver_write_waiting(req->ns, 1);
+ return 1;
+ case 2:
+ /* failed in some other way */
+ retcode = 1;
+ /* fall through */
+ default:
+ /* all ok */
+ log(EVDNS_LOG_DEBUG,
+ "Setting timeout for request %lx", (unsigned long) req);
+ if (evtimer_add(&req->timeout_event, &global_timeout) < 0) {
+ log(EVDNS_LOG_WARN,
+ "Error from libevent when adding timer for request %lx",
+ (unsigned long) req);
+ /* ???? Do more? */
+ }
+ req->tx_count++;
+ req->transmit_me = 0;
+ return retcode;
+ }
+}
+
+static void
+nameserver_probe_callback(int result, char type, int count, int ttl, void *addresses, void *arg) {
+ struct nameserver *const ns = (struct nameserver *) arg;
+ (void) type;
+ (void) count;
+ (void) ttl;
+ (void) addresses;
+
+ if (result == DNS_ERR_NONE || result == DNS_ERR_NOTEXIST) {
+ /* this is a good reply */
+ nameserver_up(ns);
+ } else nameserver_probe_failed(ns);
+}
+
+static void
+nameserver_send_probe(struct nameserver *const ns) {
+ struct request *req;
+ /* here we need to send a probe to a given nameserver */
+ /* in the hope that it is up now. */
+
+ log(EVDNS_LOG_DEBUG, "Sending probe to %s", debug_ntoa(ns->address));
+
+ req = request_new(TYPE_A, "www.google.com", DNS_QUERY_NO_SEARCH, nameserver_probe_callback, ns);
+ if (!req) return;
+ /* we force this into the inflight queue no matter what */
+ request_trans_id_set(req, transaction_id_pick());
+ req->ns = ns;
+ request_submit(req);
+}
+
+/* returns: */
+/* 0 didn't try to transmit anything */
+/* 1 tried to transmit something */
+static int
+evdns_transmit(void) {
+ char did_try_to_transmit = 0;
+
+ if (req_head) {
+ struct request *const started_at = req_head, *req = req_head;
+ /* first transmit all the requests which are currently waiting */
+ do {
+ if (req->transmit_me) {
+ did_try_to_transmit = 1;
+ evdns_request_transmit(req);
+ }
+
+ req = req->next;
+ } while (req != started_at);
+ }
+
+ return did_try_to_transmit;
+}
+
+/* exported function */
+int
+evdns_count_nameservers(void)
+{
+ const struct nameserver *server = server_head;
+ int n = 0;
+ if (!server)
+ return 0;
+ do {
+ ++n;
+ server = server->next;
+ } while (server != server_head);
+ return n;
+}
+
+/* exported function */
+int
+evdns_clear_nameservers_and_suspend(void)
+{
+ struct nameserver *server = server_head, *started_at = server_head;
+ struct request *req = req_head, *req_started_at = req_head;
+
+ if (!server)
+ return 0;
+ while (1) {
+ struct nameserver *next = server->next;
+ (void) event_del(&server->event);
+ if (evtimer_initialized(&server->timeout_event))
+ (void) evtimer_del(&server->timeout_event);
+ if (server->socket >= 0)
+ CLOSE_SOCKET(server->socket);
+ free(server);
+ if (next == started_at)
+ break;
+ server = next;
+ }
+ server_head = NULL;
+ global_good_nameservers = 0;
+
+ while (req) {
+ struct request *next = req->next;
+ req->tx_count = req->reissue_count = 0;
+ req->ns = NULL;
+ /* ???? What to do about searches? */
+ (void) evtimer_del(&req->timeout_event);
+ req->trans_id = 0;
+ req->transmit_me = 0;
+
+ global_requests_waiting++;
+ evdns_request_insert(req, &req_waiting_head);
+ /* We want to insert these suspended elements at the front of
+ * the waiting queue, since they were pending before any of
+ * the waiting entries were added. This is a circular list,
+ * so we can just shift the start back by one.*/
+ req_waiting_head = req_waiting_head->prev;
+
+ if (next == req_started_at)
+ break;
+ req = next;
+ }
+ req_head = NULL;
+ global_requests_inflight = 0;
+
+ return 0;
+}
+
+
+/* exported function */
+int
+evdns_resume(void)
+{
+ evdns_requests_pump_waiting_queue();
+ return 0;
+}
+
+static int
+_evdns_nameserver_add_impl(unsigned long int address, int port) {
+ /* first check to see if we already have this nameserver */
+
+ const struct nameserver *server = server_head, *const started_at = server_head;
+ struct nameserver *ns;
+ int err = 0;
+ if (server) {
+ do {
+ if (server->address == address) return 3;
+ server = server->next;
+ } while (server != started_at);
+ }
+
+ ns = (struct nameserver *) malloc(sizeof(struct nameserver));
+ if (!ns) return -1;
+
+ memset(ns, 0, sizeof(struct nameserver));
+
+ evtimer_set(&ns->timeout_event, nameserver_prod_callback, ns);
+
+ ns->socket = socket(PF_INET, SOCK_DGRAM, 0);
+ if (ns->socket < 0) { err = 1; goto out1; }
+ FD_CLOSEONEXEC(ns->socket);
+ evutil_make_socket_nonblocking(ns->socket);
+
+ ns->address = address;
+ ns->port = htons(port);
+ ns->state = 1;
+ event_set(&ns->event, ns->socket, EV_READ | EV_PERSIST, nameserver_ready_callback, ns);
+ if (event_add(&ns->event, NULL) < 0) {
+ err = 2;
+ goto out2;
+ }
+
+ log(EVDNS_LOG_DEBUG, "Added nameserver %s", debug_ntoa(address));
+
+ /* insert this nameserver into the list of them */
+ if (!server_head) {
+ ns->next = ns->prev = ns;
+ server_head = ns;
+ } else {
+ ns->next = server_head->next;
+ ns->prev = server_head;
+ server_head->next = ns;
+ if (server_head->prev == server_head) {
+ server_head->prev = ns;
+ }
+ }
+
+ global_good_nameservers++;
+
+ return 0;
+
+out2:
+ CLOSE_SOCKET(ns->socket);
+out1:
+ free(ns);
+ log(EVDNS_LOG_WARN, "Unable to add nameserver %s: error %d", debug_ntoa(address), err);
+ return err;
+}
+
+/* exported function */
+int
+evdns_nameserver_add(unsigned long int address) {
+ return _evdns_nameserver_add_impl(address, 53);
+}
+
+/* exported function */
+int
+evdns_nameserver_ip_add(const char *ip_as_string) {
+ struct in_addr ina;
+ int port;
+ char buf[20];
+ const char *cp;
+ cp = strchr(ip_as_string, ':');
+ if (! cp) {
+ cp = ip_as_string;
+ port = 53;
+ } else {
+ port = strtoint(cp+1);
+ if (port < 0 || port > 65535) {
+ return 4;
+ }
+ if ((cp-ip_as_string) >= (int)sizeof(buf)) {
+ return 4;
+ }
+ memcpy(buf, ip_as_string, cp-ip_as_string);
+ buf[cp-ip_as_string] = '\0';
+ cp = buf;
+ }
+ if (!inet_aton(cp, &ina)) {
+ return 4;
+ }
+ return _evdns_nameserver_add_impl(ina.s_addr, port);
+}
+
+/* insert into the tail of the queue */
+static void
+evdns_request_insert(struct request *req, struct request **head) {
+ if (!*head) {
+ *head = req;
+ req->next = req->prev = req;
+ return;
+ }
+
+ req->prev = (*head)->prev;
+ req->prev->next = req;
+ req->next = *head;
+ (*head)->prev = req;
+}
+
+static int
+string_num_dots(const char *s) {
+ int count = 0;
+ while ((s = strchr(s, '.'))) {
+ s++;
+ count++;
+ }
+ return count;
+}
+
+static struct request *
+request_new(int type, const char *name, int flags,
+ evdns_callback_type callback, void *user_ptr) {
+ const char issuing_now =
+ (global_requests_inflight < global_max_requests_inflight) ? 1 : 0;
+
+ const int name_len = strlen(name);
+ const int request_max_len = evdns_request_len(name_len);
+ const u16 trans_id = issuing_now ? transaction_id_pick() : 0xffff;
+ /* the request data is alloced in a single block with the header */
+ struct request *const req =
+ (struct request *) malloc(sizeof(struct request) + request_max_len);
+ int rlen;
+ (void) flags;
+
+ if (!req) return NULL;
+ memset(req, 0, sizeof(struct request));
+
+ evtimer_set(&req->timeout_event, evdns_request_timeout_callback, req);
+
+ /* request data lives just after the header */
+ req->request = ((u8 *) req) + sizeof(struct request);
+ /* denotes that the request data shouldn't be free()ed */
+ req->request_appended = 1;
+ rlen = evdns_request_data_build(name, name_len, trans_id,
+ type, CLASS_INET, req->request, request_max_len);
+ if (rlen < 0)
+ goto err1;
+ req->request_len = rlen;
+ req->trans_id = trans_id;
+ req->tx_count = 0;
+ req->request_type = type;
+ req->user_pointer = user_ptr;
+ req->user_callback = callback;
+ req->ns = issuing_now ? nameserver_pick() : NULL;
+ req->next = req->prev = NULL;
+
+ return req;
+err1:
+ free(req);
+ return NULL;
+}
+
+static void
+request_submit(struct request *const req) {
+ if (req->ns) {
+ /* if it has a nameserver assigned then this is going */
+ /* straight into the inflight queue */
+ evdns_request_insert(req, &req_head);
+ global_requests_inflight++;
+ evdns_request_transmit(req);
+ } else {
+ evdns_request_insert(req, &req_waiting_head);
+ global_requests_waiting++;
+ }
+}
+
+/* exported function */
+int evdns_resolve_ipv4(const char *name, int flags,
+ evdns_callback_type callback, void *ptr) {
+ log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name);
+ if (flags & DNS_QUERY_NO_SEARCH) {
+ struct request *const req =
+ request_new(TYPE_A, name, flags, callback, ptr);
+ if (req == NULL)
+ return (1);
+ request_submit(req);
+ return (0);
+ } else {
+ return (search_request_new(TYPE_A, name, flags, callback, ptr));
+ }
+}
+
+/* exported function */
+int evdns_resolve_ipv6(const char *name, int flags,
+ evdns_callback_type callback, void *ptr) {
+ log(EVDNS_LOG_DEBUG, "Resolve requested for %s", name);
+ if (flags & DNS_QUERY_NO_SEARCH) {
+ struct request *const req =
+ request_new(TYPE_AAAA, name, flags, callback, ptr);
+ if (req == NULL)
+ return (1);
+ request_submit(req);
+ return (0);
+ } else {
+ return (search_request_new(TYPE_AAAA, name, flags, callback, ptr));
+ }
+}
+
+int evdns_resolve_reverse(const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr) {
+ char buf[32];
+ struct request *req;
+ u32 a;
+ assert(in);
+ a = ntohl(in->s_addr);
+ evutil_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa",
+ (int)(u8)((a )&0xff),
+ (int)(u8)((a>>8 )&0xff),
+ (int)(u8)((a>>16)&0xff),
+ (int)(u8)((a>>24)&0xff));
+ log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf);
+ req = request_new(TYPE_PTR, buf, flags, callback, ptr);
+ if (!req) return 1;
+ request_submit(req);
+ return 0;
+}
+
+int evdns_resolve_reverse_ipv6(const struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr) {
+ /* 32 nybbles, 32 periods, "ip6.arpa", NUL. */
+ char buf[73];
+ char *cp;
+ struct request *req;
+ int i;
+ assert(in);
+ cp = buf;
+ for (i=15; i >= 0; --i) {
+ u8 byte = in->s6_addr[i];
+ *cp++ = "0123456789abcdef"[byte & 0x0f];
+ *cp++ = '.';
+ *cp++ = "0123456789abcdef"[byte >> 4];
+ *cp++ = '.';
+ }
+ assert(cp + strlen("ip6.arpa") < buf+sizeof(buf));
+ memcpy(cp, "ip6.arpa", strlen("ip6.arpa")+1);
+ log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf);
+ req = request_new(TYPE_PTR, buf, flags, callback, ptr);
+ if (!req) return 1;
+ request_submit(req);
+ return 0;
+}
+
+/*/////////////////////////////////////////////////////////////////// */
+/* Search support */
+/* */
+/* the libc resolver has support for searching a number of domains */
+/* to find a name. If nothing else then it takes the single domain */
+/* from the gethostname() call. */
+/* */
+/* It can also be configured via the domain and search options in a */
+/* resolv.conf. */
+/* */
+/* The ndots option controls how many dots it takes for the resolver */
+/* to decide that a name is non-local and so try a raw lookup first. */
+
+struct search_domain {
+ int len;
+ struct search_domain *next;
+ /* the text string is appended to this structure */
+};
+
+struct search_state {
+ int refcount;
+ int ndots;
+ int num_domains;
+ struct search_domain *head;
+};
+
+static struct search_state *global_search_state = NULL;
+
+static void
+search_state_decref(struct search_state *const state) {
+ if (!state) return;
+ state->refcount--;
+ if (!state->refcount) {
+ struct search_domain *next, *dom;
+ for (dom = state->head; dom; dom = next) {
+ next = dom->next;
+ free(dom);
+ }
+ free(state);
+ }
+}
+
+static struct search_state *
+search_state_new(void) {
+ struct search_state *state = (struct search_state *) malloc(sizeof(struct search_state));
+ if (!state) return NULL;
+ memset(state, 0, sizeof(struct search_state));
+ state->refcount = 1;
+ state->ndots = 1;
+
+ return state;
+}
+
+static void
+search_postfix_clear(void) {
+ search_state_decref(global_search_state);
+
+ global_search_state = search_state_new();
+}
+
+/* exported function */
+void
+evdns_search_clear(void) {
+ search_postfix_clear();
+}
+
+static void
+search_postfix_add(const char *domain) {
+ int domain_len;
+ struct search_domain *sdomain;
+ while (domain[0] == '.') domain++;
+ domain_len = strlen(domain);
+
+ if (!global_search_state) global_search_state = search_state_new();
+ if (!global_search_state) return;
+ global_search_state->num_domains++;
+
+ sdomain = (struct search_domain *) malloc(sizeof(struct search_domain) + domain_len);
+ if (!sdomain) return;
+ memcpy( ((u8 *) sdomain) + sizeof(struct search_domain), domain, domain_len);
+ sdomain->next = global_search_state->head;
+ sdomain->len = domain_len;
+
+ global_search_state->head = sdomain;
+}
+
+/* reverse the order of members in the postfix list. This is needed because, */
+/* when parsing resolv.conf we push elements in the wrong order */
+static void
+search_reverse(void) {
+ struct search_domain *cur, *prev = NULL, *next;
+ cur = global_search_state->head;
+ while (cur) {
+ next = cur->next;
+ cur->next = prev;
+ prev = cur;
+ cur = next;
+ }
+
+ global_search_state->head = prev;
+}
+
+/* exported function */
+void
+evdns_search_add(const char *domain) {
+ search_postfix_add(domain);
+}
+
+/* exported function */
+void
+evdns_search_ndots_set(const int ndots) {
+ if (!global_search_state) global_search_state = search_state_new();
+ if (!global_search_state) return;
+ global_search_state->ndots = ndots;
+}
+
+static void
+search_set_from_hostname(void) {
+ char hostname[HOST_NAME_MAX + 1], *domainname;
+
+ search_postfix_clear();
+ if (gethostname(hostname, sizeof(hostname))) return;
+ domainname = strchr(hostname, '.');
+ if (!domainname) return;
+ search_postfix_add(domainname);
+}
+
+/* warning: returns malloced string */
+static char *
+search_make_new(const struct search_state *const state, int n, const char *const base_name) {
+ const int base_len = strlen(base_name);
+ const char need_to_append_dot = base_name[base_len - 1] == '.' ? 0 : 1;
+ struct search_domain *dom;
+
+ for (dom = state->head; dom; dom = dom->next) {
+ if (!n--) {
+ /* this is the postfix we want */
+ /* the actual postfix string is kept at the end of the structure */
+ const u8 *const postfix = ((u8 *) dom) + sizeof(struct search_domain);
+ const int postfix_len = dom->len;
+ char *const newname = (char *) malloc(base_len + need_to_append_dot + postfix_len + 1);
+ if (!newname) return NULL;
+ memcpy(newname, base_name, base_len);
+ if (need_to_append_dot) newname[base_len] = '.';
+ memcpy(newname + base_len + need_to_append_dot, postfix, postfix_len);
+ newname[base_len + need_to_append_dot + postfix_len] = 0;
+ return newname;
+ }
+ }
+
+ /* we ran off the end of the list and still didn't find the requested string */
+ abort();
+ return NULL; /* unreachable; stops warnings in some compilers. */
+}
+
+static int
+search_request_new(int type, const char *const name, int flags, evdns_callback_type user_callback, void *user_arg) {
+ assert(type == TYPE_A || type == TYPE_AAAA);
+ if ( ((flags & DNS_QUERY_NO_SEARCH) == 0) &&
+ global_search_state &&
+ global_search_state->num_domains) {
+ /* we have some domains to search */
+ struct request *req;
+ if (string_num_dots(name) >= global_search_state->ndots) {
+ req = request_new(type, name, flags, user_callback, user_arg);
+ if (!req) return 1;
+ req->search_index = -1;
+ } else {
+ char *const new_name = search_make_new(global_search_state, 0, name);
+ if (!new_name) return 1;
+ req = request_new(type, new_name, flags, user_callback, user_arg);
+ free(new_name);
+ if (!req) return 1;
+ req->search_index = 0;
+ }
+ req->search_origname = strdup(name);
+ req->search_state = global_search_state;
+ req->search_flags = flags;
+ global_search_state->refcount++;
+ request_submit(req);
+ return 0;
+ } else {
+ struct request *const req = request_new(type, name, flags, user_callback, user_arg);
+ if (!req) return 1;
+ request_submit(req);
+ return 0;
+ }
+}
+
+/* this is called when a request has failed to find a name. We need to check */
+/* if it is part of a search and, if so, try the next name in the list */
+/* returns: */
+/* 0 another request has been submitted */
+/* 1 no more requests needed */
+static int
+search_try_next(struct request *const req) {
+ if (req->search_state) {
+ /* it is part of a search */
+ char *new_name;
+ struct request *newreq;
+ req->search_index++;
+ if (req->search_index >= req->search_state->num_domains) {
+ /* no more postfixes to try, however we may need to try */
+ /* this name without a postfix */
+ if (string_num_dots(req->search_origname) < req->search_state->ndots) {
+ /* yep, we need to try it raw */
+ newreq = request_new(req->request_type, req->search_origname, req->search_flags, req->user_callback, req->user_pointer);
+ log(EVDNS_LOG_DEBUG, "Search: trying raw query %s", req->search_origname);
+ if (newreq) {
+ request_submit(newreq);
+ return 0;
+ }
+ }
+ return 1;
+ }
+
+ new_name = search_make_new(req->search_state, req->search_index, req->search_origname);
+ if (!new_name) return 1;
+ log(EVDNS_LOG_DEBUG, "Search: now trying %s (%d)", new_name, req->search_index);
+ newreq = request_new(req->request_type, new_name, req->search_flags, req->user_callback, req->user_pointer);
+ free(new_name);
+ if (!newreq) return 1;
+ newreq->search_origname = req->search_origname;
+ req->search_origname = NULL;
+ newreq->search_state = req->search_state;
+ newreq->search_flags = req->search_flags;
+ newreq->search_index = req->search_index;
+ newreq->search_state->refcount++;
+ request_submit(newreq);
+ return 0;
+ }
+ return 1;
+}
+
+static void
+search_request_finished(struct request *const req) {
+ if (req->search_state) {
+ search_state_decref(req->search_state);
+ req->search_state = NULL;
+ }
+ if (req->search_origname) {
+ free(req->search_origname);
+ req->search_origname = NULL;
+ }
+}
+
+/*/////////////////////////////////////////////////////////////////// */
+/* Parsing resolv.conf files */
+
+static void
+evdns_resolv_set_defaults(int flags) {
+ /* if the file isn't found then we assume a local resolver */
+ if (flags & DNS_OPTION_SEARCH) search_set_from_hostname();
+ if (flags & DNS_OPTION_NAMESERVERS) evdns_nameserver_ip_add("127.0.0.1");
+}
+
+#ifndef HAVE_STRTOK_R
+static char *
+strtok_r(char *s, const char *delim, char **state) {
+ return strtok(s, delim);
+}
+#endif
+
+/* helper version of atoi which returns -1 on error */
+static int
+strtoint(const char *const str) {
+ char *endptr;
+ const int r = strtol(str, &endptr, 10);
+ if (*endptr) return -1;
+ return r;
+}
+
+/* helper version of atoi that returns -1 on error and clips to bounds. */
+static int
+strtoint_clipped(const char *const str, int min, int max)
+{
+ int r = strtoint(str);
+ if (r == -1)
+ return r;
+ else if (r<min)
+ return min;
+ else if (r>max)
+ return max;
+ else
+ return r;
+}
+
+/* exported function */
+int
+evdns_set_option(const char *option, const char *val, int flags)
+{
+ if (!strncmp(option, "ndots:", 6)) {
+ const int ndots = strtoint(val);
+ if (ndots == -1) return -1;
+ if (!(flags & DNS_OPTION_SEARCH)) return 0;
+ log(EVDNS_LOG_DEBUG, "Setting ndots to %d", ndots);
+ if (!global_search_state) global_search_state = search_state_new();
+ if (!global_search_state) return -1;
+ global_search_state->ndots = ndots;
+ } else if (!strncmp(option, "timeout:", 8)) {
+ const int timeout = strtoint(val);
+ if (timeout == -1) return -1;
+ if (!(flags & DNS_OPTION_MISC)) return 0;
+ log(EVDNS_LOG_DEBUG, "Setting timeout to %d", timeout);
+ global_timeout.tv_sec = timeout;
+ } else if (!strncmp(option, "max-timeouts:", 12)) {
+ const int maxtimeout = strtoint_clipped(val, 1, 255);
+ if (maxtimeout == -1) return -1;
+ if (!(flags & DNS_OPTION_MISC)) return 0;
+ log(EVDNS_LOG_DEBUG, "Setting maximum allowed timeouts to %d",
+ maxtimeout);
+ global_max_nameserver_timeout = maxtimeout;
+ } else if (!strncmp(option, "max-inflight:", 13)) {
+ const int maxinflight = strtoint_clipped(val, 1, 65000);
+ if (maxinflight == -1) return -1;
+ if (!(flags & DNS_OPTION_MISC)) return 0;
+ log(EVDNS_LOG_DEBUG, "Setting maximum inflight requests to %d",
+ maxinflight);
+ global_max_requests_inflight = maxinflight;
+ } else if (!strncmp(option, "attempts:", 9)) {
+ int retries = strtoint(val);
+ if (retries == -1) return -1;
+ if (retries > 255) retries = 255;
+ if (!(flags & DNS_OPTION_MISC)) return 0;
+ log(EVDNS_LOG_DEBUG, "Setting retries to %d", retries);
+ global_max_retransmits = retries;
+ }
+ return 0;
+}
+
+static void
+resolv_conf_parse_line(char *const start, int flags) {
+ char *strtok_state;
+ static const char *const delims = " \t";
+#define NEXT_TOKEN strtok_r(NULL, delims, &strtok_state)
+
+ char *const first_token = strtok_r(start, delims, &strtok_state);
+ if (!first_token) return;
+
+ if (!strcmp(first_token, "nameserver") && (flags & DNS_OPTION_NAMESERVERS)) {
+ const char *const nameserver = NEXT_TOKEN;
+ struct in_addr ina;
+
+ if (nameserver && inet_aton(nameserver, &ina)) {
+ /* address is valid */
+ evdns_nameserver_add(ina.s_addr);
+ }
+ } else if (!strcmp(first_token, "domain") && (flags & DNS_OPTION_SEARCH)) {
+ const char *const domain = NEXT_TOKEN;
+ if (domain) {
+ search_postfix_clear();
+ search_postfix_add(domain);
+ }
+ } else if (!strcmp(first_token, "search") && (flags & DNS_OPTION_SEARCH)) {
+ const char *domain;
+ search_postfix_clear();
+
+ while ((domain = NEXT_TOKEN)) {
+ search_postfix_add(domain);
+ }
+ search_reverse();
+ } else if (!strcmp(first_token, "options")) {
+ const char *option;
+ while ((option = NEXT_TOKEN)) {
+ const char *val = strchr(option, ':');
+ evdns_set_option(option, val ? val+1 : "", flags);
+ }
+ }
+#undef NEXT_TOKEN
+}
+
+/* exported function */
+/* returns: */
+/* 0 no errors */
+/* 1 failed to open file */
+/* 2 failed to stat file */
+/* 3 file too large */
+/* 4 out of memory */
+/* 5 short read from file */
+int
+evdns_resolv_conf_parse(int flags, const char *const filename) {
+ struct stat st;
+ int fd, n, r;
+ u8 *resolv;
+ char *start;
+ int err = 0;
+
+ log(EVDNS_LOG_DEBUG, "Parsing resolv.conf file %s", filename);
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ evdns_resolv_set_defaults(flags);
+ return 1;
+ }
+
+ if (fstat(fd, &st)) { err = 2; goto out1; }
+ if (!st.st_size) {
+ evdns_resolv_set_defaults(flags);
+ err = (flags & DNS_OPTION_NAMESERVERS) ? 6 : 0;
+ goto out1;
+ }
+ if (st.st_size > 65535) { err = 3; goto out1; } /* no resolv.conf should be any bigger */
+
+ resolv = (u8 *) malloc((size_t)st.st_size + 1);
+ if (!resolv) { err = 4; goto out1; }
+
+ n = 0;
+ while ((r = read(fd, resolv+n, (size_t)st.st_size-n)) > 0) {
+ n += r;
+ if (n == st.st_size)
+ break;
+ assert(n < st.st_size);
+ }
+ if (r < 0) { err = 5; goto out2; }
+ resolv[n] = 0; /* we malloced an extra byte; this should be fine. */
+
+ start = (char *) resolv;
+ for (;;) {
+ char *const newline = strchr(start, '\n');
+ if (!newline) {
+ resolv_conf_parse_line(start, flags);
+ break;
+ } else {
+ *newline = 0;
+ resolv_conf_parse_line(start, flags);
+ start = newline + 1;
+ }
+ }
+
+ if (!server_head && (flags & DNS_OPTION_NAMESERVERS)) {
+ /* no nameservers were configured. */
+ evdns_nameserver_ip_add("127.0.0.1");
+ err = 6;
+ }
+ if (flags & DNS_OPTION_SEARCH && (!global_search_state || global_search_state->num_domains == 0)) {
+ search_set_from_hostname();
+ }
+
+out2:
+ free(resolv);
+out1:
+ close(fd);
+ return err;
+}
+
+#ifdef WIN32
+/* Add multiple nameservers from a space-or-comma-separated list. */
+static int
+evdns_nameserver_ip_add_line(const char *ips) {
+ const char *addr;
+ char *buf;
+ int r;
+ while (*ips) {
+ while (ISSPACE(*ips) || *ips == ',' || *ips == '\t')
+ ++ips;
+ addr = ips;
+ while (ISDIGIT(*ips) || *ips == '.' || *ips == ':')
+ ++ips;
+ buf = malloc(ips-addr+1);
+ if (!buf) return 4;
+ memcpy(buf, addr, ips-addr);
+ buf[ips-addr] = '\0';
+ r = evdns_nameserver_ip_add(buf);
+ free(buf);
+ if (r) return r;
+ }
+ return 0;
+}
+
+typedef DWORD(WINAPI *GetNetworkParams_fn_t)(FIXED_INFO *, DWORD*);
+
+/* Use the windows GetNetworkParams interface in iphlpapi.dll to */
+/* figure out what our nameservers are. */
+static int
+load_nameservers_with_getnetworkparams(void)
+{
+ /* Based on MSDN examples and inspection of c-ares code. */
+ FIXED_INFO *fixed;
+ HMODULE handle = 0;
+ ULONG size = sizeof(FIXED_INFO);
+ void *buf = NULL;
+ int status = 0, r, added_any;
+ IP_ADDR_STRING *ns;
+ GetNetworkParams_fn_t fn;
+
+ if (!(handle = LoadLibraryA("iphlpapi.dll"))) {
+ log(EVDNS_LOG_WARN, "Could not open iphlpapi.dll");
+ status = -1;
+ goto done;
+ }
+ if (!(fn = (GetNetworkParams_fn_t) GetProcAddress(handle, "GetNetworkParams"))) {
+ log(EVDNS_LOG_WARN, "Could not get address of function.");
+ status = -1;
+ goto done;
+ }
+
+ buf = malloc(size);
+ if (!buf) { status = 4; goto done; }
+ fixed = buf;
+ r = fn(fixed, &size);
+ if (r != ERROR_SUCCESS && r != ERROR_BUFFER_OVERFLOW) {
+ status = -1;
+ goto done;
+ }
+ if (r != ERROR_SUCCESS) {
+ free(buf);
+ buf = malloc(size);
+ if (!buf) { status = 4; goto done; }
+ fixed = buf;
+ r = fn(fixed, &size);
+ if (r != ERROR_SUCCESS) {
+ log(EVDNS_LOG_DEBUG, "fn() failed.");
+ status = -1;
+ goto done;
+ }
+ }
+
+ assert(fixed);
+ added_any = 0;
+ ns = &(fixed->DnsServerList);
+ while (ns) {
+ r = evdns_nameserver_ip_add_line(ns->IpAddress.String);
+ if (r) {
+ log(EVDNS_LOG_DEBUG,"Could not add nameserver %s to list,error: %d",
+ (ns->IpAddress.String),(int)GetLastError());
+ status = r;
+ goto done;
+ } else {
+ log(EVDNS_LOG_DEBUG,"Succesfully added %s as nameserver",ns->IpAddress.String);
+ }
+
+ added_any++;
+ ns = ns->Next;
+ }
+
+ if (!added_any) {
+ log(EVDNS_LOG_DEBUG, "No nameservers added.");
+ status = -1;
+ }
+
+ done:
+ if (buf)
+ free(buf);
+ if (handle)
+ FreeLibrary(handle);
+ return status;
+}
+
+static int
+config_nameserver_from_reg_key(HKEY key, const char *subkey)
+{
+ char *buf;
+ DWORD bufsz = 0, type = 0;
+ int status = 0;
+
+ if (RegQueryValueExA(key, subkey, 0, &type, NULL, &bufsz)
+ != ERROR_MORE_DATA)
+ return -1;
+ if (!(buf = malloc(bufsz)))
+ return -1;
+
+ if (RegQueryValueExA(key, subkey, 0, &type, (LPBYTE)buf, &bufsz)
+ == ERROR_SUCCESS && bufsz > 1) {
+ status = evdns_nameserver_ip_add_line(buf);
+ }
+
+ free(buf);
+ return status;
+}
+
+#define SERVICES_KEY "System\\CurrentControlSet\\Services\\"
+#define WIN_NS_9X_KEY SERVICES_KEY "VxD\\MSTCP"
+#define WIN_NS_NT_KEY SERVICES_KEY "Tcpip\\Parameters"
+
+static int
+load_nameservers_from_registry(void)
+{
+ int found = 0;
+ int r;
+#define TRY(k, name) \
+ if (!found && config_nameserver_from_reg_key(k,name) == 0) { \
+ log(EVDNS_LOG_DEBUG,"Found nameservers in %s/%s",#k,name); \
+ found = 1; \
+ } else if (!found) { \
+ log(EVDNS_LOG_DEBUG,"Didn't find nameservers in %s/%s", \
+ #k,#name); \
+ }
+
+ if (((int)GetVersion()) > 0) { /* NT */
+ HKEY nt_key = 0, interfaces_key = 0;
+
+ if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0,
+ KEY_READ, &nt_key) != ERROR_SUCCESS) {
+ log(EVDNS_LOG_DEBUG,"Couldn't open nt key, %d",(int)GetLastError());
+ return -1;
+ }
+ r = RegOpenKeyExA(nt_key, "Interfaces", 0,
+ KEY_QUERY_VALUE|KEY_ENUMERATE_SUB_KEYS,
+ &interfaces_key);
+ if (r != ERROR_SUCCESS) {
+ log(EVDNS_LOG_DEBUG,"Couldn't open interfaces key, %d",(int)GetLastError());
+ return -1;
+ }
+ TRY(nt_key, "NameServer");
+ TRY(nt_key, "DhcpNameServer");
+ TRY(interfaces_key, "NameServer");
+ TRY(interfaces_key, "DhcpNameServer");
+ RegCloseKey(interfaces_key);
+ RegCloseKey(nt_key);
+ } else {
+ HKEY win_key = 0;
+ if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, WIN_NS_9X_KEY, 0,
+ KEY_READ, &win_key) != ERROR_SUCCESS) {
+ log(EVDNS_LOG_DEBUG, "Couldn't open registry key, %d", (int)GetLastError());
+ return -1;
+ }
+ TRY(win_key, "NameServer");
+ RegCloseKey(win_key);
+ }
+
+ if (found == 0) {
+ log(EVDNS_LOG_WARN,"Didn't find any nameservers.");
+ }
+
+ return found ? 0 : -1;
+#undef TRY
+}
+
+int
+evdns_config_windows_nameservers(void)
+{
+ if (load_nameservers_with_getnetworkparams() == 0)
+ return 0;
+ return load_nameservers_from_registry();
+}
+#endif
+
+int
+evdns_init(void)
+{
+ int res = 0;
+#ifdef WIN32
+ res = evdns_config_windows_nameservers();
+#else
+ res = evdns_resolv_conf_parse(DNS_OPTIONS_ALL, "/etc/resolv.conf");
+#endif
+
+ return (res);
+}
+
+const char *
+evdns_err_to_string(int err)
+{
+ switch (err) {
+ case DNS_ERR_NONE: return "no error";
+ case DNS_ERR_FORMAT: return "misformatted query";
+ case DNS_ERR_SERVERFAILED: return "server failed";
+ case DNS_ERR_NOTEXIST: return "name does not exist";
+ case DNS_ERR_NOTIMPL: return "query not implemented";
+ case DNS_ERR_REFUSED: return "refused";
+
+ case DNS_ERR_TRUNCATED: return "reply truncated or ill-formed";
+ case DNS_ERR_UNKNOWN: return "unknown";
+ case DNS_ERR_TIMEOUT: return "request timed out";
+ case DNS_ERR_SHUTDOWN: return "dns subsystem shut down";
+ default: return "[Unknown error code]";
+ }
+}
+
+void
+evdns_shutdown(int fail_requests)
+{
+ struct nameserver *server, *server_next;
+ struct search_domain *dom, *dom_next;
+
+ while (req_head) {
+ if (fail_requests)
+ reply_callback(req_head, 0, DNS_ERR_SHUTDOWN, NULL);
+ request_finished(req_head, &req_head);
+ }
+ while (req_waiting_head) {
+ if (fail_requests)
+ reply_callback(req_waiting_head, 0, DNS_ERR_SHUTDOWN, NULL);
+ request_finished(req_waiting_head, &req_waiting_head);
+ }
+ global_requests_inflight = global_requests_waiting = 0;
+
+ for (server = server_head; server; server = server_next) {
+ server_next = server->next;
+ if (server->socket >= 0)
+ CLOSE_SOCKET(server->socket);
+ (void) event_del(&server->event);
+ if (server->state == 0)
+ (void) event_del(&server->timeout_event);
+ free(server);
+ if (server_next == server_head)
+ break;
+ }
+ server_head = NULL;
+ global_good_nameservers = 0;
+
+ if (global_search_state) {
+ for (dom = global_search_state->head; dom; dom = dom_next) {
+ dom_next = dom->next;
+ free(dom);
+ }
+ free(global_search_state);
+ global_search_state = NULL;
+ }
+ evdns_log_fn = NULL;
+}
+
+#ifdef EVDNS_MAIN
+void
+main_callback(int result, char type, int count, int ttl,
+ void *addrs, void *orig) {
+ char *n = (char*)orig;
+ int i;
+ for (i = 0; i < count; ++i) {
+ if (type == DNS_IPv4_A) {
+ printf("%s: %s\n", n, debug_ntoa(((u32*)addrs)[i]));
+ } else if (type == DNS_PTR) {
+ printf("%s: %s\n", n, ((char**)addrs)[i]);
+ }
+ }
+ if (!count) {
+ printf("%s: No answer (%d)\n", n, result);
+ }
+ fflush(stdout);
+}
+void
+evdns_server_callback(struct evdns_server_request *req, void *data)
+{
+ int i, r;
+ (void)data;
+ /* dummy; give 192.168.11.11 as an answer for all A questions,
+ * give foo.bar.example.com as an answer for all PTR questions. */
+ for (i = 0; i < req->nquestions; ++i) {
+ u32 ans = htonl(0xc0a80b0bUL);
+ if (req->questions[i]->type == EVDNS_TYPE_A &&
+ req->questions[i]->dns_question_class == EVDNS_CLASS_INET) {
+ printf(" -- replying for %s (A)\n", req->questions[i]->name);
+ r = evdns_server_request_add_a_reply(req, req->questions[i]->name,
+ 1, &ans, 10);
+ if (r<0)
+ printf("eeep, didn't work.\n");
+ } else if (req->questions[i]->type == EVDNS_TYPE_PTR &&
+ req->questions[i]->dns_question_class == EVDNS_CLASS_INET) {
+ printf(" -- replying for %s (PTR)\n", req->questions[i]->name);
+ r = evdns_server_request_add_ptr_reply(req, NULL, req->questions[i]->name,
+ "foo.bar.example.com", 10);
+ } else {
+ printf(" -- skipping %s [%d %d]\n", req->questions[i]->name,
+ req->questions[i]->type, req->questions[i]->dns_question_class);
+ }
+ }
+
+ r = evdns_request_respond(req, 0);
+ if (r<0)
+ printf("eeek, couldn't send reply.\n");
+}
+
+void
+logfn(int is_warn, const char *msg) {
+ (void) is_warn;
+ fprintf(stderr, "%s\n", msg);
+}
+int
+main(int c, char **v) {
+ int idx;
+ int reverse = 0, verbose = 1, servertest = 0;
+ if (c<2) {
+ fprintf(stderr, "syntax: %s [-x] [-v] hostname\n", v[0]);
+ fprintf(stderr, "syntax: %s [-servertest]\n", v[0]);
+ return 1;
+ }
+ idx = 1;
+ while (idx < c && v[idx][0] == '-') {
+ if (!strcmp(v[idx], "-x"))
+ reverse = 1;
+ else if (!strcmp(v[idx], "-v"))
+ verbose = 1;
+ else if (!strcmp(v[idx], "-servertest"))
+ servertest = 1;
+ else
+ fprintf(stderr, "Unknown option %s\n", v[idx]);
+ ++idx;
+ }
+ event_init();
+ if (verbose)
+ evdns_set_log_fn(logfn);
+ evdns_resolv_conf_parse(DNS_OPTION_NAMESERVERS, "/etc/resolv.conf");
+ if (servertest) {
+ int sock;
+ struct sockaddr_in my_addr;
+ sock = socket(PF_INET, SOCK_DGRAM, 0);
+ evutil_make_socket_nonblocking(sock);
+ my_addr.sin_family = AF_INET;
+ my_addr.sin_port = htons(10053);
+ my_addr.sin_addr.s_addr = INADDR_ANY;
+ if (bind(sock, (struct sockaddr*)&my_addr, sizeof(my_addr))<0) {
+ perror("bind");
+ exit(1);
+ }
+ evdns_add_server_port(sock, 0, evdns_server_callback, NULL);
+ }
+ for (; idx < c; ++idx) {
+ if (reverse) {
+ struct in_addr addr;
+ if (!inet_aton(v[idx], &addr)) {
+ fprintf(stderr, "Skipping non-IP %s\n", v[idx]);
+ continue;
+ }
+ fprintf(stderr, "resolving %s...\n",v[idx]);
+ evdns_resolve_reverse(&addr, 0, main_callback, v[idx]);
+ } else {
+ fprintf(stderr, "resolving (fwd) %s...\n",v[idx]);
+ evdns_resolve_ipv4(v[idx], 0, main_callback, v[idx]);
+ }
+ }
+ fflush(stdout);
+ event_dispatch();
+ return 0;
+}
+#endif
diff --git a/chromium/base/third_party/libevent/evdns.h b/chromium/base/third_party/libevent/evdns.h
new file mode 100644
index 00000000000..fca4ac380bf
--- /dev/null
+++ b/chromium/base/third_party/libevent/evdns.h
@@ -0,0 +1,528 @@
+/*
+ * Copyright (c) 2006 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * The original DNS code is due to Adam Langley with heavy
+ * modifications by Nick Mathewson. Adam put his DNS software in the
+ * public domain. You can find his original copyright below. Please,
+ * aware that the code as part of libevent is governed by the 3-clause
+ * BSD license above.
+ *
+ * This software is Public Domain. To view a copy of the public domain dedication,
+ * visit http://creativecommons.org/licenses/publicdomain/ or send a letter to
+ * Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
+ *
+ * I ask and expect, but do not require, that all derivative works contain an
+ * attribution similar to:
+ * Parts developed by Adam Langley <agl@imperialviolet.org>
+ *
+ * You may wish to replace the word "Parts" with something else depending on
+ * the amount of original code.
+ *
+ * (Derivative works does not include programs which link against, run or include
+ * the source verbatim in their source distributions)
+ */
+
+/** @file evdns.h
+ *
+ * Welcome, gentle reader
+ *
+ * Async DNS lookups are really a whole lot harder than they should be,
+ * mostly stemming from the fact that the libc resolver has never been
+ * very good at them. Before you use this library you should see if libc
+ * can do the job for you with the modern async call getaddrinfo_a
+ * (see http://www.imperialviolet.org/page25.html#e498). Otherwise,
+ * please continue.
+ *
+ * This code is based on libevent and you must call event_init before
+ * any of the APIs in this file. You must also seed the OpenSSL random
+ * source if you are using OpenSSL for ids (see below).
+ *
+ * This library is designed to be included and shipped with your source
+ * code. You statically link with it. You should also test for the
+ * existence of strtok_r and define HAVE_STRTOK_R if you have it.
+ *
+ * The DNS protocol requires a good source of id numbers and these
+ * numbers should be unpredictable for spoofing reasons. There are
+ * three methods for generating them here and you must define exactly
+ * one of them. In increasing order of preference:
+ *
+ * DNS_USE_GETTIMEOFDAY_FOR_ID:
+ * Using the bottom 16 bits of the usec result from gettimeofday. This
+ * is a pretty poor solution but should work anywhere.
+ * DNS_USE_CPU_CLOCK_FOR_ID:
+ * Using the bottom 16 bits of the nsec result from the CPU's time
+ * counter. This is better, but may not work everywhere. Requires
+ * POSIX realtime support and you'll need to link against -lrt on
+ * glibc systems at least.
+ * DNS_USE_OPENSSL_FOR_ID:
+ * Uses the OpenSSL RAND_bytes call to generate the data. You must
+ * have seeded the pool before making any calls to this library.
+ *
+ * The library keeps track of the state of nameservers and will avoid
+ * them when they go down. Otherwise it will round robin between them.
+ *
+ * Quick start guide:
+ * #include "evdns.h"
+ * void callback(int result, char type, int count, int ttl,
+ * void *addresses, void *arg);
+ * evdns_resolv_conf_parse(DNS_OPTIONS_ALL, "/etc/resolv.conf");
+ * evdns_resolve("www.hostname.com", 0, callback, NULL);
+ *
+ * When the lookup is complete the callback function is called. The
+ * first argument will be one of the DNS_ERR_* defines in evdns.h.
+ * Hopefully it will be DNS_ERR_NONE, in which case type will be
+ * DNS_IPv4_A, count will be the number of IP addresses, ttl is the time
+ * which the data can be cached for (in seconds), addresses will point
+ * to an array of uint32_t's and arg will be whatever you passed to
+ * evdns_resolve.
+ *
+ * Searching:
+ *
+ * In order for this library to be a good replacement for glibc's resolver it
+ * supports searching. This involves setting a list of default domains, in
+ * which names will be queried for. The number of dots in the query name
+ * determines the order in which this list is used.
+ *
+ * Searching appears to be a single lookup from the point of view of the API,
+ * although many DNS queries may be generated from a single call to
+ * evdns_resolve. Searching can also drastically slow down the resolution
+ * of names.
+ *
+ * To disable searching:
+ * 1. Never set it up. If you never call evdns_resolv_conf_parse or
+ * evdns_search_add then no searching will occur.
+ *
+ * 2. If you do call evdns_resolv_conf_parse then don't pass
+ * DNS_OPTION_SEARCH (or DNS_OPTIONS_ALL, which implies it).
+ *
+ * 3. When calling evdns_resolve, pass the DNS_QUERY_NO_SEARCH flag.
+ *
+ * The order of searches depends on the number of dots in the name. If the
+ * number is greater than the ndots setting then the names is first tried
+ * globally. Otherwise each search domain is appended in turn.
+ *
+ * The ndots setting can either be set from a resolv.conf, or by calling
+ * evdns_search_ndots_set.
+ *
+ * For example, with ndots set to 1 (the default) and a search domain list of
+ * ["myhome.net"]:
+ * Query: www
+ * Order: www.myhome.net, www.
+ *
+ * Query: www.abc
+ * Order: www.abc., www.abc.myhome.net
+ *
+ * Internals:
+ *
+ * Requests are kept in two queues. The first is the inflight queue. In
+ * this queue requests have an allocated transaction id and nameserver.
+ * They will soon be transmitted if they haven't already been.
+ *
+ * The second is the waiting queue. The size of the inflight ring is
+ * limited and all other requests wait in waiting queue for space. This
+ * bounds the number of concurrent requests so that we don't flood the
+ * nameserver. Several algorithms require a full walk of the inflight
+ * queue and so bounding its size keeps thing going nicely under huge
+ * (many thousands of requests) loads.
+ *
+ * If a nameserver loses too many requests it is considered down and we
+ * try not to use it. After a while we send a probe to that nameserver
+ * (a lookup for google.com) and, if it replies, we consider it working
+ * again. If the nameserver fails a probe we wait longer to try again
+ * with the next probe.
+ */
+
+#ifndef EVENTDNS_H
+#define EVENTDNS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* For integer types. */
+#include "evutil.h"
+
+/** Error codes 0-5 are as described in RFC 1035. */
+#define DNS_ERR_NONE 0
+/** The name server was unable to interpret the query */
+#define DNS_ERR_FORMAT 1
+/** The name server was unable to process this query due to a problem with the
+ * name server */
+#define DNS_ERR_SERVERFAILED 2
+/** The domain name does not exist */
+#define DNS_ERR_NOTEXIST 3
+/** The name server does not support the requested kind of query */
+#define DNS_ERR_NOTIMPL 4
+/** The name server refuses to reform the specified operation for policy
+ * reasons */
+#define DNS_ERR_REFUSED 5
+/** The reply was truncated or ill-formated */
+#define DNS_ERR_TRUNCATED 65
+/** An unknown error occurred */
+#define DNS_ERR_UNKNOWN 66
+/** Communication with the server timed out */
+#define DNS_ERR_TIMEOUT 67
+/** The request was canceled because the DNS subsystem was shut down. */
+#define DNS_ERR_SHUTDOWN 68
+
+#define DNS_IPv4_A 1
+#define DNS_PTR 2
+#define DNS_IPv6_AAAA 3
+
+#define DNS_QUERY_NO_SEARCH 1
+
+#define DNS_OPTION_SEARCH 1
+#define DNS_OPTION_NAMESERVERS 2
+#define DNS_OPTION_MISC 4
+#define DNS_OPTIONS_ALL 7
+
+/**
+ * The callback that contains the results from a lookup.
+ * - type is either DNS_IPv4_A or DNS_PTR or DNS_IPv6_AAAA
+ * - count contains the number of addresses of form type
+ * - ttl is the number of seconds the resolution may be cached for.
+ * - addresses needs to be cast according to type
+ */
+typedef void (*evdns_callback_type) (int result, char type, int count, int ttl, void *addresses, void *arg);
+
+/**
+ Initialize the asynchronous DNS library.
+
+ This function initializes support for non-blocking name resolution by
+ calling evdns_resolv_conf_parse() on UNIX and
+ evdns_config_windows_nameservers() on Windows.
+
+ @return 0 if successful, or -1 if an error occurred
+ @see evdns_shutdown()
+ */
+int evdns_init(void);
+
+
+/**
+ Shut down the asynchronous DNS resolver and terminate all active requests.
+
+ If the 'fail_requests' option is enabled, all active requests will return
+ an empty result with the error flag set to DNS_ERR_SHUTDOWN. Otherwise,
+ the requests will be silently discarded.
+
+ @param fail_requests if zero, active requests will be aborted; if non-zero,
+ active requests will return DNS_ERR_SHUTDOWN.
+ @see evdns_init()
+ */
+void evdns_shutdown(int fail_requests);
+
+
+/**
+ Convert a DNS error code to a string.
+
+ @param err the DNS error code
+ @return a string containing an explanation of the error code
+*/
+const char *evdns_err_to_string(int err);
+
+
+/**
+ Add a nameserver.
+
+ The address should be an IPv4 address in network byte order.
+ The type of address is chosen so that it matches in_addr.s_addr.
+
+ @param address an IP address in network byte order
+ @return 0 if successful, or -1 if an error occurred
+ @see evdns_nameserver_ip_add()
+ */
+int evdns_nameserver_add(unsigned long int address);
+
+
+/**
+ Get the number of configured nameservers.
+
+ This returns the number of configured nameservers (not necessarily the
+ number of running nameservers). This is useful for double-checking
+ whether our calls to the various nameserver configuration functions
+ have been successful.
+
+ @return the number of configured nameservers
+ @see evdns_nameserver_add()
+ */
+int evdns_count_nameservers(void);
+
+
+/**
+ Remove all configured nameservers, and suspend all pending resolves.
+
+ Resolves will not necessarily be re-attempted until evdns_resume() is called.
+
+ @return 0 if successful, or -1 if an error occurred
+ @see evdns_resume()
+ */
+int evdns_clear_nameservers_and_suspend(void);
+
+
+/**
+ Resume normal operation and continue any suspended resolve requests.
+
+ Re-attempt resolves left in limbo after an earlier call to
+ evdns_clear_nameservers_and_suspend().
+
+ @return 0 if successful, or -1 if an error occurred
+ @see evdns_clear_nameservers_and_suspend()
+ */
+int evdns_resume(void);
+
+
+/**
+ Add a nameserver.
+
+ This wraps the evdns_nameserver_add() function by parsing a string as an IP
+ address and adds it as a nameserver.
+
+ @return 0 if successful, or -1 if an error occurred
+ @see evdns_nameserver_add()
+ */
+int evdns_nameserver_ip_add(const char *ip_as_string);
+
+
+/**
+ Lookup an A record for a given name.
+
+ @param name a DNS hostname
+ @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query.
+ @param callback a callback function to invoke when the request is completed
+ @param ptr an argument to pass to the callback function
+ @return 0 if successful, or -1 if an error occurred
+ @see evdns_resolve_ipv6(), evdns_resolve_reverse(), evdns_resolve_reverse_ipv6()
+ */
+int evdns_resolve_ipv4(const char *name, int flags, evdns_callback_type callback, void *ptr);
+
+
+/**
+ Lookup an AAAA record for a given name.
+
+ @param name a DNS hostname
+ @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query.
+ @param callback a callback function to invoke when the request is completed
+ @param ptr an argument to pass to the callback function
+ @return 0 if successful, or -1 if an error occurred
+ @see evdns_resolve_ipv4(), evdns_resolve_reverse(), evdns_resolve_reverse_ipv6()
+ */
+int evdns_resolve_ipv6(const char *name, int flags, evdns_callback_type callback, void *ptr);
+
+struct in_addr;
+struct in6_addr;
+
+/**
+ Lookup a PTR record for a given IP address.
+
+ @param in an IPv4 address
+ @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query.
+ @param callback a callback function to invoke when the request is completed
+ @param ptr an argument to pass to the callback function
+ @return 0 if successful, or -1 if an error occurred
+ @see evdns_resolve_reverse_ipv6()
+ */
+int evdns_resolve_reverse(const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr);
+
+
+/**
+ Lookup a PTR record for a given IPv6 address.
+
+ @param in an IPv6 address
+ @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query.
+ @param callback a callback function to invoke when the request is completed
+ @param ptr an argument to pass to the callback function
+ @return 0 if successful, or -1 if an error occurred
+ @see evdns_resolve_reverse_ipv6()
+ */
+int evdns_resolve_reverse_ipv6(const struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr);
+
+
+/**
+ Set the value of a configuration option.
+
+ The currently available configuration options are:
+
+ ndots, timeout, max-timeouts, max-inflight, and attempts
+
+ @param option the name of the configuration option to be modified
+ @param val the value to be set
+ @param flags either 0 | DNS_OPTION_SEARCH | DNS_OPTION_MISC
+ @return 0 if successful, or -1 if an error occurred
+ */
+int evdns_set_option(const char *option, const char *val, int flags);
+
+
+/**
+ Parse a resolv.conf file.
+
+ The 'flags' parameter determines what information is parsed from the
+ resolv.conf file. See the man page for resolv.conf for the format of this
+ file.
+
+ The following directives are not parsed from the file: sortlist, rotate,
+ no-check-names, inet6, debug.
+
+ If this function encounters an error, the possible return values are: 1 =
+ failed to open file, 2 = failed to stat file, 3 = file too large, 4 = out of
+ memory, 5 = short read from file, 6 = no nameservers listed in the file
+
+ @param flags any of DNS_OPTION_NAMESERVERS|DNS_OPTION_SEARCH|DNS_OPTION_MISC|
+ DNS_OPTIONS_ALL
+ @param filename the path to the resolv.conf file
+ @return 0 if successful, or various positive error codes if an error
+ occurred (see above)
+ @see resolv.conf(3), evdns_config_windows_nameservers()
+ */
+int evdns_resolv_conf_parse(int flags, const char *const filename);
+
+
+/**
+ Obtain nameserver information using the Windows API.
+
+ Attempt to configure a set of nameservers based on platform settings on
+ a win32 host. Preferentially tries to use GetNetworkParams; if that fails,
+ looks in the registry.
+
+ @return 0 if successful, or -1 if an error occurred
+ @see evdns_resolv_conf_parse()
+ */
+#ifdef WIN32
+int evdns_config_windows_nameservers(void);
+#endif
+
+
+/**
+ Clear the list of search domains.
+ */
+void evdns_search_clear(void);
+
+
+/**
+ Add a domain to the list of search domains
+
+ @param domain the domain to be added to the search list
+ */
+void evdns_search_add(const char *domain);
+
+
+/**
+ Set the 'ndots' parameter for searches.
+
+ Sets the number of dots which, when found in a name, causes
+ the first query to be without any search domain.
+
+ @param ndots the new ndots parameter
+ */
+void evdns_search_ndots_set(const int ndots);
+
+/**
+ A callback that is invoked when a log message is generated
+
+ @param is_warning indicates if the log message is a 'warning'
+ @param msg the content of the log message
+ */
+typedef void (*evdns_debug_log_fn_type)(int is_warning, const char *msg);
+
+
+/**
+ Set the callback function to handle log messages.
+
+ @param fn the callback to be invoked when a log message is generated
+ */
+void evdns_set_log_fn(evdns_debug_log_fn_type fn);
+
+/**
+ Set a callback that will be invoked to generate transaction IDs. By
+ default, we pick transaction IDs based on the current clock time.
+
+ @param fn the new callback, or NULL to use the default.
+ */
+void evdns_set_transaction_id_fn(ev_uint16_t (*fn)(void));
+
+#define DNS_NO_SEARCH 1
+
+/*
+ * Structures and functions used to implement a DNS server.
+ */
+
+struct evdns_server_request {
+ int flags;
+ int nquestions;
+ struct evdns_server_question **questions;
+};
+struct evdns_server_question {
+ int type;
+#ifdef __cplusplus
+ int dns_question_class;
+#else
+ /* You should refer to this field as "dns_question_class". The
+ * name "class" works in C for backward compatibility, and will be
+ * removed in a future version. (1.5 or later). */
+ int class;
+#define dns_question_class class
+#endif
+ char name[1];
+};
+typedef void (*evdns_request_callback_fn_type)(struct evdns_server_request *, void *);
+#define EVDNS_ANSWER_SECTION 0
+#define EVDNS_AUTHORITY_SECTION 1
+#define EVDNS_ADDITIONAL_SECTION 2
+
+#define EVDNS_TYPE_A 1
+#define EVDNS_TYPE_NS 2
+#define EVDNS_TYPE_CNAME 5
+#define EVDNS_TYPE_SOA 6
+#define EVDNS_TYPE_PTR 12
+#define EVDNS_TYPE_MX 15
+#define EVDNS_TYPE_TXT 16
+#define EVDNS_TYPE_AAAA 28
+
+#define EVDNS_QTYPE_AXFR 252
+#define EVDNS_QTYPE_ALL 255
+
+#define EVDNS_CLASS_INET 1
+
+struct evdns_server_port *evdns_add_server_port(int socket, int is_tcp, evdns_request_callback_fn_type callback, void *user_data);
+void evdns_close_server_port(struct evdns_server_port *port);
+
+int evdns_server_request_add_reply(struct evdns_server_request *req, int section, const char *name, int type, int dns_class, int ttl, int datalen, int is_name, const char *data);
+int evdns_server_request_add_a_reply(struct evdns_server_request *req, const char *name, int n, void *addrs, int ttl);
+int evdns_server_request_add_aaaa_reply(struct evdns_server_request *req, const char *name, int n, void *addrs, int ttl);
+int evdns_server_request_add_ptr_reply(struct evdns_server_request *req, struct in_addr *in, const char *inaddr_name, const char *hostname, int ttl);
+int evdns_server_request_add_cname_reply(struct evdns_server_request *req, const char *name, const char *cname, int ttl);
+
+int evdns_server_request_respond(struct evdns_server_request *req, int err);
+int evdns_server_request_drop(struct evdns_server_request *req);
+struct sockaddr;
+int evdns_server_request_get_requesting_addr(struct evdns_server_request *_req, struct sockaddr *sa, int addr_len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !EVENTDNS_H */
diff --git a/chromium/base/third_party/libevent/event-config.h b/chromium/base/third_party/libevent/event-config.h
new file mode 100644
index 00000000000..3b1eaa0bba1
--- /dev/null
+++ b/chromium/base/third_party/libevent/event-config.h
@@ -0,0 +1,22 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is Chromium-specific, and brings in the appropriate
+// event-config.h depending on your platform.
+
+#if defined(__native_client_nonsfi__)
+#include "base/third_party/libevent/nacl_nonsfi/event-config.h"
+#elif defined(__APPLE__)
+#include "base/third_party/libevent/mac/event-config.h"
+#elif defined(ANDROID)
+#include "base/third_party/libevent/android/event-config.h"
+#elif defined(__linux__)
+#include "base/third_party/libevent/linux/event-config.h"
+#elif defined(__FreeBSD__)
+#include "base/third_party/libevent/freebsd/event-config.h"
+#elif defined(__sun)
+#include "base/third_party/libevent/solaris/event-config.h"
+#else
+#error generate event-config.h for your platform
+#endif
diff --git a/chromium/base/third_party/libevent/event-internal.h b/chromium/base/third_party/libevent/event-internal.h
new file mode 100644
index 00000000000..b7f00402be5
--- /dev/null
+++ b/chromium/base/third_party/libevent/event-internal.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2000-2004 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _EVENT_INTERNAL_H_
+#define _EVENT_INTERNAL_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "config.h"
+#include "min_heap.h"
+#include "evsignal.h"
+
+struct eventop {
+ const char *name;
+ void *(*init)(struct event_base *);
+ int (*add)(void *, struct event *);
+ int (*del)(void *, struct event *);
+ int (*dispatch)(struct event_base *, void *, struct timeval *);
+ void (*dealloc)(struct event_base *, void *);
+ /* set if we need to reinitialize the event base */
+ int need_reinit;
+};
+
+struct event_base {
+ const struct eventop *evsel;
+ void *evbase;
+ int event_count; /* counts number of total events */
+ int event_count_active; /* counts number of active events */
+
+ int event_gotterm; /* Set to terminate loop */
+ int event_break; /* Set to terminate loop immediately */
+
+ /* active event management */
+ struct event_list **activequeues;
+ int nactivequeues;
+
+ /* signal handling info */
+ struct evsignal_info sig;
+
+ struct event_list eventqueue;
+ struct timeval event_tv;
+
+ struct min_heap timeheap;
+
+ struct timeval tv_cache;
+};
+
+/* Internal use only: Functions that might be missing from <sys/queue.h> */
+#ifndef HAVE_TAILQFOREACH
+#define TAILQ_FIRST(head) ((head)->tqh_first)
+#define TAILQ_END(head) NULL
+#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
+#define TAILQ_FOREACH(var, head, field) \
+ for((var) = TAILQ_FIRST(head); \
+ (var) != TAILQ_END(head); \
+ (var) = TAILQ_NEXT(var, field))
+#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
+ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
+ (elm)->field.tqe_next = (listelm); \
+ *(listelm)->field.tqe_prev = (elm); \
+ (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
+} while (0)
+#endif /* TAILQ_FOREACH */
+
+int _evsignal_set_handler(struct event_base *base, int evsignal,
+ void (*fn)(int));
+int _evsignal_restore_handler(struct event_base *base, int evsignal);
+
+/* defined in evutil.c */
+const char *evutil_getenv(const char *varname);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _EVENT_INTERNAL_H_ */
diff --git a/chromium/base/third_party/libevent/event.3 b/chromium/base/third_party/libevent/event.3
new file mode 100644
index 00000000000..5b33ec64a93
--- /dev/null
+++ b/chromium/base/third_party/libevent/event.3
@@ -0,0 +1,624 @@
+.\" $OpenBSD: event.3,v 1.4 2002/07/12 18:50:48 provos Exp $
+.\"
+.\" Copyright (c) 2000 Artur Grabowski <art@openbsd.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+.\" AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+.\" THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+.\" EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+.\" PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+.\" OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd August 8, 2000
+.Dt EVENT 3
+.Os
+.Sh NAME
+.Nm event_init ,
+.Nm event_dispatch ,
+.Nm event_loop ,
+.Nm event_loopexit ,
+.Nm event_loopbreak ,
+.Nm event_set ,
+.Nm event_base_dispatch ,
+.Nm event_base_loop ,
+.Nm event_base_loopexit ,
+.Nm event_base_loopbreak ,
+.Nm event_base_set ,
+.Nm event_base_free ,
+.Nm event_add ,
+.Nm event_del ,
+.Nm event_once ,
+.Nm event_base_once ,
+.Nm event_pending ,
+.Nm event_initialized ,
+.Nm event_priority_init ,
+.Nm event_priority_set ,
+.Nm evtimer_set ,
+.Nm evtimer_add ,
+.Nm evtimer_del ,
+.Nm evtimer_pending ,
+.Nm evtimer_initialized ,
+.Nm signal_set ,
+.Nm signal_add ,
+.Nm signal_del ,
+.Nm signal_pending ,
+.Nm signal_initialized ,
+.Nm bufferevent_new ,
+.Nm bufferevent_free ,
+.Nm bufferevent_write ,
+.Nm bufferevent_write_buffer ,
+.Nm bufferevent_read ,
+.Nm bufferevent_enable ,
+.Nm bufferevent_disable ,
+.Nm bufferevent_settimeout ,
+.Nm bufferevent_base_set ,
+.Nm evbuffer_new ,
+.Nm evbuffer_free ,
+.Nm evbuffer_add ,
+.Nm evbuffer_add_buffer ,
+.Nm evbuffer_add_printf ,
+.Nm evbuffer_add_vprintf ,
+.Nm evbuffer_drain ,
+.Nm evbuffer_write ,
+.Nm evbuffer_read ,
+.Nm evbuffer_find ,
+.Nm evbuffer_readline ,
+.Nm evhttp_new ,
+.Nm evhttp_bind_socket ,
+.Nm evhttp_free
+.Nd execute a function when a specific event occurs
+.Sh SYNOPSIS
+.Fd #include <sys/time.h>
+.Fd #include <event.h>
+.Ft "struct event_base *"
+.Fn "event_init" "void"
+.Ft int
+.Fn "event_dispatch" "void"
+.Ft int
+.Fn "event_loop" "int flags"
+.Ft int
+.Fn "event_loopexit" "struct timeval *tv"
+.Ft int
+.Fn "event_loopbreak" "void"
+.Ft void
+.Fn "event_set" "struct event *ev" "int fd" "short event" "void (*fn)(int, short, void *)" "void *arg"
+.Ft int
+.Fn "event_base_dispatch" "struct event_base *base"
+.Ft int
+.Fn "event_base_loop" "struct event_base *base" "int flags"
+.Ft int
+.Fn "event_base_loopexit" "struct event_base *base" "struct timeval *tv"
+.Ft int
+.Fn "event_base_loopbreak" "struct event_base *base"
+.Ft int
+.Fn "event_base_set" "struct event_base *base" "struct event *"
+.Ft void
+.Fn "event_base_free" "struct event_base *base"
+.Ft int
+.Fn "event_add" "struct event *ev" "struct timeval *tv"
+.Ft int
+.Fn "event_del" "struct event *ev"
+.Ft int
+.Fn "event_once" "int fd" "short event" "void (*fn)(int, short, void *)" "void *arg" "struct timeval *tv"
+.Ft int
+.Fn "event_base_once" "struct event_base *base" "int fd" "short event" "void (*fn)(int, short, void *)" "void *arg" "struct timeval *tv"
+.Ft int
+.Fn "event_pending" "struct event *ev" "short event" "struct timeval *tv"
+.Ft int
+.Fn "event_initialized" "struct event *ev"
+.Ft int
+.Fn "event_priority_init" "int npriorities"
+.Ft int
+.Fn "event_priority_set" "struct event *ev" "int priority"
+.Ft void
+.Fn "evtimer_set" "struct event *ev" "void (*fn)(int, short, void *)" "void *arg"
+.Ft void
+.Fn "evtimer_add" "struct event *ev" "struct timeval *"
+.Ft void
+.Fn "evtimer_del" "struct event *ev"
+.Ft int
+.Fn "evtimer_pending" "struct event *ev" "struct timeval *tv"
+.Ft int
+.Fn "evtimer_initialized" "struct event *ev"
+.Ft void
+.Fn "signal_set" "struct event *ev" "int signal" "void (*fn)(int, short, void *)" "void *arg"
+.Ft void
+.Fn "signal_add" "struct event *ev" "struct timeval *"
+.Ft void
+.Fn "signal_del" "struct event *ev"
+.Ft int
+.Fn "signal_pending" "struct event *ev" "struct timeval *tv"
+.Ft int
+.Fn "signal_initialized" "struct event *ev"
+.Ft "struct bufferevent *"
+.Fn "bufferevent_new" "int fd" "evbuffercb readcb" "evbuffercb writecb" "everrorcb" "void *cbarg"
+.Ft void
+.Fn "bufferevent_free" "struct bufferevent *bufev"
+.Ft int
+.Fn "bufferevent_write" "struct bufferevent *bufev" "void *data" "size_t size"
+.Ft int
+.Fn "bufferevent_write_buffer" "struct bufferevent *bufev" "struct evbuffer *buf"
+.Ft size_t
+.Fn "bufferevent_read" "struct bufferevent *bufev" "void *data" "size_t size"
+.Ft int
+.Fn "bufferevent_enable" "struct bufferevent *bufev" "short event"
+.Ft int
+.Fn "bufferevent_disable" "struct bufferevent *bufev" "short event"
+.Ft void
+.Fn "bufferevent_settimeout" "struct bufferevent *bufev" "int timeout_read" "int timeout_write"
+.Ft int
+.Fn "bufferevent_base_set" "struct event_base *base" "struct bufferevent *bufev"
+.Ft "struct evbuffer *"
+.Fn "evbuffer_new" "void"
+.Ft void
+.Fn "evbuffer_free" "struct evbuffer *buf"
+.Ft int
+.Fn "evbuffer_add" "struct evbuffer *buf" "const void *data" "size_t size"
+.Ft int
+.Fn "evbuffer_add_buffer" "struct evbuffer *dst" "struct evbuffer *src"
+.Ft int
+.Fn "evbuffer_add_printf" "struct evbuffer *buf" "const char *fmt" "..."
+.Ft int
+.Fn "evbuffer_add_vprintf" "struct evbuffer *buf" "const char *fmt" "va_list ap"
+.Ft void
+.Fn "evbuffer_drain" "struct evbuffer *buf" "size_t size"
+.Ft int
+.Fn "evbuffer_write" "struct evbuffer *buf" "int fd"
+.Ft int
+.Fn "evbuffer_read" "struct evbuffer *buf" "int fd" "int size"
+.Ft "u_char *"
+.Fn "evbuffer_find" "struct evbuffer *buf" "const u_char *data" "size_t size"
+.Ft "char *"
+.Fn "evbuffer_readline" "struct evbuffer *buf"
+.Ft "struct evhttp *"
+.Fn "evhttp_new" "struct event_base *base"
+.Ft int
+.Fn "evhttp_bind_socket" "struct evhttp *http" "const char *address" "u_short port"
+.Ft "void"
+.Fn "evhttp_free" "struct evhttp *http"
+.Ft int
+.Fa (*event_sigcb)(void) ;
+.Ft volatile sig_atomic_t
+.Fa event_gotsig ;
+.Sh DESCRIPTION
+The
+.Nm event
+API provides a mechanism to execute a function when a specific event
+on a file descriptor occurs or after a given time has passed.
+.Pp
+The
+.Nm event
+API needs to be initialized with
+.Fn event_init
+before it can be used.
+.Pp
+In order to process events, an application needs to call
+.Fn event_dispatch .
+This function only returns on error, and should replace the event core
+of the application program.
+.Pp
+The function
+.Fn event_set
+prepares the event structure
+.Fa ev
+to be used in future calls to
+.Fn event_add
+and
+.Fn event_del .
+The event will be prepared to call the function specified by the
+.Fa fn
+argument with an
+.Fa int
+argument indicating the file descriptor, a
+.Fa short
+argument indicating the type of event, and a
+.Fa void *
+argument given in the
+.Fa arg
+argument.
+The
+.Fa fd
+indicates the file descriptor that should be monitored for events.
+The events can be either
+.Va EV_READ ,
+.Va EV_WRITE ,
+or both,
+indicating that an application can read or write from the file descriptor
+respectively without blocking.
+.Pp
+The function
+.Fa fn
+will be called with the file descriptor that triggered the event and
+the type of event which will be either
+.Va EV_TIMEOUT ,
+.Va EV_SIGNAL ,
+.Va EV_READ ,
+or
+.Va EV_WRITE .
+Additionally, an event which has registered interest in more than one of the
+preceeding events, via bitwise-OR to
+.Fn event_set ,
+can provide its callback function with a bitwise-OR of more than one triggered
+event.
+The additional flag
+.Va EV_PERSIST
+makes an
+.Fn event_add
+persistent until
+.Fn event_del
+has been called.
+.Pp
+Once initialized, the
+.Fa ev
+structure can be used repeatedly with
+.Fn event_add
+and
+.Fn event_del
+and does not need to be reinitialized unless the function called and/or
+the argument to it are to be changed.
+However, when an
+.Fa ev
+structure has been added to libevent using
+.Fn event_add
+the structure must persist until the event occurs (assuming
+.Fa EV_PERSIST
+is not set) or is removed
+using
+.Fn event_del .
+You may not reuse the same
+.Fa ev
+structure for multiple monitored descriptors; each descriptor
+needs its own
+.Fa ev .
+.Pp
+The function
+.Fn event_add
+schedules the execution of the
+.Fa ev
+event when the event specified in
+.Fn event_set
+occurs or in at least the time specified in the
+.Fa tv .
+If
+.Fa tv
+is
+.Dv NULL ,
+no timeout occurs and the function will only be called
+if a matching event occurs on the file descriptor.
+The event in the
+.Fa ev
+argument must be already initialized by
+.Fn event_set
+and may not be used in calls to
+.Fn event_set
+until it has timed out or been removed with
+.Fn event_del .
+If the event in the
+.Fa ev
+argument already has a scheduled timeout, the old timeout will be
+replaced by the new one.
+.Pp
+The function
+.Fn event_del
+will cancel the event in the argument
+.Fa ev .
+If the event has already executed or has never been added
+the call will have no effect.
+.Pp
+The functions
+.Fn evtimer_set ,
+.Fn evtimer_add ,
+.Fn evtimer_del ,
+.Fn evtimer_initialized ,
+and
+.Fn evtimer_pending
+are abbreviations for common situations where only a timeout is required.
+The file descriptor passed will be \-1, and the event type will be
+.Va EV_TIMEOUT .
+.Pp
+The functions
+.Fn signal_set ,
+.Fn signal_add ,
+.Fn signal_del ,
+.Fn signal_initialized ,
+and
+.Fn signal_pending
+are abbreviations.
+The event type will be a persistent
+.Va EV_SIGNAL .
+That means
+.Fn signal_set
+adds
+.Va EV_PERSIST .
+.Pp
+In order to avoid races in signal handlers, the
+.Nm event
+API provides two variables:
+.Va event_sigcb
+and
+.Va event_gotsig .
+A signal handler
+sets
+.Va event_gotsig
+to indicate that a signal has been received.
+The application sets
+.Va event_sigcb
+to a callback function.
+After the signal handler sets
+.Va event_gotsig ,
+.Nm event_dispatch
+will execute the callback function to process received signals.
+The callback returns 1 when no events are registered any more.
+It can return \-1 to indicate an error to the
+.Nm event
+library, causing
+.Fn event_dispatch
+to terminate with
+.Va errno
+set to
+.Er EINTR .
+.Pp
+The function
+.Fn event_once
+is similar to
+.Fn event_set .
+However, it schedules a callback to be called exactly once and does not
+require the caller to prepare an
+.Fa event
+structure.
+This function supports
+.Fa EV_TIMEOUT ,
+.Fa EV_READ ,
+and
+.Fa EV_WRITE .
+.Pp
+The
+.Fn event_pending
+function can be used to check if the event specified by
+.Fa event
+is pending to run.
+If
+.Va EV_TIMEOUT
+was specified and
+.Fa tv
+is not
+.Dv NULL ,
+the expiration time of the event will be returned in
+.Fa tv .
+.Pp
+The
+.Fn event_initialized
+macro can be used to check if an event has been initialized.
+.Pp
+The
+.Nm event_loop
+function provides an interface for single pass execution of pending
+events.
+The flags
+.Va EVLOOP_ONCE
+and
+.Va EVLOOP_NONBLOCK
+are recognized.
+The
+.Nm event_loopexit
+function exits from the event loop. The next
+.Fn event_loop
+iteration after the
+given timer expires will complete normally (handling all queued events) then
+exit without blocking for events again. Subsequent invocations of
+.Fn event_loop
+will proceed normally.
+The
+.Nm event_loopbreak
+function exits from the event loop immediately.
+.Fn event_loop
+will abort after the next event is completed;
+.Fn event_loopbreak
+is typically invoked from this event's callback. This behavior is analogous
+to the "break;" statement. Subsequent invocations of
+.Fn event_loop
+will proceed normally.
+.Pp
+It is the responsibility of the caller to provide these functions with
+pre-allocated event structures.
+.Pp
+.Sh EVENT PRIORITIES
+By default
+.Nm libevent
+schedules all active events with the same priority.
+However, sometimes it is desirable to process some events with a higher
+priority than others.
+For that reason,
+.Nm libevent
+supports strict priority queues.
+Active events with a lower priority are always processed before events
+with a higher priority.
+.Pp
+The number of different priorities can be set initially with the
+.Fn event_priority_init
+function.
+This function should be called before the first call to
+.Fn event_dispatch .
+The
+.Fn event_priority_set
+function can be used to assign a priority to an event.
+By default,
+.Nm libevent
+assigns the middle priority to all events unless their priority
+is explicitly set.
+.Sh THREAD SAFE EVENTS
+.Nm Libevent
+has experimental support for thread-safe events.
+When initializing the library via
+.Fn event_init ,
+an event base is returned.
+This event base can be used in conjunction with calls to
+.Fn event_base_set ,
+.Fn event_base_dispatch ,
+.Fn event_base_loop ,
+.Fn event_base_loopexit ,
+.Fn bufferevent_base_set
+and
+.Fn event_base_free .
+.Fn event_base_set
+should be called after preparing an event with
+.Fn event_set ,
+as
+.Fn event_set
+assigns the provided event to the most recently created event base.
+.Fn bufferevent_base_set
+should be called after preparing a bufferevent with
+.Fn bufferevent_new .
+.Fn event_base_free
+should be used to free memory associated with the event base
+when it is no longer needed.
+.Sh BUFFERED EVENTS
+.Nm libevent
+provides an abstraction on top of the regular event callbacks.
+This abstraction is called a
+.Va "buffered event" .
+A buffered event provides input and output buffers that get filled
+and drained automatically.
+The user of a buffered event no longer deals directly with the IO,
+but instead is reading from input and writing to output buffers.
+.Pp
+A new bufferevent is created by
+.Fn bufferevent_new .
+The parameter
+.Fa fd
+specifies the file descriptor from which data is read and written to.
+This file descriptor is not allowed to be a
+.Xr pipe 2 .
+The next three parameters are callbacks.
+The read and write callback have the following form:
+.Ft void
+.Fn "(*cb)" "struct bufferevent *bufev" "void *arg" .
+The error callback has the following form:
+.Ft void
+.Fn "(*cb)" "struct bufferevent *bufev" "short what" "void *arg" .
+The argument is specified by the fourth parameter
+.Fa "cbarg" .
+A
+.Fa bufferevent struct
+pointer is returned on success, NULL on error.
+Both the read and the write callback may be NULL.
+The error callback has to be always provided.
+.Pp
+Once initialized, the bufferevent structure can be used repeatedly with
+bufferevent_enable() and bufferevent_disable().
+The flags parameter can be a combination of
+.Va EV_READ
+and
+.Va EV_WRITE .
+When read enabled the bufferevent will try to read from the file
+descriptor and call the read callback.
+The write callback is executed
+whenever the output buffer is drained below the write low watermark,
+which is
+.Va 0
+by default.
+.Pp
+The
+.Fn bufferevent_write
+function can be used to write data to the file descriptor.
+The data is appended to the output buffer and written to the descriptor
+automatically as it becomes available for writing.
+.Fn bufferevent_write
+returns 0 on success or \-1 on failure.
+The
+.Fn bufferevent_read
+function is used to read data from the input buffer,
+returning the amount of data read.
+.Pp
+If multiple bases are in use, bufferevent_base_set() must be called before
+enabling the bufferevent for the first time.
+.Sh NON-BLOCKING HTTP SUPPORT
+.Nm libevent
+provides a very thin HTTP layer that can be used both to host an HTTP
+server and also to make HTTP requests.
+An HTTP server can be created by calling
+.Fn evhttp_new .
+It can be bound to any port and address with the
+.Fn evhttp_bind_socket
+function.
+When the HTTP server is no longer used, it can be freed via
+.Fn evhttp_free .
+.Pp
+To be notified of HTTP requests, a user needs to register callbacks with the
+HTTP server.
+This can be done by calling
+.Fn evhttp_set_cb .
+The second argument is the URI for which a callback is being registered.
+The corresponding callback will receive an
+.Va struct evhttp_request
+object that contains all information about the request.
+.Pp
+This section does not document all the possible function calls; please
+check
+.Va event.h
+for the public interfaces.
+.Sh ADDITIONAL NOTES
+It is possible to disable support for
+.Va epoll , kqueue , devpoll , poll
+or
+.Va select
+by setting the environment variable
+.Va EVENT_NOEPOLL , EVENT_NOKQUEUE , EVENT_NODEVPOLL , EVENT_NOPOLL
+or
+.Va EVENT_NOSELECT ,
+respectively.
+By setting the environment variable
+.Va EVENT_SHOW_METHOD ,
+.Nm libevent
+displays the kernel notification method that it uses.
+.Sh RETURN VALUES
+Upon successful completion
+.Fn event_add
+and
+.Fn event_del
+return 0.
+Otherwise, \-1 is returned and the global variable errno is
+set to indicate the error.
+.Sh SEE ALSO
+.Xr kqueue 2 ,
+.Xr poll 2 ,
+.Xr select 2 ,
+.Xr evdns 3 ,
+.Xr timeout 9
+.Sh HISTORY
+The
+.Nm event
+API manpage is based on the
+.Xr timeout 9
+manpage by Artur Grabowski.
+The port of
+.Nm libevent
+to Windows is due to Michael A. Davis.
+Support for real-time signals is due to Taral.
+.Sh AUTHORS
+The
+.Nm event
+library was written by Niels Provos.
+.Sh BUGS
+This documentation is neither complete nor authoritative.
+If you are in doubt about the usage of this API then
+check the source code to find out how it works, write
+up the missing piece of documentation and send it to
+me for inclusion in this man page.
diff --git a/chromium/base/third_party/libevent/event.c b/chromium/base/third_party/libevent/event.c
new file mode 100644
index 00000000000..36b1c51bcad
--- /dev/null
+++ b/chromium/base/third_party/libevent/event.c
@@ -0,0 +1,1017 @@
+/*
+ * Copyright (c) 2000-2004 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#endif
+#include <sys/types.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <sys/_libevent_time.h>
+#endif
+#include <sys/queue.h>
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef WIN32
+#include <unistd.h>
+#endif
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <assert.h>
+#include <time.h>
+
+#include "event.h"
+#include "event-internal.h"
+#include "evutil.h"
+#include "log.h"
+
+#ifdef HAVE_EVENT_PORTS
+extern const struct eventop evportops;
+#endif
+#ifdef HAVE_SELECT
+extern const struct eventop selectops;
+#endif
+#ifdef HAVE_POLL
+extern const struct eventop pollops;
+#endif
+#ifdef HAVE_EPOLL
+extern const struct eventop epollops;
+#endif
+#ifdef HAVE_WORKING_KQUEUE
+extern const struct eventop kqops;
+#endif
+#ifdef HAVE_DEVPOLL
+extern const struct eventop devpollops;
+#endif
+#ifdef WIN32
+extern const struct eventop win32ops;
+#endif
+
+/* In order of preference */
+static const struct eventop *eventops[] = {
+#ifdef HAVE_EVENT_PORTS
+ &evportops,
+#endif
+#ifdef HAVE_WORKING_KQUEUE
+ &kqops,
+#endif
+#ifdef HAVE_EPOLL
+ &epollops,
+#endif
+#ifdef HAVE_DEVPOLL
+ &devpollops,
+#endif
+#ifdef HAVE_POLL
+ &pollops,
+#endif
+#ifdef HAVE_SELECT
+ &selectops,
+#endif
+#ifdef WIN32
+ &win32ops,
+#endif
+ NULL
+};
+
+/* Global state */
+struct event_base *current_base = NULL;
+extern struct event_base *evsignal_base;
+static int use_monotonic = 1;
+
+/* Handle signals - This is a deprecated interface */
+int (*event_sigcb)(void); /* Signal callback when gotsig is set */
+volatile sig_atomic_t event_gotsig; /* Set in signal handler */
+
+/* Prototypes */
+static void event_queue_insert(struct event_base *, struct event *, int);
+static void event_queue_remove(struct event_base *, struct event *, int);
+static int event_haveevents(struct event_base *);
+
+static void event_process_active(struct event_base *);
+
+static int timeout_next(struct event_base *, struct timeval **);
+static void timeout_process(struct event_base *);
+static void timeout_correct(struct event_base *, struct timeval *);
+
+static int
+gettime(struct event_base *base, struct timeval *tp)
+{
+ if (base->tv_cache.tv_sec) {
+ *tp = base->tv_cache;
+ return (0);
+ }
+
+#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
+ struct timespec ts;
+
+ if (use_monotonic &&
+ clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
+ tp->tv_sec = ts.tv_sec;
+ tp->tv_usec = ts.tv_nsec / 1000;
+ return (0);
+ }
+#endif
+
+ use_monotonic = 0;
+
+ return (evutil_gettimeofday(tp, NULL));
+}
+
+struct event_base *
+event_init(void)
+{
+ struct event_base *base = event_base_new();
+
+ if (base != NULL)
+ current_base = base;
+
+ return (base);
+}
+
+struct event_base *
+event_base_new(void)
+{
+ int i;
+ struct event_base *base;
+
+ if ((base = calloc(1, sizeof(struct event_base))) == NULL)
+ event_err(1, "%s: calloc", __func__);
+
+ event_sigcb = NULL;
+ event_gotsig = 0;
+
+ gettime(base, &base->event_tv);
+
+ min_heap_ctor(&base->timeheap);
+ TAILQ_INIT(&base->eventqueue);
+ base->sig.ev_signal_pair[0] = -1;
+ base->sig.ev_signal_pair[1] = -1;
+
+ base->evbase = NULL;
+ for (i = 0; eventops[i] && !base->evbase; i++) {
+ base->evsel = eventops[i];
+
+ base->evbase = base->evsel->init(base);
+ }
+
+ if (base->evbase == NULL)
+ event_errx(1, "%s: no event mechanism available", __func__);
+
+ if (evutil_getenv("EVENT_SHOW_METHOD"))
+ event_msgx("libevent using: %s\n",
+ base->evsel->name);
+
+ /* allocate a single active event queue */
+ event_base_priority_init(base, 1);
+
+ return (base);
+}
+
+void
+event_base_free(struct event_base *base)
+{
+ int i, n_deleted=0;
+ struct event *ev;
+
+ if (base == NULL && current_base)
+ base = current_base;
+ if (base == current_base)
+ current_base = NULL;
+
+ /* XXX(niels) - check for internal events first */
+ assert(base);
+ /* Delete all non-internal events. */
+ for (ev = TAILQ_FIRST(&base->eventqueue); ev; ) {
+ struct event *next = TAILQ_NEXT(ev, ev_next);
+ if (!(ev->ev_flags & EVLIST_INTERNAL)) {
+ event_del(ev);
+ ++n_deleted;
+ }
+ ev = next;
+ }
+ while ((ev = min_heap_top(&base->timeheap)) != NULL) {
+ event_del(ev);
+ ++n_deleted;
+ }
+
+ for (i = 0; i < base->nactivequeues; ++i) {
+ for (ev = TAILQ_FIRST(base->activequeues[i]); ev; ) {
+ struct event *next = TAILQ_NEXT(ev, ev_active_next);
+ if (!(ev->ev_flags & EVLIST_INTERNAL)) {
+ event_del(ev);
+ ++n_deleted;
+ }
+ ev = next;
+ }
+ }
+
+ if (n_deleted)
+ event_debug(("%s: %d events were still set in base",
+ __func__, n_deleted));
+
+ if (base->evsel->dealloc != NULL)
+ base->evsel->dealloc(base, base->evbase);
+
+ for (i = 0; i < base->nactivequeues; ++i)
+ assert(TAILQ_EMPTY(base->activequeues[i]));
+
+ assert(min_heap_empty(&base->timeheap));
+ min_heap_dtor(&base->timeheap);
+
+ for (i = 0; i < base->nactivequeues; ++i)
+ free(base->activequeues[i]);
+ free(base->activequeues);
+
+ assert(TAILQ_EMPTY(&base->eventqueue));
+
+ free(base);
+}
+
+/* reinitialized the event base after a fork */
+int
+event_reinit(struct event_base *base)
+{
+ const struct eventop *evsel = base->evsel;
+ void *evbase = base->evbase;
+ int res = 0;
+ struct event *ev;
+
+#if 0
+ /* Right now, reinit always takes effect, since even if the
+ backend doesn't require it, the signal socketpair code does.
+ */
+ /* check if this event mechanism requires reinit */
+ if (!evsel->need_reinit)
+ return (0);
+#endif
+
+ /* prevent internal delete */
+ if (base->sig.ev_signal_added) {
+ /* we cannot call event_del here because the base has
+ * not been reinitialized yet. */
+ event_queue_remove(base, &base->sig.ev_signal,
+ EVLIST_INSERTED);
+ if (base->sig.ev_signal.ev_flags & EVLIST_ACTIVE)
+ event_queue_remove(base, &base->sig.ev_signal,
+ EVLIST_ACTIVE);
+ base->sig.ev_signal_added = 0;
+ }
+
+ if (base->evsel->dealloc != NULL)
+ base->evsel->dealloc(base, base->evbase);
+ evbase = base->evbase = evsel->init(base);
+ if (base->evbase == NULL)
+ event_errx(1, "%s: could not reinitialize event mechanism",
+ __func__);
+
+ TAILQ_FOREACH(ev, &base->eventqueue, ev_next) {
+ if (evsel->add(evbase, ev) == -1)
+ res = -1;
+ }
+
+ return (res);
+}
+
+int
+event_priority_init(int npriorities)
+{
+ return event_base_priority_init(current_base, npriorities);
+}
+
+int
+event_base_priority_init(struct event_base *base, int npriorities)
+{
+ int i;
+
+ if (base->event_count_active)
+ return (-1);
+
+ if (npriorities == base->nactivequeues)
+ return (0);
+
+ if (base->nactivequeues) {
+ for (i = 0; i < base->nactivequeues; ++i) {
+ free(base->activequeues[i]);
+ }
+ free(base->activequeues);
+ }
+
+ /* Allocate our priority queues */
+ base->nactivequeues = npriorities;
+ base->activequeues = (struct event_list **)
+ calloc(base->nactivequeues, sizeof(struct event_list *));
+ if (base->activequeues == NULL)
+ event_err(1, "%s: calloc", __func__);
+
+ for (i = 0; i < base->nactivequeues; ++i) {
+ base->activequeues[i] = malloc(sizeof(struct event_list));
+ if (base->activequeues[i] == NULL)
+ event_err(1, "%s: malloc", __func__);
+ TAILQ_INIT(base->activequeues[i]);
+ }
+
+ return (0);
+}
+
+int
+event_haveevents(struct event_base *base)
+{
+ return (base->event_count > 0);
+}
+
+/*
+ * Active events are stored in priority queues. Lower priorities are always
+ * process before higher priorities. Low priority events can starve high
+ * priority ones.
+ */
+
+static void
+event_process_active(struct event_base *base)
+{
+ struct event *ev;
+ struct event_list *activeq = NULL;
+ int i;
+ short ncalls;
+
+ for (i = 0; i < base->nactivequeues; ++i) {
+ if (TAILQ_FIRST(base->activequeues[i]) != NULL) {
+ activeq = base->activequeues[i];
+ break;
+ }
+ }
+
+ assert(activeq != NULL);
+
+ for (ev = TAILQ_FIRST(activeq); ev; ev = TAILQ_FIRST(activeq)) {
+ if (ev->ev_events & EV_PERSIST)
+ event_queue_remove(base, ev, EVLIST_ACTIVE);
+ else
+ event_del(ev);
+
+ /* Allows deletes to work */
+ ncalls = ev->ev_ncalls;
+ ev->ev_pncalls = &ncalls;
+ while (ncalls) {
+ ncalls--;
+ ev->ev_ncalls = ncalls;
+ (*ev->ev_callback)((int)ev->ev_fd, ev->ev_res, ev->ev_arg);
+ if (event_gotsig || base->event_break)
+ return;
+ }
+ }
+}
+
+/*
+ * Wait continously for events. We exit only if no events are left.
+ */
+
+int
+event_dispatch(void)
+{
+ return (event_loop(0));
+}
+
+int
+event_base_dispatch(struct event_base *event_base)
+{
+ return (event_base_loop(event_base, 0));
+}
+
+const char *
+event_base_get_method(struct event_base *base)
+{
+ assert(base);
+ return (base->evsel->name);
+}
+
+static void
+event_loopexit_cb(int fd, short what, void *arg)
+{
+ struct event_base *base = arg;
+ base->event_gotterm = 1;
+}
+
+/* not thread safe */
+int
+event_loopexit(const struct timeval *tv)
+{
+ return (event_once(-1, EV_TIMEOUT, event_loopexit_cb,
+ current_base, tv));
+}
+
+int
+event_base_loopexit(struct event_base *event_base, const struct timeval *tv)
+{
+ return (event_base_once(event_base, -1, EV_TIMEOUT, event_loopexit_cb,
+ event_base, tv));
+}
+
+/* not thread safe */
+int
+event_loopbreak(void)
+{
+ return (event_base_loopbreak(current_base));
+}
+
+int
+event_base_loopbreak(struct event_base *event_base)
+{
+ if (event_base == NULL)
+ return (-1);
+
+ event_base->event_break = 1;
+ return (0);
+}
+
+
+
+/* not thread safe */
+
+int
+event_loop(int flags)
+{
+ return event_base_loop(current_base, flags);
+}
+
+int
+event_base_loop(struct event_base *base, int flags)
+{
+ const struct eventop *evsel = base->evsel;
+ void *evbase = base->evbase;
+ struct timeval tv;
+ struct timeval *tv_p;
+ int res, done;
+
+ /* clear time cache */
+ base->tv_cache.tv_sec = 0;
+
+ if (base->sig.ev_signal_added)
+ evsignal_base = base;
+ done = 0;
+ while (!done) {
+ /* Terminate the loop if we have been asked to */
+ if (base->event_gotterm) {
+ base->event_gotterm = 0;
+ break;
+ }
+
+ if (base->event_break) {
+ base->event_break = 0;
+ break;
+ }
+
+ /* You cannot use this interface for multi-threaded apps */
+ while (event_gotsig) {
+ event_gotsig = 0;
+ if (event_sigcb) {
+ res = (*event_sigcb)();
+ if (res == -1) {
+ errno = EINTR;
+ return (-1);
+ }
+ }
+ }
+
+ timeout_correct(base, &tv);
+
+ tv_p = &tv;
+ if (!base->event_count_active && !(flags & EVLOOP_NONBLOCK)) {
+ timeout_next(base, &tv_p);
+ } else {
+ /*
+ * if we have active events, we just poll new events
+ * without waiting.
+ */
+ evutil_timerclear(&tv);
+ }
+
+ /* If we have no events, we just exit */
+ if (!event_haveevents(base)) {
+ event_debug(("%s: no events registered.", __func__));
+ return (1);
+ }
+
+ /* update last old time */
+ gettime(base, &base->event_tv);
+
+ /* clear time cache */
+ base->tv_cache.tv_sec = 0;
+
+ res = evsel->dispatch(base, evbase, tv_p);
+
+ if (res == -1)
+ return (-1);
+ gettime(base, &base->tv_cache);
+
+ timeout_process(base);
+
+ if (base->event_count_active) {
+ event_process_active(base);
+ if (!base->event_count_active && (flags & EVLOOP_ONCE))
+ done = 1;
+ } else if (flags & EVLOOP_NONBLOCK)
+ done = 1;
+ }
+
+ /* clear time cache */
+ base->tv_cache.tv_sec = 0;
+
+ event_debug(("%s: asked to terminate loop.", __func__));
+ return (0);
+}
+
+/* Sets up an event for processing once */
+
+struct event_once {
+ struct event ev;
+
+ void (*cb)(int, short, void *);
+ void *arg;
+};
+
+/* One-time callback, it deletes itself */
+
+static void
+event_once_cb(int fd, short events, void *arg)
+{
+ struct event_once *eonce = arg;
+
+ (*eonce->cb)(fd, events, eonce->arg);
+ free(eonce);
+}
+
+/* not threadsafe, event scheduled once. */
+int
+event_once(int fd, short events,
+ void (*callback)(int, short, void *), void *arg, const struct timeval *tv)
+{
+ return event_base_once(current_base, fd, events, callback, arg, tv);
+}
+
+/* Schedules an event once */
+int
+event_base_once(struct event_base *base, int fd, short events,
+ void (*callback)(int, short, void *), void *arg, const struct timeval *tv)
+{
+ struct event_once *eonce;
+ struct timeval etv;
+ int res;
+
+ /* We cannot support signals that just fire once */
+ if (events & EV_SIGNAL)
+ return (-1);
+
+ if ((eonce = calloc(1, sizeof(struct event_once))) == NULL)
+ return (-1);
+
+ eonce->cb = callback;
+ eonce->arg = arg;
+
+ if (events == EV_TIMEOUT) {
+ if (tv == NULL) {
+ evutil_timerclear(&etv);
+ tv = &etv;
+ }
+
+ evtimer_set(&eonce->ev, event_once_cb, eonce);
+ } else if (events & (EV_READ|EV_WRITE)) {
+ events &= EV_READ|EV_WRITE;
+
+ event_set(&eonce->ev, fd, events, event_once_cb, eonce);
+ } else {
+ /* Bad event combination */
+ free(eonce);
+ return (-1);
+ }
+
+ res = event_base_set(base, &eonce->ev);
+ if (res == 0)
+ res = event_add(&eonce->ev, tv);
+ if (res != 0) {
+ free(eonce);
+ return (res);
+ }
+
+ return (0);
+}
+
+void
+event_set(struct event *ev, int fd, short events,
+ void (*callback)(int, short, void *), void *arg)
+{
+ /* Take the current base - caller needs to set the real base later */
+ ev->ev_base = current_base;
+
+ ev->ev_callback = callback;
+ ev->ev_arg = arg;
+ ev->ev_fd = fd;
+ ev->ev_events = events;
+ ev->ev_res = 0;
+ ev->ev_flags = EVLIST_INIT;
+ ev->ev_ncalls = 0;
+ ev->ev_pncalls = NULL;
+
+ min_heap_elem_init(ev);
+
+ /* by default, we put new events into the middle priority */
+ if(current_base)
+ ev->ev_pri = current_base->nactivequeues/2;
+}
+
+int
+event_base_set(struct event_base *base, struct event *ev)
+{
+ /* Only innocent events may be assigned to a different base */
+ if (ev->ev_flags != EVLIST_INIT)
+ return (-1);
+
+ ev->ev_base = base;
+ ev->ev_pri = base->nactivequeues/2;
+
+ return (0);
+}
+
+/*
+ * Set's the priority of an event - if an event is already scheduled
+ * changing the priority is going to fail.
+ */
+
+int
+event_priority_set(struct event *ev, int pri)
+{
+ if (ev->ev_flags & EVLIST_ACTIVE)
+ return (-1);
+ if (pri < 0 || pri >= ev->ev_base->nactivequeues)
+ return (-1);
+
+ ev->ev_pri = pri;
+
+ return (0);
+}
+
+/*
+ * Checks if a specific event is pending or scheduled.
+ */
+
+int
+event_pending(struct event *ev, short event, struct timeval *tv)
+{
+ struct timeval now, res;
+ int flags = 0;
+
+ if (ev->ev_flags & EVLIST_INSERTED)
+ flags |= (ev->ev_events & (EV_READ|EV_WRITE|EV_SIGNAL));
+ if (ev->ev_flags & EVLIST_ACTIVE)
+ flags |= ev->ev_res;
+ if (ev->ev_flags & EVLIST_TIMEOUT)
+ flags |= EV_TIMEOUT;
+
+ event &= (EV_TIMEOUT|EV_READ|EV_WRITE|EV_SIGNAL);
+
+ /* See if there is a timeout that we should report */
+ if (tv != NULL && (flags & event & EV_TIMEOUT)) {
+ gettime(ev->ev_base, &now);
+ evutil_timersub(&ev->ev_timeout, &now, &res);
+ /* correctly remap to real time */
+ evutil_gettimeofday(&now, NULL);
+ evutil_timeradd(&now, &res, tv);
+ }
+
+ return (flags & event);
+}
+
+int
+event_add(struct event *ev, const struct timeval *tv)
+{
+ struct event_base *base = ev->ev_base;
+ const struct eventop *evsel = base->evsel;
+ void *evbase = base->evbase;
+ int res = 0;
+
+ event_debug((
+ "event_add: event: %p, %s%s%scall %p",
+ ev,
+ ev->ev_events & EV_READ ? "EV_READ " : " ",
+ ev->ev_events & EV_WRITE ? "EV_WRITE " : " ",
+ tv ? "EV_TIMEOUT " : " ",
+ ev->ev_callback));
+
+ assert(!(ev->ev_flags & ~EVLIST_ALL));
+
+ /*
+ * prepare for timeout insertion further below, if we get a
+ * failure on any step, we should not change any state.
+ */
+ if (tv != NULL && !(ev->ev_flags & EVLIST_TIMEOUT)) {
+ if (min_heap_reserve(&base->timeheap,
+ 1 + min_heap_size(&base->timeheap)) == -1)
+ return (-1); /* ENOMEM == errno */
+ }
+
+ if ((ev->ev_events & (EV_READ|EV_WRITE|EV_SIGNAL)) &&
+ !(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) {
+ res = evsel->add(evbase, ev);
+ if (res != -1)
+ event_queue_insert(base, ev, EVLIST_INSERTED);
+ }
+
+ /*
+ * we should change the timout state only if the previous event
+ * addition succeeded.
+ */
+ if (res != -1 && tv != NULL) {
+ struct timeval now;
+
+ /*
+ * we already reserved memory above for the case where we
+ * are not replacing an exisiting timeout.
+ */
+ if (ev->ev_flags & EVLIST_TIMEOUT)
+ event_queue_remove(base, ev, EVLIST_TIMEOUT);
+
+ /* Check if it is active due to a timeout. Rescheduling
+ * this timeout before the callback can be executed
+ * removes it from the active list. */
+ if ((ev->ev_flags & EVLIST_ACTIVE) &&
+ (ev->ev_res & EV_TIMEOUT)) {
+ /* See if we are just active executing this
+ * event in a loop
+ */
+ if (ev->ev_ncalls && ev->ev_pncalls) {
+ /* Abort loop */
+ *ev->ev_pncalls = 0;
+ }
+
+ event_queue_remove(base, ev, EVLIST_ACTIVE);
+ }
+
+ gettime(base, &now);
+ evutil_timeradd(&now, tv, &ev->ev_timeout);
+
+ event_debug((
+ "event_add: timeout in %ld seconds, call %p",
+ tv->tv_sec, ev->ev_callback));
+
+ event_queue_insert(base, ev, EVLIST_TIMEOUT);
+ }
+
+ return (res);
+}
+
+int
+event_del(struct event *ev)
+{
+ struct event_base *base;
+
+ event_debug(("event_del: %p, callback %p",
+ ev, ev->ev_callback));
+
+ /* An event without a base has not been added */
+ if (ev->ev_base == NULL)
+ return (-1);
+
+ base = ev->ev_base;
+
+ assert(!(ev->ev_flags & ~EVLIST_ALL));
+
+ /* See if we are just active executing this event in a loop */
+ if (ev->ev_ncalls && ev->ev_pncalls) {
+ /* Abort loop */
+ *ev->ev_pncalls = 0;
+ }
+
+ if (ev->ev_flags & EVLIST_TIMEOUT)
+ event_queue_remove(base, ev, EVLIST_TIMEOUT);
+
+ if (ev->ev_flags & EVLIST_ACTIVE)
+ event_queue_remove(base, ev, EVLIST_ACTIVE);
+
+ if (ev->ev_flags & EVLIST_INSERTED) {
+ event_queue_remove(base, ev, EVLIST_INSERTED);
+ return (base->evsel->del(base->evbase, ev));
+ }
+
+ return (0);
+}
+
+void
+event_active(struct event *ev, int res, short ncalls)
+{
+ /* We get different kinds of events, add them together */
+ if (ev->ev_flags & EVLIST_ACTIVE) {
+ ev->ev_res |= res;
+ return;
+ }
+
+ ev->ev_res = res;
+ ev->ev_ncalls = ncalls;
+ ev->ev_pncalls = NULL;
+ event_queue_insert(ev->ev_base, ev, EVLIST_ACTIVE);
+}
+
+static int
+timeout_next(struct event_base *base, struct timeval **tv_p)
+{
+ struct timeval now;
+ struct event *ev;
+ struct timeval *tv = *tv_p;
+
+ if ((ev = min_heap_top(&base->timeheap)) == NULL) {
+ /* if no time-based events are active wait for I/O */
+ *tv_p = NULL;
+ return (0);
+ }
+
+ if (gettime(base, &now) == -1)
+ return (-1);
+
+ if (evutil_timercmp(&ev->ev_timeout, &now, <=)) {
+ evutil_timerclear(tv);
+ return (0);
+ }
+
+ evutil_timersub(&ev->ev_timeout, &now, tv);
+
+ assert(tv->tv_sec >= 0);
+ assert(tv->tv_usec >= 0);
+
+ event_debug(("timeout_next: in %ld seconds", tv->tv_sec));
+ return (0);
+}
+
+/*
+ * Determines if the time is running backwards by comparing the current
+ * time against the last time we checked. Not needed when using clock
+ * monotonic.
+ */
+
+static void
+timeout_correct(struct event_base *base, struct timeval *tv)
+{
+ struct event **pev;
+ unsigned int size;
+ struct timeval off;
+
+ if (use_monotonic)
+ return;
+
+ /* Check if time is running backwards */
+ gettime(base, tv);
+ if (evutil_timercmp(tv, &base->event_tv, >=)) {
+ base->event_tv = *tv;
+ return;
+ }
+
+ event_debug(("%s: time is running backwards, corrected",
+ __func__));
+ evutil_timersub(&base->event_tv, tv, &off);
+
+ /*
+ * We can modify the key element of the node without destroying
+ * the key, beause we apply it to all in the right order.
+ */
+ pev = base->timeheap.p;
+ size = base->timeheap.n;
+ for (; size-- > 0; ++pev) {
+ struct timeval *ev_tv = &(**pev).ev_timeout;
+ evutil_timersub(ev_tv, &off, ev_tv);
+ }
+ /* Now remember what the new time turned out to be. */
+ base->event_tv = *tv;
+}
+
+void
+timeout_process(struct event_base *base)
+{
+ struct timeval now;
+ struct event *ev;
+
+ if (min_heap_empty(&base->timeheap))
+ return;
+
+ gettime(base, &now);
+
+ while ((ev = min_heap_top(&base->timeheap))) {
+ if (evutil_timercmp(&ev->ev_timeout, &now, >))
+ break;
+
+ /* delete this event from the I/O queues */
+ event_del(ev);
+
+ event_debug(("timeout_process: call %p",
+ ev->ev_callback));
+ event_active(ev, EV_TIMEOUT, 1);
+ }
+}
+
+void
+event_queue_remove(struct event_base *base, struct event *ev, int queue)
+{
+ if (!(ev->ev_flags & queue))
+ event_errx(1, "%s: %p(fd %d) not on queue %x", __func__,
+ ev, ev->ev_fd, queue);
+
+ if (~ev->ev_flags & EVLIST_INTERNAL)
+ base->event_count--;
+
+ ev->ev_flags &= ~queue;
+ switch (queue) {
+ case EVLIST_INSERTED:
+ TAILQ_REMOVE(&base->eventqueue, ev, ev_next);
+ break;
+ case EVLIST_ACTIVE:
+ base->event_count_active--;
+ TAILQ_REMOVE(base->activequeues[ev->ev_pri],
+ ev, ev_active_next);
+ break;
+ case EVLIST_TIMEOUT:
+ min_heap_erase(&base->timeheap, ev);
+ break;
+ default:
+ event_errx(1, "%s: unknown queue %x", __func__, queue);
+ }
+}
+
+void
+event_queue_insert(struct event_base *base, struct event *ev, int queue)
+{
+ if (ev->ev_flags & queue) {
+ /* Double insertion is possible for active events */
+ if (queue & EVLIST_ACTIVE)
+ return;
+
+ event_errx(1, "%s: %p(fd %d) already on queue %x", __func__,
+ ev, ev->ev_fd, queue);
+ }
+
+ if (~ev->ev_flags & EVLIST_INTERNAL)
+ base->event_count++;
+
+ ev->ev_flags |= queue;
+ switch (queue) {
+ case EVLIST_INSERTED:
+ TAILQ_INSERT_TAIL(&base->eventqueue, ev, ev_next);
+ break;
+ case EVLIST_ACTIVE:
+ base->event_count_active++;
+ TAILQ_INSERT_TAIL(base->activequeues[ev->ev_pri],
+ ev,ev_active_next);
+ break;
+ case EVLIST_TIMEOUT: {
+ min_heap_push(&base->timeheap, ev);
+ break;
+ }
+ default:
+ event_errx(1, "%s: unknown queue %x", __func__, queue);
+ }
+}
+
+/* Functions for debugging */
+
+const char *
+event_get_version(void)
+{
+ return (VERSION);
+}
+
+/*
+ * No thread-safe interface needed - the information should be the same
+ * for all threads.
+ */
+
+const char *
+event_get_method(void)
+{
+ return (current_base->evsel->name);
+}
diff --git a/chromium/base/third_party/libevent/event.h b/chromium/base/third_party/libevent/event.h
new file mode 100644
index 00000000000..f0887b96163
--- /dev/null
+++ b/chromium/base/third_party/libevent/event.h
@@ -0,0 +1,1212 @@
+/*
+ * Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _EVENT_H_
+#define _EVENT_H_
+
+/** @mainpage
+
+ @section intro Introduction
+
+ libevent is an event notification library for developing scalable network
+ servers. The libevent API provides a mechanism to execute a callback
+ function when a specific event occurs on a file descriptor or after a
+ timeout has been reached. Furthermore, libevent also support callbacks due
+ to signals or regular timeouts.
+
+ libevent is meant to replace the event loop found in event driven network
+ servers. An application just needs to call event_dispatch() and then add or
+ remove events dynamically without having to change the event loop.
+
+ Currently, libevent supports /dev/poll, kqueue(2), select(2), poll(2) and
+ epoll(4). It also has experimental support for real-time signals. The
+ internal event mechanism is completely independent of the exposed event API,
+ and a simple update of libevent can provide new functionality without having
+ to redesign the applications. As a result, Libevent allows for portable
+ application development and provides the most scalable event notification
+ mechanism available on an operating system. Libevent can also be used for
+ multi-threaded aplications; see Steven Grimm's explanation. Libevent should
+ compile on Linux, *BSD, Mac OS X, Solaris and Windows.
+
+ @section usage Standard usage
+
+ Every program that uses libevent must include the <event.h> header, and pass
+ the -levent flag to the linker. Before using any of the functions in the
+ library, you must call event_init() or event_base_new() to perform one-time
+ initialization of the libevent library.
+
+ @section event Event notification
+
+ For each file descriptor that you wish to monitor, you must declare an event
+ structure and call event_set() to initialize the members of the structure.
+ To enable notification, you add the structure to the list of monitored
+ events by calling event_add(). The event structure must remain allocated as
+ long as it is active, so it should be allocated on the heap. Finally, you
+ call event_dispatch() to loop and dispatch events.
+
+ @section bufferevent I/O Buffers
+
+ libevent provides an abstraction on top of the regular event callbacks. This
+ abstraction is called a buffered event. A buffered event provides input and
+ output buffers that get filled and drained automatically. The user of a
+ buffered event no longer deals directly with the I/O, but instead is reading
+ from input and writing to output buffers.
+
+ Once initialized via bufferevent_new(), the bufferevent structure can be
+ used repeatedly with bufferevent_enable() and bufferevent_disable().
+ Instead of reading and writing directly to a socket, you would call
+ bufferevent_read() and bufferevent_write().
+
+ When read enabled the bufferevent will try to read from the file descriptor
+ and call the read callback. The write callback is executed whenever the
+ output buffer is drained below the write low watermark, which is 0 by
+ default.
+
+ @section timers Timers
+
+ libevent can also be used to create timers that invoke a callback after a
+ certain amount of time has expired. The evtimer_set() function prepares an
+ event struct to be used as a timer. To activate the timer, call
+ evtimer_add(). Timers can be deactivated by calling evtimer_del().
+
+ @section timeouts Timeouts
+
+ In addition to simple timers, libevent can assign timeout events to file
+ descriptors that are triggered whenever a certain amount of time has passed
+ with no activity on a file descriptor. The timeout_set() function
+ initializes an event struct for use as a timeout. Once initialized, the
+ event must be activated by using timeout_add(). To cancel the timeout, call
+ timeout_del().
+
+ @section evdns Asynchronous DNS resolution
+
+ libevent provides an asynchronous DNS resolver that should be used instead
+ of the standard DNS resolver functions. These functions can be imported by
+ including the <evdns.h> header in your program. Before using any of the
+ resolver functions, you must call evdns_init() to initialize the library. To
+ convert a hostname to an IP address, you call the evdns_resolve_ipv4()
+ function. To perform a reverse lookup, you would call the
+ evdns_resolve_reverse() function. All of these functions use callbacks to
+ avoid blocking while the lookup is performed.
+
+ @section evhttp Event-driven HTTP servers
+
+ libevent provides a very simple event-driven HTTP server that can be
+ embedded in your program and used to service HTTP requests.
+
+ To use this capability, you need to include the <evhttp.h> header in your
+ program. You create the server by calling evhttp_new(). Add addresses and
+ ports to listen on with evhttp_bind_socket(). You then register one or more
+ callbacks to handle incoming requests. Each URI can be assigned a callback
+ via the evhttp_set_cb() function. A generic callback function can also be
+ registered via evhttp_set_gencb(); this callback will be invoked if no other
+ callbacks have been registered for a given URI.
+
+ @section evrpc A framework for RPC servers and clients
+
+ libevents provides a framework for creating RPC servers and clients. It
+ takes care of marshaling and unmarshaling all data structures.
+
+ @section api API Reference
+
+ To browse the complete documentation of the libevent API, click on any of
+ the following links.
+
+ event.h
+ The primary libevent header
+
+ evdns.h
+ Asynchronous DNS resolution
+
+ evhttp.h
+ An embedded libevent-based HTTP server
+
+ evrpc.h
+ A framework for creating RPC servers and clients
+
+ */
+
+/** @file event.h
+
+ A library for writing event-driven network servers
+
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "event-config.h"
+#ifdef _EVENT_HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef _EVENT_HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef _EVENT_HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#include <stdarg.h>
+
+/* For int types. */
+#include "evutil.h"
+
+#ifdef WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+typedef unsigned char u_char;
+typedef unsigned short u_short;
+#endif
+
+#define EVLIST_TIMEOUT 0x01
+#define EVLIST_INSERTED 0x02
+#define EVLIST_SIGNAL 0x04
+#define EVLIST_ACTIVE 0x08
+#define EVLIST_INTERNAL 0x10
+#define EVLIST_INIT 0x80
+
+/* EVLIST_X_ Private space: 0x1000-0xf000 */
+#define EVLIST_ALL (0xf000 | 0x9f)
+
+#define EV_TIMEOUT 0x01
+#define EV_READ 0x02
+#define EV_WRITE 0x04
+#define EV_SIGNAL 0x08
+#define EV_PERSIST 0x10 /* Persistant event */
+
+/* Fix so that ppl dont have to run with <sys/queue.h> */
+#ifndef TAILQ_ENTRY
+#define _EVENT_DEFINED_TQENTRY
+#define TAILQ_ENTRY(type) \
+struct { \
+ struct type *tqe_next; /* next element */ \
+ struct type **tqe_prev; /* address of previous next element */ \
+}
+#endif /* !TAILQ_ENTRY */
+
+struct event_base;
+#ifndef EVENT_NO_STRUCT
+struct event {
+ TAILQ_ENTRY (event) ev_next;
+ TAILQ_ENTRY (event) ev_active_next;
+ TAILQ_ENTRY (event) ev_signal_next;
+ unsigned int min_heap_idx; /* for managing timeouts */
+
+ struct event_base *ev_base;
+
+ int ev_fd;
+ short ev_events;
+ short ev_ncalls;
+ short *ev_pncalls; /* Allows deletes in callback */
+
+ struct timeval ev_timeout;
+
+ int ev_pri; /* smaller numbers are higher priority */
+
+ void (*ev_callback)(int, short, void *arg);
+ void *ev_arg;
+
+ int ev_res; /* result passed to event callback */
+ int ev_flags;
+};
+#else
+struct event;
+#endif
+
+#define EVENT_SIGNAL(ev) (int)(ev)->ev_fd
+#define EVENT_FD(ev) (int)(ev)->ev_fd
+
+/*
+ * Key-Value pairs. Can be used for HTTP headers but also for
+ * query argument parsing.
+ */
+struct evkeyval {
+ TAILQ_ENTRY(evkeyval) next;
+
+ char *key;
+ char *value;
+};
+
+#ifdef _EVENT_DEFINED_TQENTRY
+#undef TAILQ_ENTRY
+struct event_list;
+struct evkeyvalq;
+#undef _EVENT_DEFINED_TQENTRY
+#else
+TAILQ_HEAD (event_list, event);
+TAILQ_HEAD (evkeyvalq, evkeyval);
+#endif /* _EVENT_DEFINED_TQENTRY */
+
+/**
+ Initialize the event API.
+
+ Use event_base_new() to initialize a new event base, but does not set
+ the current_base global. If using only event_base_new(), each event
+ added must have an event base set with event_base_set()
+
+ @see event_base_set(), event_base_free(), event_init()
+ */
+struct event_base *event_base_new(void);
+
+/**
+ Initialize the event API.
+
+ The event API needs to be initialized with event_init() before it can be
+ used. Sets the current_base global representing the default base for
+ events that have no base associated with them.
+
+ @see event_base_set(), event_base_new()
+ */
+struct event_base *event_init(void);
+
+/**
+ Reinitialized the event base after a fork
+
+ Some event mechanisms do not survive across fork. The event base needs
+ to be reinitialized with the event_reinit() function.
+
+ @param base the event base that needs to be re-initialized
+ @return 0 if successful, or -1 if some events could not be re-added.
+ @see event_base_new(), event_init()
+*/
+int event_reinit(struct event_base *base);
+
+/**
+ Loop to process events.
+
+ In order to process events, an application needs to call
+ event_dispatch(). This function only returns on error, and should
+ replace the event core of the application program.
+
+ @see event_base_dispatch()
+ */
+int event_dispatch(void);
+
+
+/**
+ Threadsafe event dispatching loop.
+
+ @param eb the event_base structure returned by event_init()
+ @see event_init(), event_dispatch()
+ */
+int event_base_dispatch(struct event_base *);
+
+
+/**
+ Get the kernel event notification mechanism used by libevent.
+
+ @param eb the event_base structure returned by event_base_new()
+ @return a string identifying the kernel event mechanism (kqueue, epoll, etc.)
+ */
+const char *event_base_get_method(struct event_base *);
+
+
+/**
+ Deallocate all memory associated with an event_base, and free the base.
+
+ Note that this function will not close any fds or free any memory passed
+ to event_set as the argument to callback.
+
+ @param eb an event_base to be freed
+ */
+void event_base_free(struct event_base *);
+
+
+#define _EVENT_LOG_DEBUG 0
+#define _EVENT_LOG_MSG 1
+#define _EVENT_LOG_WARN 2
+#define _EVENT_LOG_ERR 3
+typedef void (*event_log_cb)(int severity, const char *msg);
+/**
+ Redirect libevent's log messages.
+
+ @param cb a function taking two arguments: an integer severity between
+ _EVENT_LOG_DEBUG and _EVENT_LOG_ERR, and a string. If cb is NULL,
+ then the default log is used.
+ */
+void event_set_log_callback(event_log_cb cb);
+
+/**
+ Associate a different event base with an event.
+
+ @param eb the event base
+ @param ev the event
+ */
+int event_base_set(struct event_base *, struct event *);
+
+/**
+ event_loop() flags
+ */
+/*@{*/
+#define EVLOOP_ONCE 0x01 /**< Block at most once. */
+#define EVLOOP_NONBLOCK 0x02 /**< Do not block. */
+/*@}*/
+
+/**
+ Handle events.
+
+ This is a more flexible version of event_dispatch().
+
+ @param flags any combination of EVLOOP_ONCE | EVLOOP_NONBLOCK
+ @return 0 if successful, -1 if an error occurred, or 1 if no events were
+ registered.
+ @see event_loopexit(), event_base_loop()
+*/
+int event_loop(int);
+
+/**
+ Handle events (threadsafe version).
+
+ This is a more flexible version of event_base_dispatch().
+
+ @param eb the event_base structure returned by event_init()
+ @param flags any combination of EVLOOP_ONCE | EVLOOP_NONBLOCK
+ @return 0 if successful, -1 if an error occurred, or 1 if no events were
+ registered.
+ @see event_loopexit(), event_base_loop()
+ */
+int event_base_loop(struct event_base *, int);
+
+/**
+ Exit the event loop after the specified time.
+
+ The next event_loop() iteration after the given timer expires will
+ complete normally (handling all queued events) then exit without
+ blocking for events again.
+
+ Subsequent invocations of event_loop() will proceed normally.
+
+ @param tv the amount of time after which the loop should terminate.
+ @return 0 if successful, or -1 if an error occurred
+ @see event_loop(), event_base_loop(), event_base_loopexit()
+ */
+int event_loopexit(const struct timeval *);
+
+
+/**
+ Exit the event loop after the specified time (threadsafe variant).
+
+ The next event_base_loop() iteration after the given timer expires will
+ complete normally (handling all queued events) then exit without
+ blocking for events again.
+
+ Subsequent invocations of event_base_loop() will proceed normally.
+
+ @param eb the event_base structure returned by event_init()
+ @param tv the amount of time after which the loop should terminate.
+ @return 0 if successful, or -1 if an error occurred
+ @see event_loopexit()
+ */
+int event_base_loopexit(struct event_base *, const struct timeval *);
+
+/**
+ Abort the active event_loop() immediately.
+
+ event_loop() will abort the loop after the next event is completed;
+ event_loopbreak() is typically invoked from this event's callback.
+ This behavior is analogous to the "break;" statement.
+
+ Subsequent invocations of event_loop() will proceed normally.
+
+ @return 0 if successful, or -1 if an error occurred
+ @see event_base_loopbreak(), event_loopexit()
+ */
+int event_loopbreak(void);
+
+/**
+ Abort the active event_base_loop() immediately.
+
+ event_base_loop() will abort the loop after the next event is completed;
+ event_base_loopbreak() is typically invoked from this event's callback.
+ This behavior is analogous to the "break;" statement.
+
+ Subsequent invocations of event_loop() will proceed normally.
+
+ @param eb the event_base structure returned by event_init()
+ @return 0 if successful, or -1 if an error occurred
+ @see event_base_loopexit
+ */
+int event_base_loopbreak(struct event_base *);
+
+
+/**
+ Add a timer event.
+
+ @param ev the event struct
+ @param tv timeval struct
+ */
+#define evtimer_add(ev, tv) event_add(ev, tv)
+
+
+/**
+ Define a timer event.
+
+ @param ev event struct to be modified
+ @param cb callback function
+ @param arg argument that will be passed to the callback function
+ */
+#define evtimer_set(ev, cb, arg) event_set(ev, -1, 0, cb, arg)
+
+
+/**
+ * Delete a timer event.
+ *
+ * @param ev the event struct to be disabled
+ */
+#define evtimer_del(ev) event_del(ev)
+#define evtimer_pending(ev, tv) event_pending(ev, EV_TIMEOUT, tv)
+#define evtimer_initialized(ev) ((ev)->ev_flags & EVLIST_INIT)
+
+/**
+ * Add a timeout event.
+ *
+ * @param ev the event struct to be disabled
+ * @param tv the timeout value, in seconds
+ */
+#define timeout_add(ev, tv) event_add(ev, tv)
+
+
+/**
+ * Define a timeout event.
+ *
+ * @param ev the event struct to be defined
+ * @param cb the callback to be invoked when the timeout expires
+ * @param arg the argument to be passed to the callback
+ */
+#define timeout_set(ev, cb, arg) event_set(ev, -1, 0, cb, arg)
+
+
+/**
+ * Disable a timeout event.
+ *
+ * @param ev the timeout event to be disabled
+ */
+#define timeout_del(ev) event_del(ev)
+
+#define timeout_pending(ev, tv) event_pending(ev, EV_TIMEOUT, tv)
+#define timeout_initialized(ev) ((ev)->ev_flags & EVLIST_INIT)
+
+#define signal_add(ev, tv) event_add(ev, tv)
+#define signal_set(ev, x, cb, arg) \
+ event_set(ev, x, EV_SIGNAL|EV_PERSIST, cb, arg)
+#define signal_del(ev) event_del(ev)
+#define signal_pending(ev, tv) event_pending(ev, EV_SIGNAL, tv)
+#define signal_initialized(ev) ((ev)->ev_flags & EVLIST_INIT)
+
+/**
+ Prepare an event structure to be added.
+
+ The function event_set() prepares the event structure ev to be used in
+ future calls to event_add() and event_del(). The event will be prepared to
+ call the function specified by the fn argument with an int argument
+ indicating the file descriptor, a short argument indicating the type of
+ event, and a void * argument given in the arg argument. The fd indicates
+ the file descriptor that should be monitored for events. The events can be
+ either EV_READ, EV_WRITE, or both. Indicating that an application can read
+ or write from the file descriptor respectively without blocking.
+
+ The function fn will be called with the file descriptor that triggered the
+ event and the type of event which will be either EV_TIMEOUT, EV_SIGNAL,
+ EV_READ, or EV_WRITE. The additional flag EV_PERSIST makes an event_add()
+ persistent until event_del() has been called.
+
+ @param ev an event struct to be modified
+ @param fd the file descriptor to be monitored
+ @param event desired events to monitor; can be EV_READ and/or EV_WRITE
+ @param fn callback function to be invoked when the event occurs
+ @param arg an argument to be passed to the callback function
+
+ @see event_add(), event_del(), event_once()
+
+ */
+void event_set(struct event *, int, short, void (*)(int, short, void *), void *);
+
+/**
+ Schedule a one-time event to occur.
+
+ The function event_once() is similar to event_set(). However, it schedules
+ a callback to be called exactly once and does not require the caller to
+ prepare an event structure.
+
+ @param fd a file descriptor to monitor
+ @param events event(s) to monitor; can be any of EV_TIMEOUT | EV_READ |
+ EV_WRITE
+ @param callback callback function to be invoked when the event occurs
+ @param arg an argument to be passed to the callback function
+ @param timeout the maximum amount of time to wait for the event, or NULL
+ to wait forever
+ @return 0 if successful, or -1 if an error occurred
+ @see event_set()
+
+ */
+int event_once(int, short, void (*)(int, short, void *), void *,
+ const struct timeval *);
+
+
+/**
+ Schedule a one-time event (threadsafe variant)
+
+ The function event_base_once() is similar to event_set(). However, it
+ schedules a callback to be called exactly once and does not require the
+ caller to prepare an event structure.
+
+ @param base an event_base returned by event_init()
+ @param fd a file descriptor to monitor
+ @param events event(s) to monitor; can be any of EV_TIMEOUT | EV_READ |
+ EV_WRITE
+ @param callback callback function to be invoked when the event occurs
+ @param arg an argument to be passed to the callback function
+ @param timeout the maximum amount of time to wait for the event, or NULL
+ to wait forever
+ @return 0 if successful, or -1 if an error occurred
+ @see event_once()
+ */
+int event_base_once(struct event_base *base, int fd, short events,
+ void (*callback)(int, short, void *), void *arg,
+ const struct timeval *timeout);
+
+
+/**
+ Add an event to the set of monitored events.
+
+ The function event_add() schedules the execution of the ev event when the
+ event specified in event_set() occurs or in at least the time specified in
+ the tv. If tv is NULL, no timeout occurs and the function will only be
+ called if a matching event occurs on the file descriptor. The event in the
+ ev argument must be already initialized by event_set() and may not be used
+ in calls to event_set() until it has timed out or been removed with
+ event_del(). If the event in the ev argument already has a scheduled
+ timeout, the old timeout will be replaced by the new one.
+
+ @param ev an event struct initialized via event_set()
+ @param timeout the maximum amount of time to wait for the event, or NULL
+ to wait forever
+ @return 0 if successful, or -1 if an error occurred
+ @see event_del(), event_set()
+ */
+int event_add(struct event *ev, const struct timeval *timeout);
+
+
+/**
+ Remove an event from the set of monitored events.
+
+ The function event_del() will cancel the event in the argument ev. If the
+ event has already executed or has never been added the call will have no
+ effect.
+
+ @param ev an event struct to be removed from the working set
+ @return 0 if successful, or -1 if an error occurred
+ @see event_add()
+ */
+int event_del(struct event *);
+
+void event_active(struct event *, int, short);
+
+
+/**
+ Checks if a specific event is pending or scheduled.
+
+ @param ev an event struct previously passed to event_add()
+ @param event the requested event type; any of EV_TIMEOUT|EV_READ|
+ EV_WRITE|EV_SIGNAL
+ @param tv an alternate timeout (FIXME - is this true?)
+
+ @return 1 if the event is pending, or 0 if the event has not occurred
+
+ */
+int event_pending(struct event *ev, short event, struct timeval *tv);
+
+
+/**
+ Test if an event structure has been initialized.
+
+ The event_initialized() macro can be used to check if an event has been
+ initialized.
+
+ @param ev an event structure to be tested
+ @return 1 if the structure has been initialized, or 0 if it has not been
+ initialized
+ */
+#ifdef WIN32
+#define event_initialized(ev) ((ev)->ev_flags & EVLIST_INIT && (ev)->ev_fd != (int)INVALID_HANDLE_VALUE)
+#else
+#define event_initialized(ev) ((ev)->ev_flags & EVLIST_INIT)
+#endif
+
+
+/**
+ Get the libevent version number.
+
+ @return a string containing the version number of libevent
+ */
+const char *event_get_version(void);
+
+
+/**
+ Get the kernel event notification mechanism used by libevent.
+
+ @return a string identifying the kernel event mechanism (kqueue, epoll, etc.)
+ */
+const char *event_get_method(void);
+
+
+/**
+ Set the number of different event priorities.
+
+ By default libevent schedules all active events with the same priority.
+ However, some time it is desirable to process some events with a higher
+ priority than others. For that reason, libevent supports strict priority
+ queues. Active events with a lower priority are always processed before
+ events with a higher priority.
+
+ The number of different priorities can be set initially with the
+ event_priority_init() function. This function should be called before the
+ first call to event_dispatch(). The event_priority_set() function can be
+ used to assign a priority to an event. By default, libevent assigns the
+ middle priority to all events unless their priority is explicitly set.
+
+ @param npriorities the maximum number of priorities
+ @return 0 if successful, or -1 if an error occurred
+ @see event_base_priority_init(), event_priority_set()
+
+ */
+int event_priority_init(int);
+
+
+/**
+ Set the number of different event priorities (threadsafe variant).
+
+ See the description of event_priority_init() for more information.
+
+ @param eb the event_base structure returned by event_init()
+ @param npriorities the maximum number of priorities
+ @return 0 if successful, or -1 if an error occurred
+ @see event_priority_init(), event_priority_set()
+ */
+int event_base_priority_init(struct event_base *, int);
+
+
+/**
+ Assign a priority to an event.
+
+ @param ev an event struct
+ @param priority the new priority to be assigned
+ @return 0 if successful, or -1 if an error occurred
+ @see event_priority_init()
+ */
+int event_priority_set(struct event *, int);
+
+
+/* These functions deal with buffering input and output */
+
+struct evbuffer {
+ u_char *buffer;
+ u_char *orig_buffer;
+
+ size_t misalign;
+ size_t totallen;
+ size_t off;
+
+ void (*cb)(struct evbuffer *, size_t, size_t, void *);
+ void *cbarg;
+};
+
+/* Just for error reporting - use other constants otherwise */
+#define EVBUFFER_READ 0x01
+#define EVBUFFER_WRITE 0x02
+#define EVBUFFER_EOF 0x10
+#define EVBUFFER_ERROR 0x20
+#define EVBUFFER_TIMEOUT 0x40
+
+struct bufferevent;
+typedef void (*evbuffercb)(struct bufferevent *, void *);
+typedef void (*everrorcb)(struct bufferevent *, short what, void *);
+
+struct event_watermark {
+ size_t low;
+ size_t high;
+};
+
+#ifndef EVENT_NO_STRUCT
+struct bufferevent {
+ struct event_base *ev_base;
+
+ struct event ev_read;
+ struct event ev_write;
+
+ struct evbuffer *input;
+ struct evbuffer *output;
+
+ struct event_watermark wm_read;
+ struct event_watermark wm_write;
+
+ evbuffercb readcb;
+ evbuffercb writecb;
+ everrorcb errorcb;
+ void *cbarg;
+
+ int timeout_read; /* in seconds */
+ int timeout_write; /* in seconds */
+
+ short enabled; /* events that are currently enabled */
+};
+#endif
+
+/**
+ Create a new bufferevent.
+
+ libevent provides an abstraction on top of the regular event callbacks.
+ This abstraction is called a buffered event. A buffered event provides
+ input and output buffers that get filled and drained automatically. The
+ user of a buffered event no longer deals directly with the I/O, but
+ instead is reading from input and writing to output buffers.
+
+ Once initialized, the bufferevent structure can be used repeatedly with
+ bufferevent_enable() and bufferevent_disable().
+
+ When read enabled the bufferevent will try to read from the file descriptor
+ and call the read callback. The write callback is executed whenever the
+ output buffer is drained below the write low watermark, which is 0 by
+ default.
+
+ If multiple bases are in use, bufferevent_base_set() must be called before
+ enabling the bufferevent for the first time.
+
+ @param fd the file descriptor from which data is read and written to.
+ This file descriptor is not allowed to be a pipe(2).
+ @param readcb callback to invoke when there is data to be read, or NULL if
+ no callback is desired
+ @param writecb callback to invoke when the file descriptor is ready for
+ writing, or NULL if no callback is desired
+ @param errorcb callback to invoke when there is an error on the file
+ descriptor
+ @param cbarg an argument that will be supplied to each of the callbacks
+ (readcb, writecb, and errorcb)
+ @return a pointer to a newly allocated bufferevent struct, or NULL if an
+ error occurred
+ @see bufferevent_base_set(), bufferevent_free()
+ */
+struct bufferevent *bufferevent_new(int fd,
+ evbuffercb readcb, evbuffercb writecb, everrorcb errorcb, void *cbarg);
+
+
+/**
+ Assign a bufferevent to a specific event_base.
+
+ @param base an event_base returned by event_init()
+ @param bufev a bufferevent struct returned by bufferevent_new()
+ @return 0 if successful, or -1 if an error occurred
+ @see bufferevent_new()
+ */
+int bufferevent_base_set(struct event_base *base, struct bufferevent *bufev);
+
+
+/**
+ Assign a priority to a bufferevent.
+
+ @param bufev a bufferevent struct
+ @param pri the priority to be assigned
+ @return 0 if successful, or -1 if an error occurred
+ */
+int bufferevent_priority_set(struct bufferevent *bufev, int pri);
+
+
+/**
+ Deallocate the storage associated with a bufferevent structure.
+
+ @param bufev the bufferevent structure to be freed.
+ */
+void bufferevent_free(struct bufferevent *bufev);
+
+
+/**
+ Changes the callbacks for a bufferevent.
+
+ @param bufev the bufferevent object for which to change callbacks
+ @param readcb callback to invoke when there is data to be read, or NULL if
+ no callback is desired
+ @param writecb callback to invoke when the file descriptor is ready for
+ writing, or NULL if no callback is desired
+ @param errorcb callback to invoke when there is an error on the file
+ descriptor
+ @param cbarg an argument that will be supplied to each of the callbacks
+ (readcb, writecb, and errorcb)
+ @see bufferevent_new()
+ */
+void bufferevent_setcb(struct bufferevent *bufev,
+ evbuffercb readcb, evbuffercb writecb, everrorcb errorcb, void *cbarg);
+
+/**
+ Changes the file descriptor on which the bufferevent operates.
+
+ @param bufev the bufferevent object for which to change the file descriptor
+ @param fd the file descriptor to operate on
+*/
+void bufferevent_setfd(struct bufferevent *bufev, int fd);
+
+/**
+ Write data to a bufferevent buffer.
+
+ The bufferevent_write() function can be used to write data to the file
+ descriptor. The data is appended to the output buffer and written to the
+ descriptor automatically as it becomes available for writing.
+
+ @param bufev the bufferevent to be written to
+ @param data a pointer to the data to be written
+ @param size the length of the data, in bytes
+ @return 0 if successful, or -1 if an error occurred
+ @see bufferevent_write_buffer()
+ */
+int bufferevent_write(struct bufferevent *bufev,
+ const void *data, size_t size);
+
+
+/**
+ Write data from an evbuffer to a bufferevent buffer. The evbuffer is
+ being drained as a result.
+
+ @param bufev the bufferevent to be written to
+ @param buf the evbuffer to be written
+ @return 0 if successful, or -1 if an error occurred
+ @see bufferevent_write()
+ */
+int bufferevent_write_buffer(struct bufferevent *bufev, struct evbuffer *buf);
+
+
+/**
+ Read data from a bufferevent buffer.
+
+ The bufferevent_read() function is used to read data from the input buffer.
+
+ @param bufev the bufferevent to be read from
+ @param data pointer to a buffer that will store the data
+ @param size the size of the data buffer, in bytes
+ @return the amount of data read, in bytes.
+ */
+size_t bufferevent_read(struct bufferevent *bufev, void *data, size_t size);
+
+/**
+ Enable a bufferevent.
+
+ @param bufev the bufferevent to be enabled
+ @param event any combination of EV_READ | EV_WRITE.
+ @return 0 if successful, or -1 if an error occurred
+ @see bufferevent_disable()
+ */
+int bufferevent_enable(struct bufferevent *bufev, short event);
+
+
+/**
+ Disable a bufferevent.
+
+ @param bufev the bufferevent to be disabled
+ @param event any combination of EV_READ | EV_WRITE.
+ @return 0 if successful, or -1 if an error occurred
+ @see bufferevent_enable()
+ */
+int bufferevent_disable(struct bufferevent *bufev, short event);
+
+
+/**
+ Set the read and write timeout for a buffered event.
+
+ @param bufev the bufferevent to be modified
+ @param timeout_read the read timeout
+ @param timeout_write the write timeout
+ */
+void bufferevent_settimeout(struct bufferevent *bufev,
+ int timeout_read, int timeout_write);
+
+
+/**
+ Sets the watermarks for read and write events.
+
+ On input, a bufferevent does not invoke the user read callback unless
+ there is at least low watermark data in the buffer. If the read buffer
+ is beyond the high watermark, the buffevent stops reading from the network.
+
+ On output, the user write callback is invoked whenever the buffered data
+ falls below the low watermark.
+
+ @param bufev the bufferevent to be modified
+ @param events EV_READ, EV_WRITE or both
+ @param lowmark the lower watermark to set
+ @param highmark the high watermark to set
+*/
+
+void bufferevent_setwatermark(struct bufferevent *bufev, short events,
+ size_t lowmark, size_t highmark);
+
+#define EVBUFFER_LENGTH(x) (x)->off
+#define EVBUFFER_DATA(x) (x)->buffer
+#define EVBUFFER_INPUT(x) (x)->input
+#define EVBUFFER_OUTPUT(x) (x)->output
+
+
+/**
+ Allocate storage for a new evbuffer.
+
+ @return a pointer to a newly allocated evbuffer struct, or NULL if an error
+ occurred
+ */
+struct evbuffer *evbuffer_new(void);
+
+
+/**
+ Deallocate storage for an evbuffer.
+
+ @param pointer to the evbuffer to be freed
+ */
+void evbuffer_free(struct evbuffer *);
+
+
+/**
+ Expands the available space in an event buffer.
+
+ Expands the available space in the event buffer to at least datlen
+
+ @param buf the event buffer to be expanded
+ @param datlen the new minimum length requirement
+ @return 0 if successful, or -1 if an error occurred
+*/
+int evbuffer_expand(struct evbuffer *, size_t);
+
+
+/**
+ Append data to the end of an evbuffer.
+
+ @param buf the event buffer to be appended to
+ @param data pointer to the beginning of the data buffer
+ @param datlen the number of bytes to be copied from the data buffer
+ */
+int evbuffer_add(struct evbuffer *, const void *, size_t);
+
+
+
+/**
+ Read data from an event buffer and drain the bytes read.
+
+ @param buf the event buffer to be read from
+ @param data the destination buffer to store the result
+ @param datlen the maximum size of the destination buffer
+ @return the number of bytes read
+ */
+int evbuffer_remove(struct evbuffer *, void *, size_t);
+
+
+/**
+ * Read a single line from an event buffer.
+ *
+ * Reads a line terminated by either '\r\n', '\n\r' or '\r' or '\n'.
+ * The returned buffer needs to be freed by the caller.
+ *
+ * @param buffer the evbuffer to read from
+ * @return pointer to a single line, or NULL if an error occurred
+ */
+char *evbuffer_readline(struct evbuffer *);
+
+
+/** Used to tell evbuffer_readln what kind of line-ending to look for.
+ */
+enum evbuffer_eol_style {
+ /** Any sequence of CR and LF characters is acceptable as an EOL. */
+ EVBUFFER_EOL_ANY,
+ /** An EOL is an LF, optionally preceded by a CR. This style is
+ * most useful for implementing text-based internet protocols. */
+ EVBUFFER_EOL_CRLF,
+ /** An EOL is a CR followed by an LF. */
+ EVBUFFER_EOL_CRLF_STRICT,
+ /** An EOL is a LF. */
+ EVBUFFER_EOL_LF
+};
+
+/**
+ * Read a single line from an event buffer.
+ *
+ * Reads a line terminated by an EOL as determined by the evbuffer_eol_style
+ * argument. Returns a newly allocated nul-terminated string; the caller must
+ * free the returned value. The EOL is not included in the returned string.
+ *
+ * @param buffer the evbuffer to read from
+ * @param n_read_out if non-NULL, points to a size_t that is set to the
+ * number of characters in the returned string. This is useful for
+ * strings that can contain NUL characters.
+ * @param eol_style the style of line-ending to use.
+ * @return pointer to a single line, or NULL if an error occurred
+ */
+char *evbuffer_readln(struct evbuffer *buffer, size_t *n_read_out,
+ enum evbuffer_eol_style eol_style);
+
+
+/**
+ Move data from one evbuffer into another evbuffer.
+
+ This is a destructive add. The data from one buffer moves into
+ the other buffer. The destination buffer is expanded as needed.
+
+ @param outbuf the output buffer
+ @param inbuf the input buffer
+ @return 0 if successful, or -1 if an error occurred
+ */
+int evbuffer_add_buffer(struct evbuffer *, struct evbuffer *);
+
+
+/**
+ Append a formatted string to the end of an evbuffer.
+
+ @param buf the evbuffer that will be appended to
+ @param fmt a format string
+ @param ... arguments that will be passed to printf(3)
+ @return The number of bytes added if successful, or -1 if an error occurred.
+ */
+int evbuffer_add_printf(struct evbuffer *, const char *fmt, ...)
+#ifdef __GNUC__
+ __attribute__((format(printf, 2, 3)))
+#endif
+;
+
+
+/**
+ Append a va_list formatted string to the end of an evbuffer.
+
+ @param buf the evbuffer that will be appended to
+ @param fmt a format string
+ @param ap a varargs va_list argument array that will be passed to vprintf(3)
+ @return The number of bytes added if successful, or -1 if an error occurred.
+ */
+int evbuffer_add_vprintf(struct evbuffer *, const char *fmt, va_list ap);
+
+
+/**
+ Remove a specified number of bytes data from the beginning of an evbuffer.
+
+ @param buf the evbuffer to be drained
+ @param len the number of bytes to drain from the beginning of the buffer
+ */
+void evbuffer_drain(struct evbuffer *, size_t);
+
+
+/**
+ Write the contents of an evbuffer to a file descriptor.
+
+ The evbuffer will be drained after the bytes have been successfully written.
+
+ @param buffer the evbuffer to be written and drained
+ @param fd the file descriptor to be written to
+ @return the number of bytes written, or -1 if an error occurred
+ @see evbuffer_read()
+ */
+int evbuffer_write(struct evbuffer *, int);
+
+
+/**
+ Read from a file descriptor and store the result in an evbuffer.
+
+ @param buf the evbuffer to store the result
+ @param fd the file descriptor to read from
+ @param howmuch the number of bytes to be read
+ @return the number of bytes read, or -1 if an error occurred
+ @see evbuffer_write()
+ */
+int evbuffer_read(struct evbuffer *, int, int);
+
+
+/**
+ Find a string within an evbuffer.
+
+ @param buffer the evbuffer to be searched
+ @param what the string to be searched for
+ @param len the length of the search string
+ @return a pointer to the beginning of the search string, or NULL if the search failed.
+ */
+u_char *evbuffer_find(struct evbuffer *, const u_char *, size_t);
+
+/**
+ Set a callback to invoke when the evbuffer is modified.
+
+ @param buffer the evbuffer to be monitored
+ @param cb the callback function to invoke when the evbuffer is modified
+ @param cbarg an argument to be provided to the callback function
+ */
+void evbuffer_setcb(struct evbuffer *, void (*)(struct evbuffer *, size_t, size_t, void *), void *);
+
+/*
+ * Marshaling tagged data - We assume that all tags are inserted in their
+ * numeric order - so that unknown tags will always be higher than the
+ * known ones - and we can just ignore the end of an event buffer.
+ */
+
+void evtag_init(void);
+
+void evtag_marshal(struct evbuffer *evbuf, ev_uint32_t tag, const void *data,
+ ev_uint32_t len);
+
+/**
+ Encode an integer and store it in an evbuffer.
+
+ We encode integer's by nibbles; the first nibble contains the number
+ of significant nibbles - 1; this allows us to encode up to 64-bit
+ integers. This function is byte-order independent.
+
+ @param evbuf evbuffer to store the encoded number
+ @param number a 32-bit integer
+ */
+void encode_int(struct evbuffer *evbuf, ev_uint32_t number);
+
+void evtag_marshal_int(struct evbuffer *evbuf, ev_uint32_t tag,
+ ev_uint32_t integer);
+
+void evtag_marshal_string(struct evbuffer *buf, ev_uint32_t tag,
+ const char *string);
+
+void evtag_marshal_timeval(struct evbuffer *evbuf, ev_uint32_t tag,
+ struct timeval *tv);
+
+int evtag_unmarshal(struct evbuffer *src, ev_uint32_t *ptag,
+ struct evbuffer *dst);
+int evtag_peek(struct evbuffer *evbuf, ev_uint32_t *ptag);
+int evtag_peek_length(struct evbuffer *evbuf, ev_uint32_t *plength);
+int evtag_payload_length(struct evbuffer *evbuf, ev_uint32_t *plength);
+int evtag_consume(struct evbuffer *evbuf);
+
+int evtag_unmarshal_int(struct evbuffer *evbuf, ev_uint32_t need_tag,
+ ev_uint32_t *pinteger);
+
+int evtag_unmarshal_fixed(struct evbuffer *src, ev_uint32_t need_tag,
+ void *data, size_t len);
+
+int evtag_unmarshal_string(struct evbuffer *evbuf, ev_uint32_t need_tag,
+ char **pstring);
+
+int evtag_unmarshal_timeval(struct evbuffer *evbuf, ev_uint32_t need_tag,
+ struct timeval *ptv);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _EVENT_H_ */
diff --git a/chromium/base/third_party/libevent/event_rpcgen.py b/chromium/base/third_party/libevent/event_rpcgen.py
new file mode 100755
index 00000000000..4ec77a6f6e3
--- /dev/null
+++ b/chromium/base/third_party/libevent/event_rpcgen.py
@@ -0,0 +1,1423 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2005 Niels Provos <provos@citi.umich.edu>
+# All rights reserved.
+#
+# Generates marshaling code based on libevent.
+
+import sys
+import re
+
+#
+_NAME = "event_rpcgen.py"
+_VERSION = "0.1"
+_STRUCT_RE = '[a-z][a-z_0-9]*'
+
+# Globals
+line_count = 0
+
+white = re.compile(r'^\s+')
+cppcomment = re.compile(r'\/\/.*$')
+headerdirect = []
+cppdirect = []
+
+# Holds everything that makes a struct
+class Struct:
+ def __init__(self, name):
+ self._name = name
+ self._entries = []
+ self._tags = {}
+ print >>sys.stderr, ' Created struct: %s' % name
+
+ def AddEntry(self, entry):
+ if self._tags.has_key(entry.Tag()):
+ print >>sys.stderr, ( 'Entry "%s" duplicates tag number '
+ '%d from "%s" around line %d' ) % (
+ entry.Name(), entry.Tag(),
+ self._tags[entry.Tag()], line_count)
+ sys.exit(1)
+ self._entries.append(entry)
+ self._tags[entry.Tag()] = entry.Name()
+ print >>sys.stderr, ' Added entry: %s' % entry.Name()
+
+ def Name(self):
+ return self._name
+
+ def EntryTagName(self, entry):
+ """Creates the name inside an enumeration for distinguishing data
+ types."""
+ name = "%s_%s" % (self._name, entry.Name())
+ return name.upper()
+
+ def PrintIdented(self, file, ident, code):
+ """Takes an array, add indentation to each entry and prints it."""
+ for entry in code:
+ print >>file, '%s%s' % (ident, entry)
+
+ def PrintTags(self, file):
+ """Prints the tag definitions for a structure."""
+ print >>file, '/* Tag definition for %s */' % self._name
+ print >>file, 'enum %s_ {' % self._name.lower()
+ for entry in self._entries:
+ print >>file, ' %s=%d,' % (self.EntryTagName(entry),
+ entry.Tag())
+ print >>file, ' %s_MAX_TAGS' % (self._name.upper())
+ print >>file, '};\n'
+
+ def PrintForwardDeclaration(self, file):
+ print >>file, 'struct %s;' % self._name
+
+ def PrintDeclaration(self, file):
+ print >>file, '/* Structure declaration for %s */' % self._name
+ print >>file, 'struct %s_access_ {' % self._name
+ for entry in self._entries:
+ dcl = entry.AssignDeclaration('(*%s_assign)' % entry.Name())
+ dcl.extend(
+ entry.GetDeclaration('(*%s_get)' % entry.Name()))
+ if entry.Array():
+ dcl.extend(
+ entry.AddDeclaration('(*%s_add)' % entry.Name()))
+ self.PrintIdented(file, ' ', dcl)
+ print >>file, '};\n'
+
+ print >>file, 'struct %s {' % self._name
+ print >>file, ' struct %s_access_ *base;\n' % self._name
+ for entry in self._entries:
+ dcl = entry.Declaration()
+ self.PrintIdented(file, ' ', dcl)
+ print >>file, ''
+ for entry in self._entries:
+ print >>file, ' ev_uint8_t %s_set;' % entry.Name()
+ print >>file, '};\n'
+
+ print >>file, \
+"""struct %(name)s *%(name)s_new(void);
+void %(name)s_free(struct %(name)s *);
+void %(name)s_clear(struct %(name)s *);
+void %(name)s_marshal(struct evbuffer *, const struct %(name)s *);
+int %(name)s_unmarshal(struct %(name)s *, struct evbuffer *);
+int %(name)s_complete(struct %(name)s *);
+void evtag_marshal_%(name)s(struct evbuffer *, ev_uint32_t,
+ const struct %(name)s *);
+int evtag_unmarshal_%(name)s(struct evbuffer *, ev_uint32_t,
+ struct %(name)s *);""" % { 'name' : self._name }
+
+
+ # Write a setting function of every variable
+ for entry in self._entries:
+ self.PrintIdented(file, '', entry.AssignDeclaration(
+ entry.AssignFuncName()))
+ self.PrintIdented(file, '', entry.GetDeclaration(
+ entry.GetFuncName()))
+ if entry.Array():
+ self.PrintIdented(file, '', entry.AddDeclaration(
+ entry.AddFuncName()))
+
+ print >>file, '/* --- %s done --- */\n' % self._name
+
+ def PrintCode(self, file):
+ print >>file, ('/*\n'
+ ' * Implementation of %s\n'
+ ' */\n') % self._name
+
+ print >>file, \
+ 'static struct %(name)s_access_ __%(name)s_base = {' % \
+ { 'name' : self._name }
+ for entry in self._entries:
+ self.PrintIdented(file, ' ', entry.CodeBase())
+ print >>file, '};\n'
+
+ # Creation
+ print >>file, (
+ 'struct %(name)s *\n'
+ '%(name)s_new(void)\n'
+ '{\n'
+ ' struct %(name)s *tmp;\n'
+ ' if ((tmp = malloc(sizeof(struct %(name)s))) == NULL) {\n'
+ ' event_warn("%%s: malloc", __func__);\n'
+ ' return (NULL);\n'
+ ' }\n'
+ ' tmp->base = &__%(name)s_base;\n') % { 'name' : self._name }
+
+ for entry in self._entries:
+ self.PrintIdented(file, ' ', entry.CodeNew('tmp'))
+ print >>file, ' tmp->%s_set = 0;\n' % entry.Name()
+
+ print >>file, (
+ ' return (tmp);\n'
+ '}\n')
+
+ # Adding
+ for entry in self._entries:
+ if entry.Array():
+ self.PrintIdented(file, '', entry.CodeAdd())
+ print >>file, ''
+
+ # Assigning
+ for entry in self._entries:
+ self.PrintIdented(file, '', entry.CodeAssign())
+ print >>file, ''
+
+ # Getting
+ for entry in self._entries:
+ self.PrintIdented(file, '', entry.CodeGet())
+ print >>file, ''
+
+ # Clearing
+ print >>file, ( 'void\n'
+ '%(name)s_clear(struct %(name)s *tmp)\n'
+ '{'
+ ) % { 'name' : self._name }
+ for entry in self._entries:
+ self.PrintIdented(file, ' ', entry.CodeClear('tmp'))
+
+ print >>file, '}\n'
+
+ # Freeing
+ print >>file, ( 'void\n'
+ '%(name)s_free(struct %(name)s *tmp)\n'
+ '{'
+ ) % { 'name' : self._name }
+
+ for entry in self._entries:
+ self.PrintIdented(file, ' ', entry.CodeFree('tmp'))
+
+ print >>file, (' free(tmp);\n'
+ '}\n')
+
+ # Marshaling
+ print >>file, ('void\n'
+ '%(name)s_marshal(struct evbuffer *evbuf, '
+ 'const struct %(name)s *tmp)'
+ '{') % { 'name' : self._name }
+ for entry in self._entries:
+ indent = ' '
+ # Optional entries do not have to be set
+ if entry.Optional():
+ indent += ' '
+ print >>file, ' if (tmp->%s_set) {' % entry.Name()
+ self.PrintIdented(
+ file, indent,
+ entry.CodeMarshal('evbuf', self.EntryTagName(entry), 'tmp'))
+ if entry.Optional():
+ print >>file, ' }'
+
+ print >>file, '}\n'
+
+ # Unmarshaling
+ print >>file, ('int\n'
+ '%(name)s_unmarshal(struct %(name)s *tmp, '
+ ' struct evbuffer *evbuf)\n'
+ '{\n'
+ ' ev_uint32_t tag;\n'
+ ' while (EVBUFFER_LENGTH(evbuf) > 0) {\n'
+ ' if (evtag_peek(evbuf, &tag) == -1)\n'
+ ' return (-1);\n'
+ ' switch (tag) {\n'
+ ) % { 'name' : self._name }
+ for entry in self._entries:
+ print >>file, ' case %s:\n' % self.EntryTagName(entry)
+ if not entry.Array():
+ print >>file, (
+ ' if (tmp->%s_set)\n'
+ ' return (-1);'
+ ) % (entry.Name())
+
+ self.PrintIdented(
+ file, ' ',
+ entry.CodeUnmarshal('evbuf',
+ self.EntryTagName(entry), 'tmp'))
+
+ print >>file, ( ' tmp->%s_set = 1;\n' % entry.Name() +
+ ' break;\n' )
+ print >>file, ( ' default:\n'
+ ' return -1;\n'
+ ' }\n'
+ ' }\n' )
+ # Check if it was decoded completely
+ print >>file, ( ' if (%(name)s_complete(tmp) == -1)\n'
+ ' return (-1);'
+ ) % { 'name' : self._name }
+
+ # Successfully decoded
+ print >>file, ( ' return (0);\n'
+ '}\n')
+
+ # Checking if a structure has all the required data
+ print >>file, (
+ 'int\n'
+ '%(name)s_complete(struct %(name)s *msg)\n'
+ '{' ) % { 'name' : self._name }
+ for entry in self._entries:
+ self.PrintIdented(
+ file, ' ',
+ entry.CodeComplete('msg'))
+ print >>file, (
+ ' return (0);\n'
+ '}\n' )
+
+ # Complete message unmarshaling
+ print >>file, (
+ 'int\n'
+ 'evtag_unmarshal_%(name)s(struct evbuffer *evbuf, '
+ 'ev_uint32_t need_tag, struct %(name)s *msg)\n'
+ '{\n'
+ ' ev_uint32_t tag;\n'
+ ' int res = -1;\n'
+ '\n'
+ ' struct evbuffer *tmp = evbuffer_new();\n'
+ '\n'
+ ' if (evtag_unmarshal(evbuf, &tag, tmp) == -1'
+ ' || tag != need_tag)\n'
+ ' goto error;\n'
+ '\n'
+ ' if (%(name)s_unmarshal(msg, tmp) == -1)\n'
+ ' goto error;\n'
+ '\n'
+ ' res = 0;\n'
+ '\n'
+ ' error:\n'
+ ' evbuffer_free(tmp);\n'
+ ' return (res);\n'
+ '}\n' ) % { 'name' : self._name }
+
+ # Complete message marshaling
+ print >>file, (
+ 'void\n'
+ 'evtag_marshal_%(name)s(struct evbuffer *evbuf, ev_uint32_t tag, '
+ 'const struct %(name)s *msg)\n'
+ '{\n'
+ ' struct evbuffer *_buf = evbuffer_new();\n'
+ ' assert(_buf != NULL);\n'
+ ' evbuffer_drain(_buf, -1);\n'
+ ' %(name)s_marshal(_buf, msg);\n'
+ ' evtag_marshal(evbuf, tag, EVBUFFER_DATA(_buf), '
+ 'EVBUFFER_LENGTH(_buf));\n'
+ ' evbuffer_free(_buf);\n'
+ '}\n' ) % { 'name' : self._name }
+
+class Entry:
+ def __init__(self, type, name, tag):
+ self._type = type
+ self._name = name
+ self._tag = int(tag)
+ self._ctype = type
+ self._optional = 0
+ self._can_be_array = 0
+ self._array = 0
+ self._line_count = -1
+ self._struct = None
+ self._refname = None
+
+ def GetTranslation(self):
+ return { "parent_name" : self._struct.Name(),
+ "name" : self._name,
+ "ctype" : self._ctype,
+ "refname" : self._refname
+ }
+
+ def SetStruct(self, struct):
+ self._struct = struct
+
+ def LineCount(self):
+ assert self._line_count != -1
+ return self._line_count
+
+ def SetLineCount(self, number):
+ self._line_count = number
+
+ def Array(self):
+ return self._array
+
+ def Optional(self):
+ return self._optional
+
+ def Tag(self):
+ return self._tag
+
+ def Name(self):
+ return self._name
+
+ def Type(self):
+ return self._type
+
+ def MakeArray(self, yes=1):
+ self._array = yes
+
+ def MakeOptional(self):
+ self._optional = 1
+
+ def GetFuncName(self):
+ return '%s_%s_get' % (self._struct.Name(), self._name)
+
+ def GetDeclaration(self, funcname):
+ code = [ 'int %s(struct %s *, %s *);' % (
+ funcname, self._struct.Name(), self._ctype ) ]
+ return code
+
+ def CodeGet(self):
+ code = (
+ 'int',
+ '%(parent_name)s_%(name)s_get(struct %(parent_name)s *msg, '
+ '%(ctype)s *value)',
+ '{',
+ ' if (msg->%(name)s_set != 1)',
+ ' return (-1);',
+ ' *value = msg->%(name)s_data;',
+ ' return (0);',
+ '}' )
+ code = '\n'.join(code)
+ code = code % self.GetTranslation()
+ return code.split('\n')
+
+ def AssignFuncName(self):
+ return '%s_%s_assign' % (self._struct.Name(), self._name)
+
+ def AddFuncName(self):
+ return '%s_%s_add' % (self._struct.Name(), self._name)
+
+ def AssignDeclaration(self, funcname):
+ code = [ 'int %s(struct %s *, const %s);' % (
+ funcname, self._struct.Name(), self._ctype ) ]
+ return code
+
+ def CodeAssign(self):
+ code = [ 'int',
+ '%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg,'
+ ' const %(ctype)s value)',
+ '{',
+ ' msg->%(name)s_set = 1;',
+ ' msg->%(name)s_data = value;',
+ ' return (0);',
+ '}' ]
+ code = '\n'.join(code)
+ code = code % self.GetTranslation()
+ return code.split('\n')
+
+ def CodeClear(self, structname):
+ code = [ '%s->%s_set = 0;' % (structname, self.Name()) ]
+
+ return code
+
+ def CodeComplete(self, structname):
+ if self.Optional():
+ return []
+
+ code = [ 'if (!%s->%s_set)' % (structname, self.Name()),
+ ' return (-1);' ]
+
+ return code
+
+ def CodeFree(self, name):
+ return []
+
+ def CodeBase(self):
+ code = [
+ '%(parent_name)s_%(name)s_assign,',
+ '%(parent_name)s_%(name)s_get,'
+ ]
+ if self.Array():
+ code.append('%(parent_name)s_%(name)s_add,')
+
+ code = '\n'.join(code)
+ code = code % self.GetTranslation()
+ return code.split('\n')
+
+ def Verify(self):
+ if self.Array() and not self._can_be_array:
+ print >>sys.stderr, (
+ 'Entry "%s" cannot be created as an array '
+ 'around line %d' ) % (self._name, self.LineCount())
+ sys.exit(1)
+ if not self._struct:
+ print >>sys.stderr, (
+ 'Entry "%s" does not know which struct it belongs to '
+ 'around line %d' ) % (self._name, self.LineCount())
+ sys.exit(1)
+ if self._optional and self._array:
+ print >>sys.stderr, ( 'Entry "%s" has illegal combination of '
+ 'optional and array around line %d' ) % (
+ self._name, self.LineCount() )
+ sys.exit(1)
+
+class EntryBytes(Entry):
+ def __init__(self, type, name, tag, length):
+ # Init base class
+ Entry.__init__(self, type, name, tag)
+
+ self._length = length
+ self._ctype = 'ev_uint8_t'
+
+ def GetDeclaration(self, funcname):
+ code = [ 'int %s(struct %s *, %s **);' % (
+ funcname, self._struct.Name(), self._ctype ) ]
+ return code
+
+ def AssignDeclaration(self, funcname):
+ code = [ 'int %s(struct %s *, const %s *);' % (
+ funcname, self._struct.Name(), self._ctype ) ]
+ return code
+
+ def Declaration(self):
+ dcl = ['ev_uint8_t %s_data[%s];' % (self._name, self._length)]
+
+ return dcl
+
+ def CodeGet(self):
+ name = self._name
+ code = [ 'int',
+ '%s_%s_get(struct %s *msg, %s **value)' % (
+ self._struct.Name(), name,
+ self._struct.Name(), self._ctype),
+ '{',
+ ' if (msg->%s_set != 1)' % name,
+ ' return (-1);',
+ ' *value = msg->%s_data;' % name,
+ ' return (0);',
+ '}' ]
+ return code
+
+ def CodeAssign(self):
+ name = self._name
+ code = [ 'int',
+ '%s_%s_assign(struct %s *msg, const %s *value)' % (
+ self._struct.Name(), name,
+ self._struct.Name(), self._ctype),
+ '{',
+ ' msg->%s_set = 1;' % name,
+ ' memcpy(msg->%s_data, value, %s);' % (
+ name, self._length),
+ ' return (0);',
+ '}' ]
+ return code
+
+ def CodeUnmarshal(self, buf, tag_name, var_name):
+ code = [ 'if (evtag_unmarshal_fixed(%s, %s, ' % (buf, tag_name) +
+ '%s->%s_data, ' % (var_name, self._name) +
+ 'sizeof(%s->%s_data)) == -1) {' % (
+ var_name, self._name),
+ ' event_warnx("%%s: failed to unmarshal %s", __func__);' % (
+ self._name ),
+ ' return (-1);',
+ '}'
+ ]
+ return code
+
+ def CodeMarshal(self, buf, tag_name, var_name):
+ code = ['evtag_marshal(%s, %s, %s->%s_data, sizeof(%s->%s_data));' % (
+ buf, tag_name, var_name, self._name, var_name, self._name )]
+ return code
+
+ def CodeClear(self, structname):
+ code = [ '%s->%s_set = 0;' % (structname, self.Name()),
+ 'memset(%s->%s_data, 0, sizeof(%s->%s_data));' % (
+ structname, self._name, structname, self._name)]
+
+ return code
+
+ def CodeNew(self, name):
+ code = ['memset(%s->%s_data, 0, sizeof(%s->%s_data));' % (
+ name, self._name, name, self._name)]
+ return code
+
+ def Verify(self):
+ if not self._length:
+ print >>sys.stderr, 'Entry "%s" needs a length around line %d' % (
+ self._name, self.LineCount() )
+ sys.exit(1)
+
+ Entry.Verify(self)
+
+class EntryInt(Entry):
+ def __init__(self, type, name, tag):
+ # Init base class
+ Entry.__init__(self, type, name, tag)
+
+ self._ctype = 'ev_uint32_t'
+
+ def CodeUnmarshal(self, buf, tag_name, var_name):
+ code = ['if (evtag_unmarshal_int(%s, %s, &%s->%s_data) == -1) {' % (
+ buf, tag_name, var_name, self._name),
+ ' event_warnx("%%s: failed to unmarshal %s", __func__);' % (
+ self._name ),
+ ' return (-1);',
+ '}' ]
+ return code
+
+ def CodeMarshal(self, buf, tag_name, var_name):
+ code = ['evtag_marshal_int(%s, %s, %s->%s_data);' % (
+ buf, tag_name, var_name, self._name)]
+ return code
+
+ def Declaration(self):
+ dcl = ['ev_uint32_t %s_data;' % self._name]
+
+ return dcl
+
+ def CodeNew(self, name):
+ code = ['%s->%s_data = 0;' % (name, self._name)]
+ return code
+
+class EntryString(Entry):
+ def __init__(self, type, name, tag):
+ # Init base class
+ Entry.__init__(self, type, name, tag)
+
+ self._ctype = 'char *'
+
+ def CodeAssign(self):
+ name = self._name
+ code = """int
+%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg,
+ const %(ctype)s value)
+{
+ if (msg->%(name)s_data != NULL)
+ free(msg->%(name)s_data);
+ if ((msg->%(name)s_data = strdup(value)) == NULL)
+ return (-1);
+ msg->%(name)s_set = 1;
+ return (0);
+}""" % self.GetTranslation()
+
+ return code.split('\n')
+
+ def CodeUnmarshal(self, buf, tag_name, var_name):
+ code = ['if (evtag_unmarshal_string(%s, %s, &%s->%s_data) == -1) {' % (
+ buf, tag_name, var_name, self._name),
+ ' event_warnx("%%s: failed to unmarshal %s", __func__);' % (
+ self._name ),
+ ' return (-1);',
+ '}'
+ ]
+ return code
+
+ def CodeMarshal(self, buf, tag_name, var_name):
+ code = ['evtag_marshal_string(%s, %s, %s->%s_data);' % (
+ buf, tag_name, var_name, self._name)]
+ return code
+
+ def CodeClear(self, structname):
+ code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()),
+ ' free (%s->%s_data);' % (structname, self.Name()),
+ ' %s->%s_data = NULL;' % (structname, self.Name()),
+ ' %s->%s_set = 0;' % (structname, self.Name()),
+ '}'
+ ]
+
+ return code
+
+ def CodeNew(self, name):
+ code = ['%s->%s_data = NULL;' % (name, self._name)]
+ return code
+
+ def CodeFree(self, name):
+ code = ['if (%s->%s_data != NULL)' % (name, self._name),
+ ' free (%s->%s_data); ' % (name, self._name)]
+
+ return code
+
+ def Declaration(self):
+ dcl = ['char *%s_data;' % self._name]
+
+ return dcl
+
+class EntryStruct(Entry):
+ def __init__(self, type, name, tag, refname):
+ # Init base class
+ Entry.__init__(self, type, name, tag)
+
+ self._can_be_array = 1
+ self._refname = refname
+ self._ctype = 'struct %s*' % refname
+
+ def CodeGet(self):
+ name = self._name
+ code = [ 'int',
+ '%s_%s_get(struct %s *msg, %s *value)' % (
+ self._struct.Name(), name,
+ self._struct.Name(), self._ctype),
+ '{',
+ ' if (msg->%s_set != 1) {' % name,
+ ' msg->%s_data = %s_new();' % (name, self._refname),
+ ' if (msg->%s_data == NULL)' % name,
+ ' return (-1);',
+ ' msg->%s_set = 1;' % name,
+ ' }',
+ ' *value = msg->%s_data;' % name,
+ ' return (0);',
+ '}' ]
+ return code
+
+ def CodeAssign(self):
+ name = self._name
+ code = """int
+%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg,
+ const %(ctype)s value)
+{
+ struct evbuffer *tmp = NULL;
+ if (msg->%(name)s_set) {
+ %(refname)s_clear(msg->%(name)s_data);
+ msg->%(name)s_set = 0;
+ } else {
+ msg->%(name)s_data = %(refname)s_new();
+ if (msg->%(name)s_data == NULL) {
+ event_warn("%%s: %(refname)s_new()", __func__);
+ goto error;
+ }
+ }
+ if ((tmp = evbuffer_new()) == NULL) {
+ event_warn("%%s: evbuffer_new()", __func__);
+ goto error;
+ }
+ %(refname)s_marshal(tmp, value);
+ if (%(refname)s_unmarshal(msg->%(name)s_data, tmp) == -1) {
+ event_warnx("%%s: %(refname)s_unmarshal", __func__);
+ goto error;
+ }
+ msg->%(name)s_set = 1;
+ evbuffer_free(tmp);
+ return (0);
+ error:
+ if (tmp != NULL)
+ evbuffer_free(tmp);
+ if (msg->%(name)s_data != NULL) {
+ %(refname)s_free(msg->%(name)s_data);
+ msg->%(name)s_data = NULL;
+ }
+ return (-1);
+}""" % self.GetTranslation()
+ return code.split('\n')
+
+ def CodeComplete(self, structname):
+ if self.Optional():
+ code = [ 'if (%s->%s_set && %s_complete(%s->%s_data) == -1)' % (
+ structname, self.Name(),
+ self._refname, structname, self.Name()),
+ ' return (-1);' ]
+ else:
+ code = [ 'if (%s_complete(%s->%s_data) == -1)' % (
+ self._refname, structname, self.Name()),
+ ' return (-1);' ]
+
+ return code
+
+ def CodeUnmarshal(self, buf, tag_name, var_name):
+ code = ['%s->%s_data = %s_new();' % (
+ var_name, self._name, self._refname),
+ 'if (%s->%s_data == NULL)' % (var_name, self._name),
+ ' return (-1);',
+ 'if (evtag_unmarshal_%s(%s, %s, %s->%s_data) == -1) {' % (
+ self._refname, buf, tag_name, var_name, self._name),
+ ' event_warnx("%%s: failed to unmarshal %s", __func__);' % (
+ self._name ),
+ ' return (-1);',
+ '}'
+ ]
+ return code
+
+ def CodeMarshal(self, buf, tag_name, var_name):
+ code = ['evtag_marshal_%s(%s, %s, %s->%s_data);' % (
+ self._refname, buf, tag_name, var_name, self._name)]
+ return code
+
+ def CodeClear(self, structname):
+ code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()),
+ ' %s_free(%s->%s_data);' % (
+ self._refname, structname, self.Name()),
+ ' %s->%s_data = NULL;' % (structname, self.Name()),
+ ' %s->%s_set = 0;' % (structname, self.Name()),
+ '}'
+ ]
+
+ return code
+
+ def CodeNew(self, name):
+ code = ['%s->%s_data = NULL;' % (name, self._name)]
+ return code
+
+ def CodeFree(self, name):
+ code = ['if (%s->%s_data != NULL)' % (name, self._name),
+ ' %s_free(%s->%s_data); ' % (
+ self._refname, name, self._name)]
+
+ return code
+
+ def Declaration(self):
+ dcl = ['%s %s_data;' % (self._ctype, self._name)]
+
+ return dcl
+
+class EntryVarBytes(Entry):
+ def __init__(self, type, name, tag):
+ # Init base class
+ Entry.__init__(self, type, name, tag)
+
+ self._ctype = 'ev_uint8_t *'
+
+ def GetDeclaration(self, funcname):
+ code = [ 'int %s(struct %s *, %s *, ev_uint32_t *);' % (
+ funcname, self._struct.Name(), self._ctype ) ]
+ return code
+
+ def AssignDeclaration(self, funcname):
+ code = [ 'int %s(struct %s *, const %s, ev_uint32_t);' % (
+ funcname, self._struct.Name(), self._ctype ) ]
+ return code
+
+ def CodeAssign(self):
+ name = self._name
+ code = [ 'int',
+ '%s_%s_assign(struct %s *msg, '
+ 'const %s value, ev_uint32_t len)' % (
+ self._struct.Name(), name,
+ self._struct.Name(), self._ctype),
+ '{',
+ ' if (msg->%s_data != NULL)' % name,
+ ' free (msg->%s_data);' % name,
+ ' msg->%s_data = malloc(len);' % name,
+ ' if (msg->%s_data == NULL)' % name,
+ ' return (-1);',
+ ' msg->%s_set = 1;' % name,
+ ' msg->%s_length = len;' % name,
+ ' memcpy(msg->%s_data, value, len);' % name,
+ ' return (0);',
+ '}' ]
+ return code
+
+ def CodeGet(self):
+ name = self._name
+ code = [ 'int',
+ '%s_%s_get(struct %s *msg, %s *value, ev_uint32_t *plen)' % (
+ self._struct.Name(), name,
+ self._struct.Name(), self._ctype),
+ '{',
+ ' if (msg->%s_set != 1)' % name,
+ ' return (-1);',
+ ' *value = msg->%s_data;' % name,
+ ' *plen = msg->%s_length;' % name,
+ ' return (0);',
+ '}' ]
+ return code
+
+ def CodeUnmarshal(self, buf, tag_name, var_name):
+ code = ['if (evtag_payload_length(%s, &%s->%s_length) == -1)' % (
+ buf, var_name, self._name),
+ ' return (-1);',
+ # We do not want DoS opportunities
+ 'if (%s->%s_length > EVBUFFER_LENGTH(%s))' % (
+ var_name, self._name, buf),
+ ' return (-1);',
+ 'if ((%s->%s_data = malloc(%s->%s_length)) == NULL)' % (
+ var_name, self._name, var_name, self._name),
+ ' return (-1);',
+ 'if (evtag_unmarshal_fixed(%s, %s, %s->%s_data, '
+ '%s->%s_length) == -1) {' % (
+ buf, tag_name, var_name, self._name, var_name, self._name),
+ ' event_warnx("%%s: failed to unmarshal %s", __func__);' % (
+ self._name ),
+ ' return (-1);',
+ '}'
+ ]
+ return code
+
+ def CodeMarshal(self, buf, tag_name, var_name):
+ code = ['evtag_marshal(%s, %s, %s->%s_data, %s->%s_length);' % (
+ buf, tag_name, var_name, self._name, var_name, self._name)]
+ return code
+
+ def CodeClear(self, structname):
+ code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()),
+ ' free (%s->%s_data);' % (structname, self.Name()),
+ ' %s->%s_data = NULL;' % (structname, self.Name()),
+ ' %s->%s_length = 0;' % (structname, self.Name()),
+ ' %s->%s_set = 0;' % (structname, self.Name()),
+ '}'
+ ]
+
+ return code
+
+ def CodeNew(self, name):
+ code = ['%s->%s_data = NULL;' % (name, self._name),
+ '%s->%s_length = 0;' % (name, self._name) ]
+ return code
+
+ def CodeFree(self, name):
+ code = ['if (%s->%s_data != NULL)' % (name, self._name),
+ ' free (%s->%s_data); ' % (name, self._name)]
+
+ return code
+
+ def Declaration(self):
+ dcl = ['ev_uint8_t *%s_data;' % self._name,
+ 'ev_uint32_t %s_length;' % self._name]
+
+ return dcl
+
+class EntryArray(Entry):
+ def __init__(self, entry):
+ # Init base class
+ Entry.__init__(self, entry._type, entry._name, entry._tag)
+
+ self._entry = entry
+ self._refname = entry._refname
+ self._ctype = 'struct %s *' % self._refname
+
+ def GetDeclaration(self, funcname):
+ """Allows direct access to elements of the array."""
+ translate = self.GetTranslation()
+ translate["funcname"] = funcname
+ code = [
+ 'int %(funcname)s(struct %(parent_name)s *, int, %(ctype)s *);' %
+ translate ]
+ return code
+
+ def AssignDeclaration(self, funcname):
+ code = [ 'int %s(struct %s *, int, const %s);' % (
+ funcname, self._struct.Name(), self._ctype ) ]
+ return code
+
+ def AddDeclaration(self, funcname):
+ code = [ '%s %s(struct %s *);' % (
+ self._ctype, funcname, self._struct.Name() ) ]
+ return code
+
+ def CodeGet(self):
+ code = """int
+%(parent_name)s_%(name)s_get(struct %(parent_name)s *msg, int offset,
+ %(ctype)s *value)
+{
+ if (!msg->%(name)s_set || offset < 0 || offset >= msg->%(name)s_length)
+ return (-1);
+ *value = msg->%(name)s_data[offset];
+ return (0);
+}""" % self.GetTranslation()
+
+ return code.split('\n')
+
+ def CodeAssign(self):
+ code = """int
+%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg, int off,
+ const %(ctype)s value)
+{
+ struct evbuffer *tmp = NULL;
+ if (!msg->%(name)s_set || off < 0 || off >= msg->%(name)s_length)
+ return (-1);
+ %(refname)s_clear(msg->%(name)s_data[off]);
+ if ((tmp = evbuffer_new()) == NULL) {
+ event_warn("%%s: evbuffer_new()", __func__);
+ goto error;
+ }
+ %(refname)s_marshal(tmp, value);
+ if (%(refname)s_unmarshal(msg->%(name)s_data[off], tmp) == -1) {
+ event_warnx("%%s: %(refname)s_unmarshal", __func__);
+ goto error;
+ }
+ evbuffer_free(tmp);
+ return (0);
+error:
+ if (tmp != NULL)
+ evbuffer_free(tmp);
+ %(refname)s_clear(msg->%(name)s_data[off]);
+ return (-1);
+}""" % self.GetTranslation()
+
+ return code.split('\n')
+
+ def CodeAdd(self):
+ code = \
+"""%(ctype)s
+%(parent_name)s_%(name)s_add(struct %(parent_name)s *msg)
+{
+ if (++msg->%(name)s_length >= msg->%(name)s_num_allocated) {
+ int tobe_allocated = msg->%(name)s_num_allocated;
+ %(ctype)s* new_data = NULL;
+ tobe_allocated = !tobe_allocated ? 1 : tobe_allocated << 1;
+ new_data = (%(ctype)s*) realloc(msg->%(name)s_data,
+ tobe_allocated * sizeof(%(ctype)s));
+ if (new_data == NULL)
+ goto error;
+ msg->%(name)s_data = new_data;
+ msg->%(name)s_num_allocated = tobe_allocated;
+ }
+ msg->%(name)s_data[msg->%(name)s_length - 1] = %(refname)s_new();
+ if (msg->%(name)s_data[msg->%(name)s_length - 1] == NULL)
+ goto error;
+ msg->%(name)s_set = 1;
+ return (msg->%(name)s_data[msg->%(name)s_length - 1]);
+error:
+ --msg->%(name)s_length;
+ return (NULL);
+}
+ """ % self.GetTranslation()
+
+ return code.split('\n')
+
+ def CodeComplete(self, structname):
+ code = []
+ translate = self.GetTranslation()
+
+ if self.Optional():
+ code.append( 'if (%(structname)s->%(name)s_set)' % translate)
+
+ translate["structname"] = structname
+ tmp = """{
+ int i;
+ for (i = 0; i < %(structname)s->%(name)s_length; ++i) {
+ if (%(refname)s_complete(%(structname)s->%(name)s_data[i]) == -1)
+ return (-1);
+ }
+}""" % translate
+ code.extend(tmp.split('\n'))
+
+ return code
+
+ def CodeUnmarshal(self, buf, tag_name, var_name):
+ translate = self.GetTranslation()
+ translate["var_name"] = var_name
+ translate["buf"] = buf
+ translate["tag_name"] = tag_name
+ code = """if (%(parent_name)s_%(name)s_add(%(var_name)s) == NULL)
+ return (-1);
+if (evtag_unmarshal_%(refname)s(%(buf)s, %(tag_name)s,
+ %(var_name)s->%(name)s_data[%(var_name)s->%(name)s_length - 1]) == -1) {
+ --%(var_name)s->%(name)s_length;
+ event_warnx("%%s: failed to unmarshal %(name)s", __func__);
+ return (-1);
+}""" % translate
+
+ return code.split('\n')
+
+ def CodeMarshal(self, buf, tag_name, var_name):
+ code = ['{',
+ ' int i;',
+ ' for (i = 0; i < %s->%s_length; ++i) {' % (
+ var_name, self._name),
+ ' evtag_marshal_%s(%s, %s, %s->%s_data[i]);' % (
+ self._refname, buf, tag_name, var_name, self._name),
+ ' }',
+ '}'
+ ]
+ return code
+
+ def CodeClear(self, structname):
+ code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()),
+ ' int i;',
+ ' for (i = 0; i < %s->%s_length; ++i) {' % (
+ structname, self.Name()),
+ ' %s_free(%s->%s_data[i]);' % (
+ self._refname, structname, self.Name()),
+ ' }',
+ ' free(%s->%s_data);' % (structname, self.Name()),
+ ' %s->%s_data = NULL;' % (structname, self.Name()),
+ ' %s->%s_set = 0;' % (structname, self.Name()),
+ ' %s->%s_length = 0;' % (structname, self.Name()),
+ ' %s->%s_num_allocated = 0;' % (structname, self.Name()),
+ '}'
+ ]
+
+ return code
+
+ def CodeNew(self, name):
+ code = ['%s->%s_data = NULL;' % (name, self._name),
+ '%s->%s_length = 0;' % (name, self._name),
+ '%s->%s_num_allocated = 0;' % (name, self._name)]
+ return code
+
+ def CodeFree(self, name):
+ code = ['if (%s->%s_data != NULL) {' % (name, self._name),
+ ' int i;',
+ ' for (i = 0; i < %s->%s_length; ++i) {' % (
+ name, self._name),
+ ' %s_free(%s->%s_data[i]); ' % (
+ self._refname, name, self._name),
+ ' %s->%s_data[i] = NULL;' % (name, self._name),
+ ' }',
+ ' free(%s->%s_data);' % (name, self._name),
+ ' %s->%s_data = NULL;' % (name, self._name),
+ ' %s->%s_length = 0;' % (name, self._name),
+ ' %s->%s_num_allocated = 0;' % (name, self._name),
+ '}'
+ ]
+
+ return code
+
+ def Declaration(self):
+ dcl = ['struct %s **%s_data;' % (self._refname, self._name),
+ 'int %s_length;' % self._name,
+ 'int %s_num_allocated;' % self._name ]
+
+ return dcl
+
+def NormalizeLine(line):
+ global white
+ global cppcomment
+
+ line = cppcomment.sub('', line)
+ line = line.strip()
+ line = white.sub(' ', line)
+
+ return line
+
+def ProcessOneEntry(newstruct, entry):
+ optional = 0
+ array = 0
+ entry_type = ''
+ name = ''
+ tag = ''
+ tag_set = None
+ separator = ''
+ fixed_length = ''
+
+ tokens = entry.split(' ')
+ while tokens:
+ token = tokens[0]
+ tokens = tokens[1:]
+
+ if not entry_type:
+ if not optional and token == 'optional':
+ optional = 1
+ continue
+
+ if not array and token == 'array':
+ array = 1
+ continue
+
+ if not entry_type:
+ entry_type = token
+ continue
+
+ if not name:
+ res = re.match(r'^([^\[\]]+)(\[.*\])?$', token)
+ if not res:
+ print >>sys.stderr, 'Cannot parse name: \"%s\" around %d' % (
+ entry, line_count)
+ sys.exit(1)
+ name = res.group(1)
+ fixed_length = res.group(2)
+ if fixed_length:
+ fixed_length = fixed_length[1:-1]
+ continue
+
+ if not separator:
+ separator = token
+ if separator != '=':
+ print >>sys.stderr, 'Expected "=" after name \"%s\" got %s' % (
+ name, token)
+ sys.exit(1)
+ continue
+
+ if not tag_set:
+ tag_set = 1
+ if not re.match(r'^(0x)?[0-9]+$', token):
+ print >>sys.stderr, 'Expected tag number: \"%s\"' % entry
+ sys.exit(1)
+ tag = int(token, 0)
+ continue
+
+ print >>sys.stderr, 'Cannot parse \"%s\"' % entry
+ sys.exit(1)
+
+ if not tag_set:
+ print >>sys.stderr, 'Need tag number: \"%s\"' % entry
+ sys.exit(1)
+
+ # Create the right entry
+ if entry_type == 'bytes':
+ if fixed_length:
+ newentry = EntryBytes(entry_type, name, tag, fixed_length)
+ else:
+ newentry = EntryVarBytes(entry_type, name, tag)
+ elif entry_type == 'int' and not fixed_length:
+ newentry = EntryInt(entry_type, name, tag)
+ elif entry_type == 'string' and not fixed_length:
+ newentry = EntryString(entry_type, name, tag)
+ else:
+ res = re.match(r'^struct\[(%s)\]$' % _STRUCT_RE,
+ entry_type, re.IGNORECASE)
+ if res:
+ # References another struct defined in our file
+ newentry = EntryStruct(entry_type, name, tag, res.group(1))
+ else:
+ print >>sys.stderr, 'Bad type: "%s" in "%s"' % (entry_type, entry)
+ sys.exit(1)
+
+ structs = []
+
+ if optional:
+ newentry.MakeOptional()
+ if array:
+ newentry.MakeArray()
+
+ newentry.SetStruct(newstruct)
+ newentry.SetLineCount(line_count)
+ newentry.Verify()
+
+ if array:
+ # We need to encapsulate this entry into a struct
+ newname = newentry.Name()+ '_array'
+
+ # Now borgify the new entry.
+ newentry = EntryArray(newentry)
+ newentry.SetStruct(newstruct)
+ newentry.SetLineCount(line_count)
+ newentry.MakeArray()
+
+ newstruct.AddEntry(newentry)
+
+ return structs
+
+def ProcessStruct(data):
+ tokens = data.split(' ')
+
+ # First three tokens are: 'struct' 'name' '{'
+ newstruct = Struct(tokens[1])
+
+ inside = ' '.join(tokens[3:-1])
+
+ tokens = inside.split(';')
+
+ structs = []
+
+ for entry in tokens:
+ entry = NormalizeLine(entry)
+ if not entry:
+ continue
+
+ # It's possible that new structs get defined in here
+ structs.extend(ProcessOneEntry(newstruct, entry))
+
+ structs.append(newstruct)
+ return structs
+
+def GetNextStruct(file):
+ global line_count
+ global cppdirect
+
+ got_struct = 0
+
+ processed_lines = []
+
+ have_c_comment = 0
+ data = ''
+ while 1:
+ line = file.readline()
+ if not line:
+ break
+
+ line_count += 1
+ line = line[:-1]
+
+ if not have_c_comment and re.search(r'/\*', line):
+ if re.search(r'/\*.*\*/', line):
+ line = re.sub(r'/\*.*\*/', '', line)
+ else:
+ line = re.sub(r'/\*.*$', '', line)
+ have_c_comment = 1
+
+ if have_c_comment:
+ if not re.search(r'\*/', line):
+ continue
+ have_c_comment = 0
+ line = re.sub(r'^.*\*/', '', line)
+
+ line = NormalizeLine(line)
+
+ if not line:
+ continue
+
+ if not got_struct:
+ if re.match(r'#include ["<].*[>"]', line):
+ cppdirect.append(line)
+ continue
+
+ if re.match(r'^#(if( |def)|endif)', line):
+ cppdirect.append(line)
+ continue
+
+ if re.match(r'^#define', line):
+ headerdirect.append(line)
+ continue
+
+ if not re.match(r'^struct %s {$' % _STRUCT_RE,
+ line, re.IGNORECASE):
+ print >>sys.stderr, 'Missing struct on line %d: %s' % (
+ line_count, line)
+ sys.exit(1)
+ else:
+ got_struct = 1
+ data += line
+ continue
+
+ # We are inside the struct
+ tokens = line.split('}')
+ if len(tokens) == 1:
+ data += ' ' + line
+ continue
+
+ if len(tokens[1]):
+ print >>sys.stderr, 'Trailing garbage after struct on line %d' % (
+ line_count )
+ sys.exit(1)
+
+ # We found the end of the struct
+ data += ' %s}' % tokens[0]
+ break
+
+ # Remove any comments, that might be in there
+ data = re.sub(r'/\*.*\*/', '', data)
+
+ return data
+
+
+def Parse(file):
+ """
+ Parses the input file and returns C code and corresponding header file.
+ """
+
+ entities = []
+
+ while 1:
+ # Just gets the whole struct nicely formatted
+ data = GetNextStruct(file)
+
+ if not data:
+ break
+
+ entities.extend(ProcessStruct(data))
+
+ return entities
+
+def GuardName(name):
+ name = '_'.join(name.split('.'))
+ name = '_'.join(name.split('/'))
+ guard = '_'+name.upper()+'_'
+
+ return guard
+
+def HeaderPreamble(name):
+ guard = GuardName(name)
+ pre = (
+ '/*\n'
+ ' * Automatically generated from %s\n'
+ ' */\n\n'
+ '#ifndef %s\n'
+ '#define %s\n\n' ) % (
+ name, guard, guard)
+
+ # insert stdint.h - let's hope everyone has it
+ pre += (
+ '#include <event-config.h>\n'
+ '#ifdef _EVENT_HAVE_STDINT_H\n'
+ '#include <stdint.h>\n'
+ '#endif\n' )
+
+ for statement in headerdirect:
+ pre += '%s\n' % statement
+ if headerdirect:
+ pre += '\n'
+
+ pre += (
+ '#define EVTAG_HAS(msg, member) ((msg)->member##_set == 1)\n'
+ '#ifdef __GNUC__\n'
+ '#define EVTAG_ASSIGN(msg, member, args...) '
+ '(*(msg)->base->member##_assign)(msg, ## args)\n'
+ '#define EVTAG_GET(msg, member, args...) '
+ '(*(msg)->base->member##_get)(msg, ## args)\n'
+ '#else\n'
+ '#define EVTAG_ASSIGN(msg, member, ...) '
+ '(*(msg)->base->member##_assign)(msg, ## __VA_ARGS__)\n'
+ '#define EVTAG_GET(msg, member, ...) '
+ '(*(msg)->base->member##_get)(msg, ## __VA_ARGS__)\n'
+ '#endif\n'
+ '#define EVTAG_ADD(msg, member) (*(msg)->base->member##_add)(msg)\n'
+ '#define EVTAG_LEN(msg, member) ((msg)->member##_length)\n'
+ )
+
+ return pre
+
+
+def HeaderPostamble(name):
+ guard = GuardName(name)
+ return '#endif /* %s */' % guard
+
+def BodyPreamble(name):
+ global _NAME
+ global _VERSION
+
+ header_file = '.'.join(name.split('.')[:-1]) + '.gen.h'
+
+ pre = ( '/*\n'
+ ' * Automatically generated from %s\n'
+ ' * by %s/%s. DO NOT EDIT THIS FILE.\n'
+ ' */\n\n' ) % (name, _NAME, _VERSION)
+ pre += ( '#include <sys/types.h>\n'
+ '#ifdef _EVENT_HAVE_SYS_TIME_H\n'
+ '#include <sys/time.h>\n'
+ '#endif\n'
+ '#include <stdlib.h>\n'
+ '#include <string.h>\n'
+ '#include <assert.h>\n'
+ '#define EVENT_NO_STRUCT\n'
+ '#include <event.h>\n\n'
+ '#ifdef _EVENT___func__\n'
+ '#define __func__ _EVENT___func__\n'
+ '#endif\n' )
+
+ for statement in cppdirect:
+ pre += '%s\n' % statement
+
+ pre += '\n#include "%s"\n\n' % header_file
+
+ pre += 'void event_err(int eval, const char *fmt, ...);\n'
+ pre += 'void event_warn(const char *fmt, ...);\n'
+ pre += 'void event_errx(int eval, const char *fmt, ...);\n'
+ pre += 'void event_warnx(const char *fmt, ...);\n\n'
+
+ return pre
+
+def main(argv):
+ if len(argv) < 2 or not argv[1]:
+ print >>sys.stderr, 'Need RPC description file as first argument.'
+ sys.exit(1)
+
+ filename = argv[1]
+
+ ext = filename.split('.')[-1]
+ if ext != 'rpc':
+ print >>sys.stderr, 'Unrecognized file extension: %s' % ext
+ sys.exit(1)
+
+ print >>sys.stderr, 'Reading \"%s\"' % filename
+
+ fp = open(filename, 'r')
+ entities = Parse(fp)
+ fp.close()
+
+ header_file = '.'.join(filename.split('.')[:-1]) + '.gen.h'
+ impl_file = '.'.join(filename.split('.')[:-1]) + '.gen.c'
+
+ print >>sys.stderr, '... creating "%s"' % header_file
+ header_fp = open(header_file, 'w')
+ print >>header_fp, HeaderPreamble(filename)
+
+ # Create forward declarations: allows other structs to reference
+ # each other
+ for entry in entities:
+ entry.PrintForwardDeclaration(header_fp)
+ print >>header_fp, ''
+
+ for entry in entities:
+ entry.PrintTags(header_fp)
+ entry.PrintDeclaration(header_fp)
+ print >>header_fp, HeaderPostamble(filename)
+ header_fp.close()
+
+ print >>sys.stderr, '... creating "%s"' % impl_file
+ impl_fp = open(impl_file, 'w')
+ print >>impl_fp, BodyPreamble(filename)
+ for entry in entities:
+ entry.PrintCode(impl_fp)
+ impl_fp.close()
+
+if __name__ == '__main__':
+ main(sys.argv)
diff --git a/chromium/base/third_party/libevent/event_tagging.c b/chromium/base/third_party/libevent/event_tagging.c
new file mode 100644
index 00000000000..d436e3fd65b
--- /dev/null
+++ b/chromium/base/third_party/libevent/event_tagging.c
@@ -0,0 +1,443 @@
+/*
+ * Copyright (c) 2003, 2004 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#ifdef WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <winsock2.h>
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#else
+#include <sys/ioctl.h>
+#endif
+
+#include <sys/queue.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifndef WIN32
+#include <syslog.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "event.h"
+#include "evutil.h"
+#include "log.h"
+
+int evtag_decode_int(ev_uint32_t *pnumber, struct evbuffer *evbuf);
+int evtag_encode_tag(struct evbuffer *evbuf, ev_uint32_t tag);
+int evtag_decode_tag(ev_uint32_t *ptag, struct evbuffer *evbuf);
+
+static struct evbuffer *_buf; /* not thread safe */
+
+void
+evtag_init(void)
+{
+ if (_buf != NULL)
+ return;
+
+ if ((_buf = evbuffer_new()) == NULL)
+ event_err(1, "%s: malloc", __func__);
+}
+
+/*
+ * We encode integer's by nibbles; the first nibble contains the number
+ * of significant nibbles - 1; this allows us to encode up to 64-bit
+ * integers. This function is byte-order independent.
+ */
+
+void
+encode_int(struct evbuffer *evbuf, ev_uint32_t number)
+{
+ int off = 1, nibbles = 0;
+ ev_uint8_t data[5];
+
+ memset(data, 0, sizeof(ev_uint32_t)+1);
+ while (number) {
+ if (off & 0x1)
+ data[off/2] = (data[off/2] & 0xf0) | (number & 0x0f);
+ else
+ data[off/2] = (data[off/2] & 0x0f) |
+ ((number & 0x0f) << 4);
+ number >>= 4;
+ off++;
+ }
+
+ if (off > 2)
+ nibbles = off - 2;
+
+ /* Off - 1 is the number of encoded nibbles */
+ data[0] = (data[0] & 0x0f) | ((nibbles & 0x0f) << 4);
+
+ evbuffer_add(evbuf, data, (off + 1) / 2);
+}
+
+/*
+ * Support variable length encoding of tags; we use the high bit in each
+ * octet as a continuation signal.
+ */
+
+int
+evtag_encode_tag(struct evbuffer *evbuf, ev_uint32_t tag)
+{
+ int bytes = 0;
+ ev_uint8_t data[5];
+
+ memset(data, 0, sizeof(data));
+ do {
+ ev_uint8_t lower = tag & 0x7f;
+ tag >>= 7;
+
+ if (tag)
+ lower |= 0x80;
+
+ data[bytes++] = lower;
+ } while (tag);
+
+ if (evbuf != NULL)
+ evbuffer_add(evbuf, data, bytes);
+
+ return (bytes);
+}
+
+static int
+decode_tag_internal(ev_uint32_t *ptag, struct evbuffer *evbuf, int dodrain)
+{
+ ev_uint32_t number = 0;
+ ev_uint8_t *data = EVBUFFER_DATA(evbuf);
+ int len = EVBUFFER_LENGTH(evbuf);
+ int count = 0, shift = 0, done = 0;
+
+ while (count++ < len) {
+ ev_uint8_t lower = *data++;
+ number |= (lower & 0x7f) << shift;
+ shift += 7;
+
+ if (!(lower & 0x80)) {
+ done = 1;
+ break;
+ }
+ }
+
+ if (!done)
+ return (-1);
+
+ if (dodrain)
+ evbuffer_drain(evbuf, count);
+
+ if (ptag != NULL)
+ *ptag = number;
+
+ return (count);
+}
+
+int
+evtag_decode_tag(ev_uint32_t *ptag, struct evbuffer *evbuf)
+{
+ return (decode_tag_internal(ptag, evbuf, 1 /* dodrain */));
+}
+
+/*
+ * Marshal a data type, the general format is as follows:
+ *
+ * tag number: one byte; length: var bytes; payload: var bytes
+ */
+
+void
+evtag_marshal(struct evbuffer *evbuf, ev_uint32_t tag,
+ const void *data, ev_uint32_t len)
+{
+ evtag_encode_tag(evbuf, tag);
+ encode_int(evbuf, len);
+ evbuffer_add(evbuf, (void *)data, len);
+}
+
+/* Marshaling for integers */
+void
+evtag_marshal_int(struct evbuffer *evbuf, ev_uint32_t tag, ev_uint32_t integer)
+{
+ evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
+ encode_int(_buf, integer);
+
+ evtag_encode_tag(evbuf, tag);
+ encode_int(evbuf, EVBUFFER_LENGTH(_buf));
+ evbuffer_add_buffer(evbuf, _buf);
+}
+
+void
+evtag_marshal_string(struct evbuffer *buf, ev_uint32_t tag, const char *string)
+{
+ evtag_marshal(buf, tag, string, strlen(string));
+}
+
+void
+evtag_marshal_timeval(struct evbuffer *evbuf, ev_uint32_t tag, struct timeval *tv)
+{
+ evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
+
+ encode_int(_buf, tv->tv_sec);
+ encode_int(_buf, tv->tv_usec);
+
+ evtag_marshal(evbuf, tag, EVBUFFER_DATA(_buf),
+ EVBUFFER_LENGTH(_buf));
+}
+
+static int
+decode_int_internal(ev_uint32_t *pnumber, struct evbuffer *evbuf, int dodrain)
+{
+ ev_uint32_t number = 0;
+ ev_uint8_t *data = EVBUFFER_DATA(evbuf);
+ int len = EVBUFFER_LENGTH(evbuf);
+ int nibbles = 0;
+
+ if (!len)
+ return (-1);
+
+ nibbles = ((data[0] & 0xf0) >> 4) + 1;
+ if (nibbles > 8 || (nibbles >> 1) + 1 > len)
+ return (-1);
+ len = (nibbles >> 1) + 1;
+
+ while (nibbles > 0) {
+ number <<= 4;
+ if (nibbles & 0x1)
+ number |= data[nibbles >> 1] & 0x0f;
+ else
+ number |= (data[nibbles >> 1] & 0xf0) >> 4;
+ nibbles--;
+ }
+
+ if (dodrain)
+ evbuffer_drain(evbuf, len);
+
+ *pnumber = number;
+
+ return (len);
+}
+
+int
+evtag_decode_int(ev_uint32_t *pnumber, struct evbuffer *evbuf)
+{
+ return (decode_int_internal(pnumber, evbuf, 1) == -1 ? -1 : 0);
+}
+
+int
+evtag_peek(struct evbuffer *evbuf, ev_uint32_t *ptag)
+{
+ return (decode_tag_internal(ptag, evbuf, 0 /* dodrain */));
+}
+
+int
+evtag_peek_length(struct evbuffer *evbuf, ev_uint32_t *plength)
+{
+ struct evbuffer tmp;
+ int res, len;
+
+ len = decode_tag_internal(NULL, evbuf, 0 /* dodrain */);
+ if (len == -1)
+ return (-1);
+
+ tmp = *evbuf;
+ tmp.buffer += len;
+ tmp.off -= len;
+
+ res = decode_int_internal(plength, &tmp, 0);
+ if (res == -1)
+ return (-1);
+
+ *plength += res + len;
+
+ return (0);
+}
+
+int
+evtag_payload_length(struct evbuffer *evbuf, ev_uint32_t *plength)
+{
+ struct evbuffer tmp;
+ int res, len;
+
+ len = decode_tag_internal(NULL, evbuf, 0 /* dodrain */);
+ if (len == -1)
+ return (-1);
+
+ tmp = *evbuf;
+ tmp.buffer += len;
+ tmp.off -= len;
+
+ res = decode_int_internal(plength, &tmp, 0);
+ if (res == -1)
+ return (-1);
+
+ return (0);
+}
+
+int
+evtag_consume(struct evbuffer *evbuf)
+{
+ ev_uint32_t len;
+ if (decode_tag_internal(NULL, evbuf, 1 /* dodrain */) == -1)
+ return (-1);
+ if (evtag_decode_int(&len, evbuf) == -1)
+ return (-1);
+ evbuffer_drain(evbuf, len);
+
+ return (0);
+}
+
+/* Reads the data type from an event buffer */
+
+int
+evtag_unmarshal(struct evbuffer *src, ev_uint32_t *ptag, struct evbuffer *dst)
+{
+ ev_uint32_t len;
+ ev_uint32_t integer;
+
+ if (decode_tag_internal(ptag, src, 1 /* dodrain */) == -1)
+ return (-1);
+ if (evtag_decode_int(&integer, src) == -1)
+ return (-1);
+ len = integer;
+
+ if (EVBUFFER_LENGTH(src) < len)
+ return (-1);
+
+ if (evbuffer_add(dst, EVBUFFER_DATA(src), len) == -1)
+ return (-1);
+
+ evbuffer_drain(src, len);
+
+ return (len);
+}
+
+/* Marshaling for integers */
+
+int
+evtag_unmarshal_int(struct evbuffer *evbuf, ev_uint32_t need_tag,
+ ev_uint32_t *pinteger)
+{
+ ev_uint32_t tag;
+ ev_uint32_t len;
+ ev_uint32_t integer;
+
+ if (decode_tag_internal(&tag, evbuf, 1 /* dodrain */) == -1)
+ return (-1);
+ if (need_tag != tag)
+ return (-1);
+ if (evtag_decode_int(&integer, evbuf) == -1)
+ return (-1);
+ len = integer;
+
+ if (EVBUFFER_LENGTH(evbuf) < len)
+ return (-1);
+
+ evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
+ if (evbuffer_add(_buf, EVBUFFER_DATA(evbuf), len) == -1)
+ return (-1);
+
+ evbuffer_drain(evbuf, len);
+
+ return (evtag_decode_int(pinteger, _buf));
+}
+
+/* Unmarshal a fixed length tag */
+
+int
+evtag_unmarshal_fixed(struct evbuffer *src, ev_uint32_t need_tag, void *data,
+ size_t len)
+{
+ ev_uint32_t tag;
+
+ /* Initialize this event buffer so that we can read into it */
+ evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
+
+ /* Now unmarshal a tag and check that it matches the tag we want */
+ if (evtag_unmarshal(src, &tag, _buf) == -1 || tag != need_tag)
+ return (-1);
+
+ if (EVBUFFER_LENGTH(_buf) != len)
+ return (-1);
+
+ memcpy(data, EVBUFFER_DATA(_buf), len);
+ return (0);
+}
+
+int
+evtag_unmarshal_string(struct evbuffer *evbuf, ev_uint32_t need_tag,
+ char **pstring)
+{
+ ev_uint32_t tag;
+
+ evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
+
+ if (evtag_unmarshal(evbuf, &tag, _buf) == -1 || tag != need_tag)
+ return (-1);
+
+ *pstring = calloc(EVBUFFER_LENGTH(_buf) + 1, 1);
+ if (*pstring == NULL)
+ event_err(1, "%s: calloc", __func__);
+ evbuffer_remove(_buf, *pstring, EVBUFFER_LENGTH(_buf));
+
+ return (0);
+}
+
+int
+evtag_unmarshal_timeval(struct evbuffer *evbuf, ev_uint32_t need_tag,
+ struct timeval *ptv)
+{
+ ev_uint32_t tag;
+ ev_uint32_t integer;
+
+ evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
+ if (evtag_unmarshal(evbuf, &tag, _buf) == -1 || tag != need_tag)
+ return (-1);
+
+ if (evtag_decode_int(&integer, _buf) == -1)
+ return (-1);
+ ptv->tv_sec = integer;
+ if (evtag_decode_int(&integer, _buf) == -1)
+ return (-1);
+ ptv->tv_usec = integer;
+
+ return (0);
+}
diff --git a/chromium/base/third_party/libevent/evhttp.h b/chromium/base/third_party/libevent/evhttp.h
new file mode 100644
index 00000000000..48c1d9186e9
--- /dev/null
+++ b/chromium/base/third_party/libevent/evhttp.h
@@ -0,0 +1,375 @@
+/*
+ * Copyright (c) 2000-2004 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _EVHTTP_H_
+#define _EVHTTP_H_
+
+#include "event.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <winsock2.h>
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#endif
+
+/** @file evhttp.h
+ *
+ * Basic support for HTTP serving.
+ *
+ * As libevent is a library for dealing with event notification and most
+ * interesting applications are networked today, I have often found the
+ * need to write HTTP code. The following prototypes and definitions provide
+ * an application with a minimal interface for making HTTP requests and for
+ * creating a very simple HTTP server.
+ */
+
+/* Response codes */
+#define HTTP_OK 200
+#define HTTP_NOCONTENT 204
+#define HTTP_MOVEPERM 301
+#define HTTP_MOVETEMP 302
+#define HTTP_NOTMODIFIED 304
+#define HTTP_BADREQUEST 400
+#define HTTP_NOTFOUND 404
+#define HTTP_SERVUNAVAIL 503
+
+struct evhttp;
+struct evhttp_request;
+struct evkeyvalq;
+
+/** Create a new HTTP server
+ *
+ * @param base (optional) the event base to receive the HTTP events
+ * @return a pointer to a newly initialized evhttp server structure
+ */
+struct evhttp *evhttp_new(struct event_base *base);
+
+/**
+ * Binds an HTTP server on the specified address and port.
+ *
+ * Can be called multiple times to bind the same http server
+ * to multiple different ports.
+ *
+ * @param http a pointer to an evhttp object
+ * @param address a string containing the IP address to listen(2) on
+ * @param port the port number to listen on
+ * @return 0 on success, -1 on failure
+ * @see evhttp_free()
+ */
+int evhttp_bind_socket(struct evhttp *http, const char *address, u_short port);
+
+/**
+ * Makes an HTTP server accept connections on the specified socket
+ *
+ * This may be useful to create a socket and then fork multiple instances
+ * of an http server, or when a socket has been communicated via file
+ * descriptor passing in situations where an http servers does not have
+ * permissions to bind to a low-numbered port.
+ *
+ * Can be called multiple times to have the http server listen to
+ * multiple different sockets.
+ *
+ * @param http a pointer to an evhttp object
+ * @param fd a socket fd that is ready for accepting connections
+ * @return 0 on success, -1 on failure.
+ * @see evhttp_free(), evhttp_bind_socket()
+ */
+int evhttp_accept_socket(struct evhttp *http, int fd);
+
+/**
+ * Free the previously created HTTP server.
+ *
+ * Works only if no requests are currently being served.
+ *
+ * @param http the evhttp server object to be freed
+ * @see evhttp_start()
+ */
+void evhttp_free(struct evhttp* http);
+
+/** Set a callback for a specified URI */
+void evhttp_set_cb(struct evhttp *, const char *,
+ void (*)(struct evhttp_request *, void *), void *);
+
+/** Removes the callback for a specified URI */
+int evhttp_del_cb(struct evhttp *, const char *);
+
+/** Set a callback for all requests that are not caught by specific callbacks
+ */
+void evhttp_set_gencb(struct evhttp *,
+ void (*)(struct evhttp_request *, void *), void *);
+
+/**
+ * Set the timeout for an HTTP request.
+ *
+ * @param http an evhttp object
+ * @param timeout_in_secs the timeout, in seconds
+ */
+void evhttp_set_timeout(struct evhttp *, int timeout_in_secs);
+
+/* Request/Response functionality */
+
+/**
+ * Send an HTML error message to the client.
+ *
+ * @param req a request object
+ * @param error the HTTP error code
+ * @param reason a brief explanation of the error
+ */
+void evhttp_send_error(struct evhttp_request *req, int error,
+ const char *reason);
+
+/**
+ * Send an HTML reply to the client.
+ *
+ * @param req a request object
+ * @param code the HTTP response code to send
+ * @param reason a brief message to send with the response code
+ * @param databuf the body of the response
+ */
+void evhttp_send_reply(struct evhttp_request *req, int code,
+ const char *reason, struct evbuffer *databuf);
+
+/* Low-level response interface, for streaming/chunked replies */
+void evhttp_send_reply_start(struct evhttp_request *, int, const char *);
+void evhttp_send_reply_chunk(struct evhttp_request *, struct evbuffer *);
+void evhttp_send_reply_end(struct evhttp_request *);
+
+/**
+ * Start an HTTP server on the specified address and port
+ *
+ * DEPRECATED: it does not allow an event base to be specified
+ *
+ * @param address the address to which the HTTP server should be bound
+ * @param port the port number on which the HTTP server should listen
+ * @return an struct evhttp object
+ */
+struct evhttp *evhttp_start(const char *address, u_short port);
+
+/*
+ * Interfaces for making requests
+ */
+enum evhttp_cmd_type { EVHTTP_REQ_GET, EVHTTP_REQ_POST, EVHTTP_REQ_HEAD };
+
+enum evhttp_request_kind { EVHTTP_REQUEST, EVHTTP_RESPONSE };
+
+/**
+ * the request structure that a server receives.
+ * WARNING: expect this structure to change. I will try to provide
+ * reasonable accessors.
+ */
+struct evhttp_request {
+#if defined(TAILQ_ENTRY)
+ TAILQ_ENTRY(evhttp_request) next;
+#else
+struct {
+ struct evhttp_request *tqe_next;
+ struct evhttp_request **tqe_prev;
+} next;
+#endif
+
+ /* the connection object that this request belongs to */
+ struct evhttp_connection *evcon;
+ int flags;
+#define EVHTTP_REQ_OWN_CONNECTION 0x0001
+#define EVHTTP_PROXY_REQUEST 0x0002
+
+ struct evkeyvalq *input_headers;
+ struct evkeyvalq *output_headers;
+
+ /* address of the remote host and the port connection came from */
+ char *remote_host;
+ u_short remote_port;
+
+ enum evhttp_request_kind kind;
+ enum evhttp_cmd_type type;
+
+ char *uri; /* uri after HTTP request was parsed */
+
+ char major; /* HTTP Major number */
+ char minor; /* HTTP Minor number */
+
+ int response_code; /* HTTP Response code */
+ char *response_code_line; /* Readable response */
+
+ struct evbuffer *input_buffer; /* read data */
+ ev_int64_t ntoread;
+ int chunked:1, /* a chunked request */
+ userdone:1; /* the user has sent all data */
+
+ struct evbuffer *output_buffer; /* outgoing post or data */
+
+ /* Callback */
+ void (*cb)(struct evhttp_request *, void *);
+ void *cb_arg;
+
+ /*
+ * Chunked data callback - call for each completed chunk if
+ * specified. If not specified, all the data is delivered via
+ * the regular callback.
+ */
+ void (*chunk_cb)(struct evhttp_request *, void *);
+};
+
+/**
+ * Creates a new request object that needs to be filled in with the request
+ * parameters. The callback is executed when the request completed or an
+ * error occurred.
+ */
+struct evhttp_request *evhttp_request_new(
+ void (*cb)(struct evhttp_request *, void *), void *arg);
+
+/** enable delivery of chunks to requestor */
+void evhttp_request_set_chunked_cb(struct evhttp_request *,
+ void (*cb)(struct evhttp_request *, void *));
+
+/** Frees the request object and removes associated events. */
+void evhttp_request_free(struct evhttp_request *req);
+
+/** Returns the connection object associated with the request or NULL */
+struct evhttp_connection *evhttp_request_get_connection(struct evhttp_request *req);
+
+/**
+ * A connection object that can be used to for making HTTP requests. The
+ * connection object tries to establish the connection when it is given an
+ * http request object.
+ */
+struct evhttp_connection *evhttp_connection_new(
+ const char *address, unsigned short port);
+
+/** Frees an http connection */
+void evhttp_connection_free(struct evhttp_connection *evcon);
+
+/** sets the ip address from which http connections are made */
+void evhttp_connection_set_local_address(struct evhttp_connection *evcon,
+ const char *address);
+
+/** sets the local port from which http connections are made */
+void evhttp_connection_set_local_port(struct evhttp_connection *evcon,
+ unsigned short port);
+
+/** Sets the timeout for events related to this connection */
+void evhttp_connection_set_timeout(struct evhttp_connection *evcon,
+ int timeout_in_secs);
+
+/** Sets the retry limit for this connection - -1 repeats indefnitely */
+void evhttp_connection_set_retries(struct evhttp_connection *evcon,
+ int retry_max);
+
+/** Set a callback for connection close. */
+void evhttp_connection_set_closecb(struct evhttp_connection *evcon,
+ void (*)(struct evhttp_connection *, void *), void *);
+
+/**
+ * Associates an event base with the connection - can only be called
+ * on a freshly created connection object that has not been used yet.
+ */
+void evhttp_connection_set_base(struct evhttp_connection *evcon,
+ struct event_base *base);
+
+/** Get the remote address and port associated with this connection. */
+void evhttp_connection_get_peer(struct evhttp_connection *evcon,
+ char **address, u_short *port);
+
+/** The connection gets ownership of the request */
+int evhttp_make_request(struct evhttp_connection *evcon,
+ struct evhttp_request *req,
+ enum evhttp_cmd_type type, const char *uri);
+
+const char *evhttp_request_uri(struct evhttp_request *req);
+
+/* Interfaces for dealing with HTTP headers */
+
+const char *evhttp_find_header(const struct evkeyvalq *, const char *);
+int evhttp_remove_header(struct evkeyvalq *, const char *);
+int evhttp_add_header(struct evkeyvalq *, const char *, const char *);
+void evhttp_clear_headers(struct evkeyvalq *);
+
+/* Miscellaneous utility functions */
+
+
+/**
+ Helper function to encode a URI.
+
+ The returned string must be freed by the caller.
+
+ @param uri an unencoded URI
+ @return a newly allocated URI-encoded string
+ */
+char *evhttp_encode_uri(const char *uri);
+
+
+/**
+ Helper function to decode a URI.
+
+ The returned string must be freed by the caller.
+
+ @param uri an encoded URI
+ @return a newly allocated unencoded URI
+ */
+char *evhttp_decode_uri(const char *uri);
+
+
+/**
+ * Helper function to parse out arguments in a query.
+ *
+ * Parsing a uri like
+ *
+ * http://foo.com/?q=test&s=some+thing
+ *
+ * will result in two entries in the key value queue.
+
+ * The first entry is: key="q", value="test"
+ * The second entry is: key="s", value="some thing"
+ *
+ * @param uri the request URI
+ * @param headers the head of the evkeyval queue
+ */
+void evhttp_parse_query(const char *uri, struct evkeyvalq *headers);
+
+
+/**
+ * Escape HTML character entities in a string.
+ *
+ * Replaces <, >, ", ' and & with &lt;, &gt;, &quot;,
+ * &#039; and &amp; correspondingly.
+ *
+ * The returned string needs to be freed by the caller.
+ *
+ * @param html an unescaped HTML string
+ * @return an escaped HTML string
+ */
+char *evhttp_htmlescape(const char *html);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _EVHTTP_H_ */
diff --git a/chromium/base/third_party/libevent/evport.c b/chromium/base/third_party/libevent/evport.c
new file mode 100644
index 00000000000..1f5ebc41e8f
--- /dev/null
+++ b/chromium/base/third_party/libevent/evport.c
@@ -0,0 +1,519 @@
+/*
+ * Submitted by David Pacheco (dp.spambait@gmail.com)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY SUN MICROSYSTEMS, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL SUN MICROSYSTEMS, INC. BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 2007 Sun Microsystems. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * evport.c: event backend using Solaris 10 event ports. See port_create(3C).
+ * This implementation is loosely modeled after the one used for select(2) (in
+ * select.c).
+ *
+ * The outstanding events are tracked in a data structure called evport_data.
+ * Each entry in the ed_fds array corresponds to a file descriptor, and contains
+ * pointers to the read and write events that correspond to that fd. (That is,
+ * when the file is readable, the "read" event should handle it, etc.)
+ *
+ * evport_add and evport_del update this data structure. evport_dispatch uses it
+ * to determine where to callback when an event occurs (which it gets from
+ * port_getn).
+ *
+ * Helper functions are used: grow() grows the file descriptor array as
+ * necessary when large fd's come in. reassociate() takes care of maintaining
+ * the proper file-descriptor/event-port associations.
+ *
+ * As in the select(2) implementation, signals are handled by evsignal.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/time.h>
+#include <assert.h>
+#include <sys/queue.h>
+#include <errno.h>
+#include <poll.h>
+#include <port.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#ifdef CHECK_INVARIANTS
+#include <assert.h>
+#endif
+
+#include "event.h"
+#include "event-internal.h"
+#include "log.h"
+#include "evsignal.h"
+
+
+/*
+ * Default value for ed_nevents, which is the maximum file descriptor number we
+ * can handle. If an event comes in for a file descriptor F > nevents, we will
+ * grow the array of file descriptors, doubling its size.
+ */
+#define DEFAULT_NFDS 16
+
+
+/*
+ * EVENTS_PER_GETN is the maximum number of events to retrieve from port_getn on
+ * any particular call. You can speed things up by increasing this, but it will
+ * (obviously) require more memory.
+ */
+#define EVENTS_PER_GETN 8
+
+/*
+ * Per-file-descriptor information about what events we're subscribed to. These
+ * fields are NULL if no event is subscribed to either of them.
+ */
+
+struct fd_info {
+ struct event* fdi_revt; /* the event responsible for the "read" */
+ struct event* fdi_wevt; /* the event responsible for the "write" */
+};
+
+#define FDI_HAS_READ(fdi) ((fdi)->fdi_revt != NULL)
+#define FDI_HAS_WRITE(fdi) ((fdi)->fdi_wevt != NULL)
+#define FDI_HAS_EVENTS(fdi) (FDI_HAS_READ(fdi) || FDI_HAS_WRITE(fdi))
+#define FDI_TO_SYSEVENTS(fdi) (FDI_HAS_READ(fdi) ? POLLIN : 0) | \
+ (FDI_HAS_WRITE(fdi) ? POLLOUT : 0)
+
+struct evport_data {
+ int ed_port; /* event port for system events */
+ int ed_nevents; /* number of allocated fdi's */
+ struct fd_info *ed_fds; /* allocated fdi table */
+ /* fdi's that we need to reassoc */
+ int ed_pending[EVENTS_PER_GETN]; /* fd's with pending events */
+};
+
+static void* evport_init (struct event_base *);
+static int evport_add (void *, struct event *);
+static int evport_del (void *, struct event *);
+static int evport_dispatch (struct event_base *, void *, struct timeval *);
+static void evport_dealloc (struct event_base *, void *);
+
+const struct eventop evportops = {
+ "evport",
+ evport_init,
+ evport_add,
+ evport_del,
+ evport_dispatch,
+ evport_dealloc,
+ 1 /* need reinit */
+};
+
+/*
+ * Initialize the event port implementation.
+ */
+
+static void*
+evport_init(struct event_base *base)
+{
+ struct evport_data *evpd;
+ int i;
+ /*
+ * Disable event ports when this environment variable is set
+ */
+ if (evutil_getenv("EVENT_NOEVPORT"))
+ return (NULL);
+
+ if (!(evpd = calloc(1, sizeof(struct evport_data))))
+ return (NULL);
+
+ if ((evpd->ed_port = port_create()) == -1) {
+ free(evpd);
+ return (NULL);
+ }
+
+ /*
+ * Initialize file descriptor structure
+ */
+ evpd->ed_fds = calloc(DEFAULT_NFDS, sizeof(struct fd_info));
+ if (evpd->ed_fds == NULL) {
+ close(evpd->ed_port);
+ free(evpd);
+ return (NULL);
+ }
+ evpd->ed_nevents = DEFAULT_NFDS;
+ for (i = 0; i < EVENTS_PER_GETN; i++)
+ evpd->ed_pending[i] = -1;
+
+ evsignal_init(base);
+
+ return (evpd);
+}
+
+#ifdef CHECK_INVARIANTS
+/*
+ * Checks some basic properties about the evport_data structure. Because it
+ * checks all file descriptors, this function can be expensive when the maximum
+ * file descriptor ever used is rather large.
+ */
+
+static void
+check_evportop(struct evport_data *evpd)
+{
+ assert(evpd);
+ assert(evpd->ed_nevents > 0);
+ assert(evpd->ed_port > 0);
+ assert(evpd->ed_fds > 0);
+
+ /*
+ * Verify the integrity of the fd_info struct as well as the events to
+ * which it points (at least, that they're valid references and correct
+ * for their position in the structure).
+ */
+ int i;
+ for (i = 0; i < evpd->ed_nevents; ++i) {
+ struct event *ev;
+ struct fd_info *fdi;
+
+ fdi = &evpd->ed_fds[i];
+ if ((ev = fdi->fdi_revt) != NULL) {
+ assert(ev->ev_fd == i);
+ }
+ if ((ev = fdi->fdi_wevt) != NULL) {
+ assert(ev->ev_fd == i);
+ }
+ }
+}
+
+/*
+ * Verifies very basic integrity of a given port_event.
+ */
+static void
+check_event(port_event_t* pevt)
+{
+ /*
+ * We've only registered for PORT_SOURCE_FD events. The only
+ * other thing we can legitimately receive is PORT_SOURCE_ALERT,
+ * but since we're not using port_alert either, we can assume
+ * PORT_SOURCE_FD.
+ */
+ assert(pevt->portev_source == PORT_SOURCE_FD);
+ assert(pevt->portev_user == NULL);
+}
+
+#else
+#define check_evportop(epop)
+#define check_event(pevt)
+#endif /* CHECK_INVARIANTS */
+
+/*
+ * Doubles the size of the allocated file descriptor array.
+ */
+static int
+grow(struct evport_data *epdp, int factor)
+{
+ struct fd_info *tmp;
+ int oldsize = epdp->ed_nevents;
+ int newsize = factor * oldsize;
+ assert(factor > 1);
+
+ check_evportop(epdp);
+
+ tmp = realloc(epdp->ed_fds, sizeof(struct fd_info) * newsize);
+ if (NULL == tmp)
+ return -1;
+ epdp->ed_fds = tmp;
+ memset((char*) (epdp->ed_fds + oldsize), 0,
+ (newsize - oldsize)*sizeof(struct fd_info));
+ epdp->ed_nevents = newsize;
+
+ check_evportop(epdp);
+
+ return 0;
+}
+
+
+/*
+ * (Re)associates the given file descriptor with the event port. The OS events
+ * are specified (implicitly) from the fd_info struct.
+ */
+static int
+reassociate(struct evport_data *epdp, struct fd_info *fdip, int fd)
+{
+ int sysevents = FDI_TO_SYSEVENTS(fdip);
+
+ if (sysevents != 0) {
+ if (port_associate(epdp->ed_port, PORT_SOURCE_FD,
+ fd, sysevents, NULL) == -1) {
+ event_warn("port_associate");
+ return (-1);
+ }
+ }
+
+ check_evportop(epdp);
+
+ return (0);
+}
+
+/*
+ * Main event loop - polls port_getn for some number of events, and processes
+ * them.
+ */
+
+static int
+evport_dispatch(struct event_base *base, void *arg, struct timeval *tv)
+{
+ int i, res;
+ struct evport_data *epdp = arg;
+ port_event_t pevtlist[EVENTS_PER_GETN];
+
+ /*
+ * port_getn will block until it has at least nevents events. It will
+ * also return how many it's given us (which may be more than we asked
+ * for, as long as it's less than our maximum (EVENTS_PER_GETN)) in
+ * nevents.
+ */
+ int nevents = 1;
+
+ /*
+ * We have to convert a struct timeval to a struct timespec
+ * (only difference is nanoseconds vs. microseconds). If no time-based
+ * events are active, we should wait for I/O (and tv == NULL).
+ */
+ struct timespec ts;
+ struct timespec *ts_p = NULL;
+ if (tv != NULL) {
+ ts.tv_sec = tv->tv_sec;
+ ts.tv_nsec = tv->tv_usec * 1000;
+ ts_p = &ts;
+ }
+
+ /*
+ * Before doing anything else, we need to reassociate the events we hit
+ * last time which need reassociation. See comment at the end of the
+ * loop below.
+ */
+ for (i = 0; i < EVENTS_PER_GETN; ++i) {
+ struct fd_info *fdi = NULL;
+ if (epdp->ed_pending[i] != -1) {
+ fdi = &(epdp->ed_fds[epdp->ed_pending[i]]);
+ }
+
+ if (fdi != NULL && FDI_HAS_EVENTS(fdi)) {
+ int fd = FDI_HAS_READ(fdi) ? fdi->fdi_revt->ev_fd :
+ fdi->fdi_wevt->ev_fd;
+ reassociate(epdp, fdi, fd);
+ epdp->ed_pending[i] = -1;
+ }
+ }
+
+ if ((res = port_getn(epdp->ed_port, pevtlist, EVENTS_PER_GETN,
+ (unsigned int *) &nevents, ts_p)) == -1) {
+ if (errno == EINTR || errno == EAGAIN) {
+ evsignal_process(base);
+ return (0);
+ } else if (errno == ETIME) {
+ if (nevents == 0)
+ return (0);
+ } else {
+ event_warn("port_getn");
+ return (-1);
+ }
+ } else if (base->sig.evsignal_caught) {
+ evsignal_process(base);
+ }
+
+ event_debug(("%s: port_getn reports %d events", __func__, nevents));
+
+ for (i = 0; i < nevents; ++i) {
+ struct event *ev;
+ struct fd_info *fdi;
+ port_event_t *pevt = &pevtlist[i];
+ int fd = (int) pevt->portev_object;
+
+ check_evportop(epdp);
+ check_event(pevt);
+ epdp->ed_pending[i] = fd;
+
+ /*
+ * Figure out what kind of event it was
+ * (because we have to pass this to the callback)
+ */
+ res = 0;
+ if (pevt->portev_events & POLLIN)
+ res |= EV_READ;
+ if (pevt->portev_events & POLLOUT)
+ res |= EV_WRITE;
+
+ /*
+ * Check for the error situations or a hangup situation
+ */
+ if (pevt->portev_events & (POLLERR|POLLHUP|POLLNVAL))
+ res |= EV_READ|EV_WRITE;
+
+ assert(epdp->ed_nevents > fd);
+ fdi = &(epdp->ed_fds[fd]);
+
+ /*
+ * We now check for each of the possible events (READ
+ * or WRITE). Then, we activate the event (which will
+ * cause its callback to be executed).
+ */
+
+ if ((res & EV_READ) && ((ev = fdi->fdi_revt) != NULL)) {
+ event_active(ev, res, 1);
+ }
+
+ if ((res & EV_WRITE) && ((ev = fdi->fdi_wevt) != NULL)) {
+ event_active(ev, res, 1);
+ }
+ } /* end of all events gotten */
+
+ check_evportop(epdp);
+
+ return (0);
+}
+
+
+/*
+ * Adds the given event (so that you will be notified when it happens via
+ * the callback function).
+ */
+
+static int
+evport_add(void *arg, struct event *ev)
+{
+ struct evport_data *evpd = arg;
+ struct fd_info *fdi;
+ int factor;
+
+ check_evportop(evpd);
+
+ /*
+ * Delegate, if it's not ours to handle.
+ */
+ if (ev->ev_events & EV_SIGNAL)
+ return (evsignal_add(ev));
+
+ /*
+ * If necessary, grow the file descriptor info table
+ */
+
+ factor = 1;
+ while (ev->ev_fd >= factor * evpd->ed_nevents)
+ factor *= 2;
+
+ if (factor > 1) {
+ if (-1 == grow(evpd, factor)) {
+ return (-1);
+ }
+ }
+
+ fdi = &evpd->ed_fds[ev->ev_fd];
+ if (ev->ev_events & EV_READ)
+ fdi->fdi_revt = ev;
+ if (ev->ev_events & EV_WRITE)
+ fdi->fdi_wevt = ev;
+
+ return reassociate(evpd, fdi, ev->ev_fd);
+}
+
+/*
+ * Removes the given event from the list of events to wait for.
+ */
+
+static int
+evport_del(void *arg, struct event *ev)
+{
+ struct evport_data *evpd = arg;
+ struct fd_info *fdi;
+ int i;
+ int associated = 1;
+
+ check_evportop(evpd);
+
+ /*
+ * Delegate, if it's not ours to handle
+ */
+ if (ev->ev_events & EV_SIGNAL) {
+ return (evsignal_del(ev));
+ }
+
+ if (evpd->ed_nevents < ev->ev_fd) {
+ return (-1);
+ }
+
+ for (i = 0; i < EVENTS_PER_GETN; ++i) {
+ if (evpd->ed_pending[i] == ev->ev_fd) {
+ associated = 0;
+ break;
+ }
+ }
+
+ fdi = &evpd->ed_fds[ev->ev_fd];
+ if (ev->ev_events & EV_READ)
+ fdi->fdi_revt = NULL;
+ if (ev->ev_events & EV_WRITE)
+ fdi->fdi_wevt = NULL;
+
+ if (associated) {
+ if (!FDI_HAS_EVENTS(fdi) &&
+ port_dissociate(evpd->ed_port, PORT_SOURCE_FD,
+ ev->ev_fd) == -1) {
+ /*
+ * Ignre EBADFD error the fd could have been closed
+ * before event_del() was called.
+ */
+ if (errno != EBADFD) {
+ event_warn("port_dissociate");
+ return (-1);
+ }
+ } else {
+ if (FDI_HAS_EVENTS(fdi)) {
+ return (reassociate(evpd, fdi, ev->ev_fd));
+ }
+ }
+ } else {
+ if (fdi->fdi_revt == NULL && fdi->fdi_wevt == NULL) {
+ evpd->ed_pending[i] = -1;
+ }
+ }
+ return 0;
+}
+
+
+static void
+evport_dealloc(struct event_base *base, void *arg)
+{
+ struct evport_data *evpd = arg;
+
+ evsignal_dealloc(base);
+
+ close(evpd->ed_port);
+
+ if (evpd->ed_fds)
+ free(evpd->ed_fds);
+ free(evpd);
+}
diff --git a/chromium/base/third_party/libevent/evrpc-internal.h b/chromium/base/third_party/libevent/evrpc-internal.h
new file mode 100644
index 00000000000..c900f959f97
--- /dev/null
+++ b/chromium/base/third_party/libevent/evrpc-internal.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2006 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _EVRPC_INTERNAL_H_
+#define _EVRPC_INTERNAL_H_
+
+#include "http-internal.h"
+
+struct evrpc;
+
+#define EVRPC_URI_PREFIX "/.rpc."
+
+struct evrpc_hook {
+ TAILQ_ENTRY(evrpc_hook) (next);
+
+ /* returns -1; if the rpc should be aborted, is allowed to rewrite */
+ int (*process)(struct evhttp_request *, struct evbuffer *, void *);
+ void *process_arg;
+};
+
+TAILQ_HEAD(evrpc_hook_list, evrpc_hook);
+
+/*
+ * this is shared between the base and the pool, so that we can reuse
+ * the hook adding functions; we alias both evrpc_pool and evrpc_base
+ * to this common structure.
+ */
+struct _evrpc_hooks {
+ /* hooks for processing outbound and inbound rpcs */
+ struct evrpc_hook_list in_hooks;
+ struct evrpc_hook_list out_hooks;
+};
+
+#define input_hooks common.in_hooks
+#define output_hooks common.out_hooks
+
+struct evrpc_base {
+ struct _evrpc_hooks common;
+
+ /* the HTTP server under which we register our RPC calls */
+ struct evhttp* http_server;
+
+ /* a list of all RPCs registered with us */
+ TAILQ_HEAD(evrpc_list, evrpc) registered_rpcs;
+};
+
+struct evrpc_req_generic;
+void evrpc_reqstate_free(struct evrpc_req_generic* rpc_state);
+
+/* A pool for holding evhttp_connection objects */
+struct evrpc_pool {
+ struct _evrpc_hooks common;
+
+ struct event_base *base;
+
+ struct evconq connections;
+
+ int timeout;
+
+ TAILQ_HEAD(evrpc_requestq, evrpc_request_wrapper) requests;
+};
+
+
+#endif /* _EVRPC_INTERNAL_H_ */
diff --git a/chromium/base/third_party/libevent/evrpc.c b/chromium/base/third_party/libevent/evrpc.c
new file mode 100644
index 00000000000..070fd9e710c
--- /dev/null
+++ b/chromium/base/third_party/libevent/evrpc.c
@@ -0,0 +1,657 @@
+/*
+ * Copyright (c) 2000-2004 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <winsock2.h>
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#endif
+
+#include <sys/types.h>
+#ifndef WIN32
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/queue.h>
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef WIN32
+#include <unistd.h>
+#endif
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <assert.h>
+
+#include "event.h"
+#include "evrpc.h"
+#include "evrpc-internal.h"
+#include "evhttp.h"
+#include "evutil.h"
+#include "log.h"
+
+struct evrpc_base *
+evrpc_init(struct evhttp *http_server)
+{
+ struct evrpc_base* base = calloc(1, sizeof(struct evrpc_base));
+ if (base == NULL)
+ return (NULL);
+
+ /* we rely on the tagging sub system */
+ evtag_init();
+
+ TAILQ_INIT(&base->registered_rpcs);
+ TAILQ_INIT(&base->input_hooks);
+ TAILQ_INIT(&base->output_hooks);
+ base->http_server = http_server;
+
+ return (base);
+}
+
+void
+evrpc_free(struct evrpc_base *base)
+{
+ struct evrpc *rpc;
+ struct evrpc_hook *hook;
+
+ while ((rpc = TAILQ_FIRST(&base->registered_rpcs)) != NULL) {
+ assert(evrpc_unregister_rpc(base, rpc->uri));
+ }
+ while ((hook = TAILQ_FIRST(&base->input_hooks)) != NULL) {
+ assert(evrpc_remove_hook(base, EVRPC_INPUT, hook));
+ }
+ while ((hook = TAILQ_FIRST(&base->output_hooks)) != NULL) {
+ assert(evrpc_remove_hook(base, EVRPC_OUTPUT, hook));
+ }
+ free(base);
+}
+
+void *
+evrpc_add_hook(void *vbase,
+ enum EVRPC_HOOK_TYPE hook_type,
+ int (*cb)(struct evhttp_request *, struct evbuffer *, void *),
+ void *cb_arg)
+{
+ struct _evrpc_hooks *base = vbase;
+ struct evrpc_hook_list *head = NULL;
+ struct evrpc_hook *hook = NULL;
+ switch (hook_type) {
+ case EVRPC_INPUT:
+ head = &base->in_hooks;
+ break;
+ case EVRPC_OUTPUT:
+ head = &base->out_hooks;
+ break;
+ default:
+ assert(hook_type == EVRPC_INPUT || hook_type == EVRPC_OUTPUT);
+ }
+
+ hook = calloc(1, sizeof(struct evrpc_hook));
+ assert(hook != NULL);
+
+ hook->process = cb;
+ hook->process_arg = cb_arg;
+ TAILQ_INSERT_TAIL(head, hook, next);
+
+ return (hook);
+}
+
+static int
+evrpc_remove_hook_internal(struct evrpc_hook_list *head, void *handle)
+{
+ struct evrpc_hook *hook = NULL;
+ TAILQ_FOREACH(hook, head, next) {
+ if (hook == handle) {
+ TAILQ_REMOVE(head, hook, next);
+ free(hook);
+ return (1);
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * remove the hook specified by the handle
+ */
+
+int
+evrpc_remove_hook(void *vbase, enum EVRPC_HOOK_TYPE hook_type, void *handle)
+{
+ struct _evrpc_hooks *base = vbase;
+ struct evrpc_hook_list *head = NULL;
+ switch (hook_type) {
+ case EVRPC_INPUT:
+ head = &base->in_hooks;
+ break;
+ case EVRPC_OUTPUT:
+ head = &base->out_hooks;
+ break;
+ default:
+ assert(hook_type == EVRPC_INPUT || hook_type == EVRPC_OUTPUT);
+ }
+
+ return (evrpc_remove_hook_internal(head, handle));
+}
+
+static int
+evrpc_process_hooks(struct evrpc_hook_list *head,
+ struct evhttp_request *req, struct evbuffer *evbuf)
+{
+ struct evrpc_hook *hook;
+ TAILQ_FOREACH(hook, head, next) {
+ if (hook->process(req, evbuf, hook->process_arg) == -1)
+ return (-1);
+ }
+
+ return (0);
+}
+
+static void evrpc_pool_schedule(struct evrpc_pool *pool);
+static void evrpc_request_cb(struct evhttp_request *, void *);
+void evrpc_request_done(struct evrpc_req_generic*);
+
+/*
+ * Registers a new RPC with the HTTP server. The evrpc object is expected
+ * to have been filled in via the EVRPC_REGISTER_OBJECT macro which in turn
+ * calls this function.
+ */
+
+static char *
+evrpc_construct_uri(const char *uri)
+{
+ char *constructed_uri;
+ int constructed_uri_len;
+
+ constructed_uri_len = strlen(EVRPC_URI_PREFIX) + strlen(uri) + 1;
+ if ((constructed_uri = malloc(constructed_uri_len)) == NULL)
+ event_err(1, "%s: failed to register rpc at %s",
+ __func__, uri);
+ memcpy(constructed_uri, EVRPC_URI_PREFIX, strlen(EVRPC_URI_PREFIX));
+ memcpy(constructed_uri + strlen(EVRPC_URI_PREFIX), uri, strlen(uri));
+ constructed_uri[constructed_uri_len - 1] = '\0';
+
+ return (constructed_uri);
+}
+
+int
+evrpc_register_rpc(struct evrpc_base *base, struct evrpc *rpc,
+ void (*cb)(struct evrpc_req_generic *, void *), void *cb_arg)
+{
+ char *constructed_uri = evrpc_construct_uri(rpc->uri);
+
+ rpc->base = base;
+ rpc->cb = cb;
+ rpc->cb_arg = cb_arg;
+
+ TAILQ_INSERT_TAIL(&base->registered_rpcs, rpc, next);
+
+ evhttp_set_cb(base->http_server,
+ constructed_uri,
+ evrpc_request_cb,
+ rpc);
+
+ free(constructed_uri);
+
+ return (0);
+}
+
+int
+evrpc_unregister_rpc(struct evrpc_base *base, const char *name)
+{
+ char *registered_uri = NULL;
+ struct evrpc *rpc;
+
+ /* find the right rpc; linear search might be slow */
+ TAILQ_FOREACH(rpc, &base->registered_rpcs, next) {
+ if (strcmp(rpc->uri, name) == 0)
+ break;
+ }
+ if (rpc == NULL) {
+ /* We did not find an RPC with this name */
+ return (-1);
+ }
+ TAILQ_REMOVE(&base->registered_rpcs, rpc, next);
+
+ free((char *)rpc->uri);
+ free(rpc);
+
+ registered_uri = evrpc_construct_uri(name);
+
+ /* remove the http server callback */
+ assert(evhttp_del_cb(base->http_server, registered_uri) == 0);
+
+ free(registered_uri);
+ return (0);
+}
+
+static void
+evrpc_request_cb(struct evhttp_request *req, void *arg)
+{
+ struct evrpc *rpc = arg;
+ struct evrpc_req_generic *rpc_state = NULL;
+
+ /* let's verify the outside parameters */
+ if (req->type != EVHTTP_REQ_POST ||
+ EVBUFFER_LENGTH(req->input_buffer) <= 0)
+ goto error;
+
+ /*
+ * we might want to allow hooks to suspend the processing,
+ * but at the moment, we assume that they just act as simple
+ * filters.
+ */
+ if (evrpc_process_hooks(&rpc->base->input_hooks,
+ req, req->input_buffer) == -1)
+ goto error;
+
+ rpc_state = calloc(1, sizeof(struct evrpc_req_generic));
+ if (rpc_state == NULL)
+ goto error;
+
+ /* let's check that we can parse the request */
+ rpc_state->request = rpc->request_new();
+ if (rpc_state->request == NULL)
+ goto error;
+
+ rpc_state->rpc = rpc;
+
+ if (rpc->request_unmarshal(
+ rpc_state->request, req->input_buffer) == -1) {
+ /* we failed to parse the request; that's a bummer */
+ goto error;
+ }
+
+ /* at this point, we have a well formed request, prepare the reply */
+
+ rpc_state->reply = rpc->reply_new();
+ if (rpc_state->reply == NULL)
+ goto error;
+
+ rpc_state->http_req = req;
+ rpc_state->done = evrpc_request_done;
+
+ /* give the rpc to the user; they can deal with it */
+ rpc->cb(rpc_state, rpc->cb_arg);
+
+ return;
+
+error:
+ evrpc_reqstate_free(rpc_state);
+ evhttp_send_error(req, HTTP_SERVUNAVAIL, "Service Error");
+ return;
+}
+
+void
+evrpc_reqstate_free(struct evrpc_req_generic* rpc_state)
+{
+ /* clean up all memory */
+ if (rpc_state != NULL) {
+ struct evrpc *rpc = rpc_state->rpc;
+
+ if (rpc_state->request != NULL)
+ rpc->request_free(rpc_state->request);
+ if (rpc_state->reply != NULL)
+ rpc->reply_free(rpc_state->reply);
+ free(rpc_state);
+ }
+}
+
+void
+evrpc_request_done(struct evrpc_req_generic* rpc_state)
+{
+ struct evhttp_request *req = rpc_state->http_req;
+ struct evrpc *rpc = rpc_state->rpc;
+ struct evbuffer* data = NULL;
+
+ if (rpc->reply_complete(rpc_state->reply) == -1) {
+ /* the reply was not completely filled in. error out */
+ goto error;
+ }
+
+ if ((data = evbuffer_new()) == NULL) {
+ /* out of memory */
+ goto error;
+ }
+
+ /* serialize the reply */
+ rpc->reply_marshal(data, rpc_state->reply);
+
+ /* do hook based tweaks to the request */
+ if (evrpc_process_hooks(&rpc->base->output_hooks,
+ req, data) == -1)
+ goto error;
+
+ /* on success, we are going to transmit marshaled binary data */
+ if (evhttp_find_header(req->output_headers, "Content-Type") == NULL) {
+ evhttp_add_header(req->output_headers,
+ "Content-Type", "application/octet-stream");
+ }
+
+ evhttp_send_reply(req, HTTP_OK, "OK", data);
+
+ evbuffer_free(data);
+
+ evrpc_reqstate_free(rpc_state);
+
+ return;
+
+error:
+ if (data != NULL)
+ evbuffer_free(data);
+ evrpc_reqstate_free(rpc_state);
+ evhttp_send_error(req, HTTP_SERVUNAVAIL, "Service Error");
+ return;
+}
+
+/* Client implementation of RPC site */
+
+static int evrpc_schedule_request(struct evhttp_connection *connection,
+ struct evrpc_request_wrapper *ctx);
+
+struct evrpc_pool *
+evrpc_pool_new(struct event_base *base)
+{
+ struct evrpc_pool *pool = calloc(1, sizeof(struct evrpc_pool));
+ if (pool == NULL)
+ return (NULL);
+
+ TAILQ_INIT(&pool->connections);
+ TAILQ_INIT(&pool->requests);
+
+ TAILQ_INIT(&pool->input_hooks);
+ TAILQ_INIT(&pool->output_hooks);
+
+ pool->base = base;
+ pool->timeout = -1;
+
+ return (pool);
+}
+
+static void
+evrpc_request_wrapper_free(struct evrpc_request_wrapper *request)
+{
+ free(request->name);
+ free(request);
+}
+
+void
+evrpc_pool_free(struct evrpc_pool *pool)
+{
+ struct evhttp_connection *connection;
+ struct evrpc_request_wrapper *request;
+ struct evrpc_hook *hook;
+
+ while ((request = TAILQ_FIRST(&pool->requests)) != NULL) {
+ TAILQ_REMOVE(&pool->requests, request, next);
+ /* if this gets more complicated we need our own function */
+ evrpc_request_wrapper_free(request);
+ }
+
+ while ((connection = TAILQ_FIRST(&pool->connections)) != NULL) {
+ TAILQ_REMOVE(&pool->connections, connection, next);
+ evhttp_connection_free(connection);
+ }
+
+ while ((hook = TAILQ_FIRST(&pool->input_hooks)) != NULL) {
+ assert(evrpc_remove_hook(pool, EVRPC_INPUT, hook));
+ }
+
+ while ((hook = TAILQ_FIRST(&pool->output_hooks)) != NULL) {
+ assert(evrpc_remove_hook(pool, EVRPC_OUTPUT, hook));
+ }
+
+ free(pool);
+}
+
+/*
+ * Add a connection to the RPC pool. A request scheduled on the pool
+ * may use any available connection.
+ */
+
+void
+evrpc_pool_add_connection(struct evrpc_pool *pool,
+ struct evhttp_connection *connection) {
+ assert(connection->http_server == NULL);
+ TAILQ_INSERT_TAIL(&pool->connections, connection, next);
+
+ /*
+ * associate an event base with this connection
+ */
+ if (pool->base != NULL)
+ evhttp_connection_set_base(connection, pool->base);
+
+ /*
+ * unless a timeout was specifically set for a connection,
+ * the connection inherits the timeout from the pool.
+ */
+ if (connection->timeout == -1)
+ connection->timeout = pool->timeout;
+
+ /*
+ * if we have any requests pending, schedule them with the new
+ * connections.
+ */
+
+ if (TAILQ_FIRST(&pool->requests) != NULL) {
+ struct evrpc_request_wrapper *request =
+ TAILQ_FIRST(&pool->requests);
+ TAILQ_REMOVE(&pool->requests, request, next);
+ evrpc_schedule_request(connection, request);
+ }
+}
+
+void
+evrpc_pool_set_timeout(struct evrpc_pool *pool, int timeout_in_secs)
+{
+ struct evhttp_connection *evcon;
+ TAILQ_FOREACH(evcon, &pool->connections, next) {
+ evcon->timeout = timeout_in_secs;
+ }
+ pool->timeout = timeout_in_secs;
+}
+
+
+static void evrpc_reply_done(struct evhttp_request *, void *);
+static void evrpc_request_timeout(int, short, void *);
+
+/*
+ * Finds a connection object associated with the pool that is currently
+ * idle and can be used to make a request.
+ */
+static struct evhttp_connection *
+evrpc_pool_find_connection(struct evrpc_pool *pool)
+{
+ struct evhttp_connection *connection;
+ TAILQ_FOREACH(connection, &pool->connections, next) {
+ if (TAILQ_FIRST(&connection->requests) == NULL)
+ return (connection);
+ }
+
+ return (NULL);
+}
+
+/*
+ * We assume that the ctx is no longer queued on the pool.
+ */
+static int
+evrpc_schedule_request(struct evhttp_connection *connection,
+ struct evrpc_request_wrapper *ctx)
+{
+ struct evhttp_request *req = NULL;
+ struct evrpc_pool *pool = ctx->pool;
+ struct evrpc_status status;
+ char *uri = NULL;
+ int res = 0;
+
+ if ((req = evhttp_request_new(evrpc_reply_done, ctx)) == NULL)
+ goto error;
+
+ /* serialize the request data into the output buffer */
+ ctx->request_marshal(req->output_buffer, ctx->request);
+
+ uri = evrpc_construct_uri(ctx->name);
+ if (uri == NULL)
+ goto error;
+
+ /* we need to know the connection that we might have to abort */
+ ctx->evcon = connection;
+
+ /* apply hooks to the outgoing request */
+ if (evrpc_process_hooks(&pool->output_hooks,
+ req, req->output_buffer) == -1)
+ goto error;
+
+ if (pool->timeout > 0) {
+ /*
+ * a timeout after which the whole rpc is going to be aborted.
+ */
+ struct timeval tv;
+ evutil_timerclear(&tv);
+ tv.tv_sec = pool->timeout;
+ evtimer_add(&ctx->ev_timeout, &tv);
+ }
+
+ /* start the request over the connection */
+ res = evhttp_make_request(connection, req, EVHTTP_REQ_POST, uri);
+ free(uri);
+
+ if (res == -1)
+ goto error;
+
+ return (0);
+
+error:
+ memset(&status, 0, sizeof(status));
+ status.error = EVRPC_STATUS_ERR_UNSTARTED;
+ (*ctx->cb)(&status, ctx->request, ctx->reply, ctx->cb_arg);
+ evrpc_request_wrapper_free(ctx);
+ return (-1);
+}
+
+int
+evrpc_make_request(struct evrpc_request_wrapper *ctx)
+{
+ struct evrpc_pool *pool = ctx->pool;
+
+ /* initialize the event structure for this rpc */
+ evtimer_set(&ctx->ev_timeout, evrpc_request_timeout, ctx);
+ if (pool->base != NULL)
+ event_base_set(pool->base, &ctx->ev_timeout);
+
+ /* we better have some available connections on the pool */
+ assert(TAILQ_FIRST(&pool->connections) != NULL);
+
+ /*
+ * if no connection is available, we queue the request on the pool,
+ * the next time a connection is empty, the rpc will be send on that.
+ */
+ TAILQ_INSERT_TAIL(&pool->requests, ctx, next);
+
+ evrpc_pool_schedule(pool);
+
+ return (0);
+}
+
+static void
+evrpc_reply_done(struct evhttp_request *req, void *arg)
+{
+ struct evrpc_request_wrapper *ctx = arg;
+ struct evrpc_pool *pool = ctx->pool;
+ struct evrpc_status status;
+ int res = -1;
+
+ /* cancel any timeout we might have scheduled */
+ event_del(&ctx->ev_timeout);
+
+ memset(&status, 0, sizeof(status));
+ status.http_req = req;
+
+ /* we need to get the reply now */
+ if (req != NULL) {
+ /* apply hooks to the incoming request */
+ if (evrpc_process_hooks(&pool->input_hooks,
+ req, req->input_buffer) == -1) {
+ status.error = EVRPC_STATUS_ERR_HOOKABORTED;
+ res = -1;
+ } else {
+ res = ctx->reply_unmarshal(ctx->reply,
+ req->input_buffer);
+ if (res == -1) {
+ status.error = EVRPC_STATUS_ERR_BADPAYLOAD;
+ }
+ }
+ } else {
+ status.error = EVRPC_STATUS_ERR_TIMEOUT;
+ }
+
+ if (res == -1) {
+ /* clear everything that we might have written previously */
+ ctx->reply_clear(ctx->reply);
+ }
+
+ (*ctx->cb)(&status, ctx->request, ctx->reply, ctx->cb_arg);
+
+ evrpc_request_wrapper_free(ctx);
+
+ /* the http layer owns the request structure */
+
+ /* see if we can schedule another request */
+ evrpc_pool_schedule(pool);
+}
+
+static void
+evrpc_pool_schedule(struct evrpc_pool *pool)
+{
+ struct evrpc_request_wrapper *ctx = TAILQ_FIRST(&pool->requests);
+ struct evhttp_connection *evcon;
+
+ /* if no requests are pending, we have no work */
+ if (ctx == NULL)
+ return;
+
+ if ((evcon = evrpc_pool_find_connection(pool)) != NULL) {
+ TAILQ_REMOVE(&pool->requests, ctx, next);
+ evrpc_schedule_request(evcon, ctx);
+ }
+}
+
+static void
+evrpc_request_timeout(int fd, short what, void *arg)
+{
+ struct evrpc_request_wrapper *ctx = arg;
+ struct evhttp_connection *evcon = ctx->evcon;
+ assert(evcon != NULL);
+
+ evhttp_connection_fail(evcon, EVCON_HTTP_TIMEOUT);
+}
diff --git a/chromium/base/third_party/libevent/evrpc.h b/chromium/base/third_party/libevent/evrpc.h
new file mode 100644
index 00000000000..7c16b95c775
--- /dev/null
+++ b/chromium/base/third_party/libevent/evrpc.h
@@ -0,0 +1,486 @@
+/*
+ * Copyright (c) 2006 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _EVRPC_H_
+#define _EVRPC_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @file evrpc.h
+ *
+ * This header files provides basic support for an RPC server and client.
+ *
+ * To support RPCs in a server, every supported RPC command needs to be
+ * defined and registered.
+ *
+ * EVRPC_HEADER(SendCommand, Request, Reply);
+ *
+ * SendCommand is the name of the RPC command.
+ * Request is the name of a structure generated by event_rpcgen.py.
+ * It contains all parameters relating to the SendCommand RPC. The
+ * server needs to fill in the Reply structure.
+ * Reply is the name of a structure generated by event_rpcgen.py. It
+ * contains the answer to the RPC.
+ *
+ * To register an RPC with an HTTP server, you need to first create an RPC
+ * base with:
+ *
+ * struct evrpc_base *base = evrpc_init(http);
+ *
+ * A specific RPC can then be registered with
+ *
+ * EVRPC_REGISTER(base, SendCommand, Request, Reply, FunctionCB, arg);
+ *
+ * when the server receives an appropriately formatted RPC, the user callback
+ * is invokved. The callback needs to fill in the reply structure.
+ *
+ * void FunctionCB(EVRPC_STRUCT(SendCommand)* rpc, void *arg);
+ *
+ * To send the reply, call EVRPC_REQUEST_DONE(rpc);
+ *
+ * See the regression test for an example.
+ */
+
+struct evbuffer;
+struct event_base;
+struct evrpc_req_generic;
+
+/* Encapsulates a request */
+struct evrpc {
+ TAILQ_ENTRY(evrpc) next;
+
+ /* the URI at which the request handler lives */
+ const char* uri;
+
+ /* creates a new request structure */
+ void *(*request_new)(void);
+
+ /* frees the request structure */
+ void (*request_free)(void *);
+
+ /* unmarshals the buffer into the proper request structure */
+ int (*request_unmarshal)(void *, struct evbuffer *);
+
+ /* creates a new reply structure */
+ void *(*reply_new)(void);
+
+ /* creates a new reply structure */
+ void (*reply_free)(void *);
+
+ /* verifies that the reply is valid */
+ int (*reply_complete)(void *);
+
+ /* marshals the reply into a buffer */
+ void (*reply_marshal)(struct evbuffer*, void *);
+
+ /* the callback invoked for each received rpc */
+ void (*cb)(struct evrpc_req_generic *, void *);
+ void *cb_arg;
+
+ /* reference for further configuration */
+ struct evrpc_base *base;
+};
+
+/** The type of a specific RPC Message
+ *
+ * @param rpcname the name of the RPC message
+ */
+#define EVRPC_STRUCT(rpcname) struct evrpc_req__##rpcname
+
+struct evhttp_request;
+struct evrpc_status;
+
+/* We alias the RPC specific structs to this voided one */
+struct evrpc_req_generic {
+ /* the unmarshaled request object */
+ void *request;
+
+ /* the empty reply object that needs to be filled in */
+ void *reply;
+
+ /*
+ * the static structure for this rpc; that can be used to
+ * automatically unmarshal and marshal the http buffers.
+ */
+ struct evrpc *rpc;
+
+ /*
+ * the http request structure on which we need to answer.
+ */
+ struct evhttp_request* http_req;
+
+ /*
+ * callback to reply and finish answering this rpc
+ */
+ void (*done)(struct evrpc_req_generic* rpc);
+};
+
+/** Creates the definitions and prototypes for an RPC
+ *
+ * You need to use EVRPC_HEADER to create structures and function prototypes
+ * needed by the server and client implementation. The structures have to be
+ * defined in an .rpc file and converted to source code via event_rpcgen.py
+ *
+ * @param rpcname the name of the RPC
+ * @param reqstruct the name of the RPC request structure
+ * @param replystruct the name of the RPC reply structure
+ * @see EVRPC_GENERATE()
+ */
+#define EVRPC_HEADER(rpcname, reqstruct, rplystruct) \
+EVRPC_STRUCT(rpcname) { \
+ struct reqstruct* request; \
+ struct rplystruct* reply; \
+ struct evrpc* rpc; \
+ struct evhttp_request* http_req; \
+ void (*done)(struct evrpc_status *, \
+ struct evrpc* rpc, void *request, void *reply); \
+}; \
+int evrpc_send_request_##rpcname(struct evrpc_pool *, \
+ struct reqstruct *, struct rplystruct *, \
+ void (*)(struct evrpc_status *, \
+ struct reqstruct *, struct rplystruct *, void *cbarg), \
+ void *);
+
+/** Generates the code for receiving and sending an RPC message
+ *
+ * EVRPC_GENERATE is used to create the code corresponding to sending
+ * and receiving a particular RPC message
+ *
+ * @param rpcname the name of the RPC
+ * @param reqstruct the name of the RPC request structure
+ * @param replystruct the name of the RPC reply structure
+ * @see EVRPC_HEADER()
+ */
+#define EVRPC_GENERATE(rpcname, reqstruct, rplystruct) \
+int evrpc_send_request_##rpcname(struct evrpc_pool *pool, \
+ struct reqstruct *request, struct rplystruct *reply, \
+ void (*cb)(struct evrpc_status *, \
+ struct reqstruct *, struct rplystruct *, void *cbarg), \
+ void *cbarg) { \
+ struct evrpc_status status; \
+ struct evrpc_request_wrapper *ctx; \
+ ctx = (struct evrpc_request_wrapper *) \
+ malloc(sizeof(struct evrpc_request_wrapper)); \
+ if (ctx == NULL) \
+ goto error; \
+ ctx->pool = pool; \
+ ctx->evcon = NULL; \
+ ctx->name = strdup(#rpcname); \
+ if (ctx->name == NULL) { \
+ free(ctx); \
+ goto error; \
+ } \
+ ctx->cb = (void (*)(struct evrpc_status *, \
+ void *, void *, void *))cb; \
+ ctx->cb_arg = cbarg; \
+ ctx->request = (void *)request; \
+ ctx->reply = (void *)reply; \
+ ctx->request_marshal = (void (*)(struct evbuffer *, void *))reqstruct##_marshal; \
+ ctx->reply_clear = (void (*)(void *))rplystruct##_clear; \
+ ctx->reply_unmarshal = (int (*)(void *, struct evbuffer *))rplystruct##_unmarshal; \
+ return (evrpc_make_request(ctx)); \
+error: \
+ memset(&status, 0, sizeof(status)); \
+ status.error = EVRPC_STATUS_ERR_UNSTARTED; \
+ (*(cb))(&status, request, reply, cbarg); \
+ return (-1); \
+}
+
+/** Provides access to the HTTP request object underlying an RPC
+ *
+ * Access to the underlying http object; can be used to look at headers or
+ * for getting the remote ip address
+ *
+ * @param rpc_req the rpc request structure provided to the server callback
+ * @return an struct evhttp_request object that can be inspected for
+ * HTTP headers or sender information.
+ */
+#define EVRPC_REQUEST_HTTP(rpc_req) (rpc_req)->http_req
+
+/** Creates the reply to an RPC request
+ *
+ * EVRPC_REQUEST_DONE is used to answer a request; the reply is expected
+ * to have been filled in. The request and reply pointers become invalid
+ * after this call has finished.
+ *
+ * @param rpc_req the rpc request structure provided to the server callback
+ */
+#define EVRPC_REQUEST_DONE(rpc_req) do { \
+ struct evrpc_req_generic *_req = (struct evrpc_req_generic *)(rpc_req); \
+ _req->done(_req); \
+} while (0)
+
+
+/* Takes a request object and fills it in with the right magic */
+#define EVRPC_REGISTER_OBJECT(rpc, name, request, reply) \
+ do { \
+ (rpc)->uri = strdup(#name); \
+ if ((rpc)->uri == NULL) { \
+ fprintf(stderr, "failed to register object\n"); \
+ exit(1); \
+ } \
+ (rpc)->request_new = (void *(*)(void))request##_new; \
+ (rpc)->request_free = (void (*)(void *))request##_free; \
+ (rpc)->request_unmarshal = (int (*)(void *, struct evbuffer *))request##_unmarshal; \
+ (rpc)->reply_new = (void *(*)(void))reply##_new; \
+ (rpc)->reply_free = (void (*)(void *))reply##_free; \
+ (rpc)->reply_complete = (int (*)(void *))reply##_complete; \
+ (rpc)->reply_marshal = (void (*)(struct evbuffer*, void *))reply##_marshal; \
+ } while (0)
+
+struct evrpc_base;
+struct evhttp;
+
+/* functions to start up the rpc system */
+
+/** Creates a new rpc base from which RPC requests can be received
+ *
+ * @param server a pointer to an existing HTTP server
+ * @return a newly allocated evrpc_base struct
+ * @see evrpc_free()
+ */
+struct evrpc_base *evrpc_init(struct evhttp *server);
+
+/**
+ * Frees the evrpc base
+ *
+ * For now, you are responsible for making sure that no rpcs are ongoing.
+ *
+ * @param base the evrpc_base object to be freed
+ * @see evrpc_init
+ */
+void evrpc_free(struct evrpc_base *base);
+
+/** register RPCs with the HTTP Server
+ *
+ * registers a new RPC with the HTTP server, each RPC needs to have
+ * a unique name under which it can be identified.
+ *
+ * @param base the evrpc_base structure in which the RPC should be
+ * registered.
+ * @param name the name of the RPC
+ * @param request the name of the RPC request structure
+ * @param reply the name of the RPC reply structure
+ * @param callback the callback that should be invoked when the RPC
+ * is received. The callback has the following prototype
+ * void (*callback)(EVRPC_STRUCT(Message)* rpc, void *arg)
+ * @param cbarg an additional parameter that can be passed to the callback.
+ * The parameter can be used to carry around state.
+ */
+#define EVRPC_REGISTER(base, name, request, reply, callback, cbarg) \
+ do { \
+ struct evrpc* rpc = (struct evrpc *)calloc(1, sizeof(struct evrpc)); \
+ EVRPC_REGISTER_OBJECT(rpc, name, request, reply); \
+ evrpc_register_rpc(base, rpc, \
+ (void (*)(struct evrpc_req_generic*, void *))callback, cbarg); \
+ } while (0)
+
+int evrpc_register_rpc(struct evrpc_base *, struct evrpc *,
+ void (*)(struct evrpc_req_generic*, void *), void *);
+
+/**
+ * Unregisters an already registered RPC
+ *
+ * @param base the evrpc_base object from which to unregister an RPC
+ * @param name the name of the rpc to unregister
+ * @return -1 on error or 0 when successful.
+ * @see EVRPC_REGISTER()
+ */
+#define EVRPC_UNREGISTER(base, name) evrpc_unregister_rpc(base, #name)
+
+int evrpc_unregister_rpc(struct evrpc_base *base, const char *name);
+
+/*
+ * Client-side RPC support
+ */
+
+struct evrpc_pool;
+struct evhttp_connection;
+
+/**
+ * provides information about the completed RPC request.
+ */
+struct evrpc_status {
+#define EVRPC_STATUS_ERR_NONE 0
+#define EVRPC_STATUS_ERR_TIMEOUT 1
+#define EVRPC_STATUS_ERR_BADPAYLOAD 2
+#define EVRPC_STATUS_ERR_UNSTARTED 3
+#define EVRPC_STATUS_ERR_HOOKABORTED 4
+ int error;
+
+ /* for looking at headers or other information */
+ struct evhttp_request *http_req;
+};
+
+struct evrpc_request_wrapper {
+ TAILQ_ENTRY(evrpc_request_wrapper) next;
+
+ /* pool on which this rpc request is being made */
+ struct evrpc_pool *pool;
+
+ /* connection on which the request is being sent */
+ struct evhttp_connection *evcon;
+
+ /* event for implementing request timeouts */
+ struct event ev_timeout;
+
+ /* the name of the rpc */
+ char *name;
+
+ /* callback */
+ void (*cb)(struct evrpc_status*, void *request, void *reply, void *arg);
+ void *cb_arg;
+
+ void *request;
+ void *reply;
+
+ /* unmarshals the buffer into the proper request structure */
+ void (*request_marshal)(struct evbuffer *, void *);
+
+ /* removes all stored state in the reply */
+ void (*reply_clear)(void *);
+
+ /* marshals the reply into a buffer */
+ int (*reply_unmarshal)(void *, struct evbuffer*);
+};
+
+/** launches an RPC and sends it to the server
+ *
+ * EVRPC_MAKE_REQUEST() is used by the client to send an RPC to the server.
+ *
+ * @param name the name of the RPC
+ * @param pool the evrpc_pool that contains the connection objects over which
+ * the request should be sent.
+ * @param request a pointer to the RPC request structure - it contains the
+ * data to be sent to the server.
+ * @param reply a pointer to the RPC reply structure. It is going to be filled
+ * if the request was answered successfully
+ * @param cb the callback to invoke when the RPC request has been answered
+ * @param cbarg an additional argument to be passed to the client
+ * @return 0 on success, -1 on failure
+ */
+#define EVRPC_MAKE_REQUEST(name, pool, request, reply, cb, cbarg) \
+ evrpc_send_request_##name(pool, request, reply, cb, cbarg)
+
+int evrpc_make_request(struct evrpc_request_wrapper *);
+
+/** creates an rpc connection pool
+ *
+ * a pool has a number of connections associated with it.
+ * rpc requests are always made via a pool.
+ *
+ * @param base a pointer to an struct event_based object; can be left NULL
+ * in singled-threaded applications
+ * @return a newly allocated struct evrpc_pool object
+ * @see evrpc_pool_free()
+ */
+struct evrpc_pool *evrpc_pool_new(struct event_base *base);
+/** frees an rpc connection pool
+ *
+ * @param pool a pointer to an evrpc_pool allocated via evrpc_pool_new()
+ * @see evrpc_pool_new()
+ */
+void evrpc_pool_free(struct evrpc_pool *pool);
+/*
+ * adds a connection over which rpc can be dispatched. the connection
+ * object must have been newly created.
+ */
+void evrpc_pool_add_connection(struct evrpc_pool *,
+ struct evhttp_connection *);
+
+/**
+ * Sets the timeout in secs after which a request has to complete. The
+ * RPC is completely aborted if it does not complete by then. Setting
+ * the timeout to 0 means that it never timeouts and can be used to
+ * implement callback type RPCs.
+ *
+ * Any connection already in the pool will be updated with the new
+ * timeout. Connections added to the pool after set_timeout has be
+ * called receive the pool timeout only if no timeout has been set
+ * for the connection itself.
+ *
+ * @param pool a pointer to a struct evrpc_pool object
+ * @param timeout_in_secs the number of seconds after which a request should
+ * timeout and a failure be returned to the callback.
+ */
+void evrpc_pool_set_timeout(struct evrpc_pool *pool, int timeout_in_secs);
+
+/**
+ * Hooks for changing the input and output of RPCs; this can be used to
+ * implement compression, authentication, encryption, ...
+ */
+
+enum EVRPC_HOOK_TYPE {
+ EVRPC_INPUT, /**< apply the function to an input hook */
+ EVRPC_OUTPUT /**< apply the function to an output hook */
+};
+
+#ifndef WIN32
+/** Deprecated alias for EVRPC_INPUT. Not available on windows, where it
+ * conflicts with platform headers. */
+#define INPUT EVRPC_INPUT
+/** Deprecated alias for EVRPC_OUTPUT. Not available on windows, where it
+ * conflicts with platform headers. */
+#define OUTPUT EVRPC_OUTPUT
+#endif
+
+/** adds a processing hook to either an rpc base or rpc pool
+ *
+ * If a hook returns -1, the processing is aborted.
+ *
+ * The add functions return handles that can be used for removing hooks.
+ *
+ * @param vbase a pointer to either struct evrpc_base or struct evrpc_pool
+ * @param hook_type either INPUT or OUTPUT
+ * @param cb the callback to call when the hook is activated
+ * @param cb_arg an additional argument for the callback
+ * @return a handle to the hook so it can be removed later
+ * @see evrpc_remove_hook()
+ */
+void *evrpc_add_hook(void *vbase,
+ enum EVRPC_HOOK_TYPE hook_type,
+ int (*cb)(struct evhttp_request *, struct evbuffer *, void *),
+ void *cb_arg);
+
+/** removes a previously added hook
+ *
+ * @param vbase a pointer to either struct evrpc_base or struct evrpc_pool
+ * @param hook_type either INPUT or OUTPUT
+ * @param handle a handle returned by evrpc_add_hook()
+ * @return 1 on success or 0 on failure
+ * @see evrpc_add_hook()
+ */
+int evrpc_remove_hook(void *vbase,
+ enum EVRPC_HOOK_TYPE hook_type,
+ void *handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _EVRPC_H_ */
diff --git a/chromium/base/third_party/libevent/evsignal.h b/chromium/base/third_party/libevent/evsignal.h
new file mode 100644
index 00000000000..076cd8dae33
--- /dev/null
+++ b/chromium/base/third_party/libevent/evsignal.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _EVSIGNAL_H_
+#define _EVSIGNAL_H_
+
+typedef void (*ev_sighandler_t)(int);
+
+struct evsignal_info {
+ struct event ev_signal;
+ int ev_signal_pair[2];
+ int ev_signal_added;
+ volatile sig_atomic_t evsignal_caught;
+ struct event_list evsigevents[NSIG];
+ sig_atomic_t evsigcaught[NSIG];
+#ifdef HAVE_SIGACTION
+ struct sigaction **sh_old;
+#else
+ ev_sighandler_t **sh_old;
+#endif
+ int sh_old_max;
+};
+int evsignal_init(struct event_base *);
+void evsignal_process(struct event_base *);
+int evsignal_add(struct event *);
+int evsignal_del(struct event *);
+void evsignal_dealloc(struct event_base *);
+
+#endif /* _EVSIGNAL_H_ */
diff --git a/chromium/base/third_party/libevent/evutil.c b/chromium/base/third_party/libevent/evutil.c
new file mode 100644
index 00000000000..cc6d0f46a9d
--- /dev/null
+++ b/chromium/base/third_party/libevent/evutil.c
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2007 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef WIN32
+#include <winsock2.h>
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#endif
+
+#include <sys/types.h>
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <errno.h>
+#if defined WIN32 && !defined(HAVE_GETTIMEOFDAY_H)
+#include <sys/timeb.h>
+#endif
+#include <stdio.h>
+#include <signal.h>
+
+#include <sys/queue.h>
+#include "event.h"
+#include "event-internal.h"
+#include "evutil.h"
+#include "log.h"
+
+int
+evutil_socketpair(int family, int type, int protocol, int fd[2])
+{
+#ifndef WIN32
+ return socketpair(family, type, protocol, fd);
+#else
+ /* This code is originally from Tor. Used with permission. */
+
+ /* This socketpair does not work when localhost is down. So
+ * it's really not the same thing at all. But it's close enough
+ * for now, and really, when localhost is down sometimes, we
+ * have other problems too.
+ */
+ int listener = -1;
+ int connector = -1;
+ int acceptor = -1;
+ struct sockaddr_in listen_addr;
+ struct sockaddr_in connect_addr;
+ int size;
+ int saved_errno = -1;
+
+ if (protocol
+#ifdef AF_UNIX
+ || family != AF_UNIX
+#endif
+ ) {
+ EVUTIL_SET_SOCKET_ERROR(WSAEAFNOSUPPORT);
+ return -1;
+ }
+ if (!fd) {
+ EVUTIL_SET_SOCKET_ERROR(WSAEINVAL);
+ return -1;
+ }
+
+ listener = socket(AF_INET, type, 0);
+ if (listener < 0)
+ return -1;
+ memset(&listen_addr, 0, sizeof(listen_addr));
+ listen_addr.sin_family = AF_INET;
+ listen_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ listen_addr.sin_port = 0; /* kernel chooses port. */
+ if (bind(listener, (struct sockaddr *) &listen_addr, sizeof (listen_addr))
+ == -1)
+ goto tidy_up_and_fail;
+ if (listen(listener, 1) == -1)
+ goto tidy_up_and_fail;
+
+ connector = socket(AF_INET, type, 0);
+ if (connector < 0)
+ goto tidy_up_and_fail;
+ /* We want to find out the port number to connect to. */
+ size = sizeof(connect_addr);
+ if (getsockname(listener, (struct sockaddr *) &connect_addr, &size) == -1)
+ goto tidy_up_and_fail;
+ if (size != sizeof (connect_addr))
+ goto abort_tidy_up_and_fail;
+ if (connect(connector, (struct sockaddr *) &connect_addr,
+ sizeof(connect_addr)) == -1)
+ goto tidy_up_and_fail;
+
+ size = sizeof(listen_addr);
+ acceptor = accept(listener, (struct sockaddr *) &listen_addr, &size);
+ if (acceptor < 0)
+ goto tidy_up_and_fail;
+ if (size != sizeof(listen_addr))
+ goto abort_tidy_up_and_fail;
+ EVUTIL_CLOSESOCKET(listener);
+ /* Now check we are talking to ourself by matching port and host on the
+ two sockets. */
+ if (getsockname(connector, (struct sockaddr *) &connect_addr, &size) == -1)
+ goto tidy_up_and_fail;
+ if (size != sizeof (connect_addr)
+ || listen_addr.sin_family != connect_addr.sin_family
+ || listen_addr.sin_addr.s_addr != connect_addr.sin_addr.s_addr
+ || listen_addr.sin_port != connect_addr.sin_port)
+ goto abort_tidy_up_and_fail;
+ fd[0] = connector;
+ fd[1] = acceptor;
+
+ return 0;
+
+ abort_tidy_up_and_fail:
+ saved_errno = WSAECONNABORTED;
+ tidy_up_and_fail:
+ if (saved_errno < 0)
+ saved_errno = WSAGetLastError();
+ if (listener != -1)
+ EVUTIL_CLOSESOCKET(listener);
+ if (connector != -1)
+ EVUTIL_CLOSESOCKET(connector);
+ if (acceptor != -1)
+ EVUTIL_CLOSESOCKET(acceptor);
+
+ EVUTIL_SET_SOCKET_ERROR(saved_errno);
+ return -1;
+#endif
+}
+
+int
+evutil_make_socket_nonblocking(int fd)
+{
+#ifdef WIN32
+ {
+ unsigned long nonblocking = 1;
+ ioctlsocket(fd, FIONBIO, (unsigned long*) &nonblocking);
+ }
+#else
+ {
+ int flags;
+ if ((flags = fcntl(fd, F_GETFL, NULL)) < 0) {
+ event_warn("fcntl(%d, F_GETFL)", fd);
+ return -1;
+ }
+ if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
+ event_warn("fcntl(%d, F_SETFL)", fd);
+ return -1;
+ }
+ }
+#endif
+ return 0;
+}
+
+ev_int64_t
+evutil_strtoll(const char *s, char **endptr, int base)
+{
+#ifdef HAVE_STRTOLL
+ return (ev_int64_t)strtoll(s, endptr, base);
+#elif SIZEOF_LONG == 8
+ return (ev_int64_t)strtol(s, endptr, base);
+#elif defined(WIN32) && defined(_MSC_VER) && _MSC_VER < 1300
+ /* XXXX on old versions of MS APIs, we only support base
+ * 10. */
+ ev_int64_t r;
+ if (base != 10)
+ return 0;
+ r = (ev_int64_t) _atoi64(s);
+ while (isspace(*s))
+ ++s;
+ while (isdigit(*s))
+ ++s;
+ if (endptr)
+ *endptr = (char*) s;
+ return r;
+#elif defined(WIN32)
+ return (ev_int64_t) _strtoi64(s, endptr, base);
+#else
+#error "I don't know how to parse 64-bit integers."
+#endif
+}
+
+#ifndef _EVENT_HAVE_GETTIMEOFDAY
+int
+evutil_gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+ struct _timeb tb;
+
+ if(tv == NULL)
+ return -1;
+
+ _ftime(&tb);
+ tv->tv_sec = (long) tb.time;
+ tv->tv_usec = ((int) tb.millitm) * 1000;
+ return 0;
+}
+#endif
+
+int
+evutil_snprintf(char *buf, size_t buflen, const char *format, ...)
+{
+ int r;
+ va_list ap;
+ va_start(ap, format);
+ r = evutil_vsnprintf(buf, buflen, format, ap);
+ va_end(ap);
+ return r;
+}
+
+int
+evutil_vsnprintf(char *buf, size_t buflen, const char *format, va_list ap)
+{
+#ifdef _MSC_VER
+ int r = _vsnprintf(buf, buflen, format, ap);
+ buf[buflen-1] = '\0';
+ if (r >= 0)
+ return r;
+ else
+ return _vscprintf(format, ap);
+#else
+ int r = vsnprintf(buf, buflen, format, ap);
+ buf[buflen-1] = '\0';
+ return r;
+#endif
+}
+
+static int
+evutil_issetugid(void)
+{
+#ifdef _EVENT_HAVE_ISSETUGID
+ return issetugid();
+#else
+
+#ifdef _EVENT_HAVE_GETEUID
+ if (getuid() != geteuid())
+ return 1;
+#endif
+#ifdef _EVENT_HAVE_GETEGID
+ if (getgid() != getegid())
+ return 1;
+#endif
+ return 0;
+#endif
+}
+
+const char *
+evutil_getenv(const char *varname)
+{
+ if (evutil_issetugid())
+ return NULL;
+
+ return getenv(varname);
+}
diff --git a/chromium/base/third_party/libevent/evutil.h b/chromium/base/third_party/libevent/evutil.h
new file mode 100644
index 00000000000..8b664b94242
--- /dev/null
+++ b/chromium/base/third_party/libevent/evutil.h
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2007 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _EVUTIL_H_
+#define _EVUTIL_H_
+
+/** @file evutil.h
+
+ Common convenience functions for cross-platform portability and
+ related socket manipulations.
+
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "event-config.h"
+#ifdef _EVENT_HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef _EVENT_HAVE_STDINT_H
+#include <stdint.h>
+#elif defined(_EVENT_HAVE_INTTYPES_H)
+#include <inttypes.h>
+#endif
+#ifdef _EVENT_HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#include <stdarg.h>
+
+#ifdef _EVENT_HAVE_UINT64_T
+#define ev_uint64_t uint64_t
+#define ev_int64_t int64_t
+#elif defined(WIN32)
+#define ev_uint64_t unsigned __int64
+#define ev_int64_t signed __int64
+#elif _EVENT_SIZEOF_LONG_LONG == 8
+#define ev_uint64_t unsigned long long
+#define ev_int64_t long long
+#elif _EVENT_SIZEOF_LONG == 8
+#define ev_uint64_t unsigned long
+#define ev_int64_t long
+#else
+#error "No way to define ev_uint64_t"
+#endif
+
+#ifdef _EVENT_HAVE_UINT32_T
+#define ev_uint32_t uint32_t
+#elif defined(WIN32)
+#define ev_uint32_t unsigned int
+#elif _EVENT_SIZEOF_LONG == 4
+#define ev_uint32_t unsigned long
+#elif _EVENT_SIZEOF_INT == 4
+#define ev_uint32_t unsigned int
+#else
+#error "No way to define ev_uint32_t"
+#endif
+
+#ifdef _EVENT_HAVE_UINT16_T
+#define ev_uint16_t uint16_t
+#elif defined(WIN32)
+#define ev_uint16_t unsigned short
+#elif _EVENT_SIZEOF_INT == 2
+#define ev_uint16_t unsigned int
+#elif _EVENT_SIZEOF_SHORT == 2
+#define ev_uint16_t unsigned short
+#else
+#error "No way to define ev_uint16_t"
+#endif
+
+#ifdef _EVENT_HAVE_UINT8_T
+#define ev_uint8_t uint8_t
+#else
+#define ev_uint8_t unsigned char
+#endif
+
+int evutil_socketpair(int d, int type, int protocol, int sv[2]);
+int evutil_make_socket_nonblocking(int sock);
+#ifdef WIN32
+#define EVUTIL_CLOSESOCKET(s) closesocket(s)
+#else
+#define EVUTIL_CLOSESOCKET(s) close(s)
+#endif
+
+#ifdef WIN32
+#define EVUTIL_SOCKET_ERROR() WSAGetLastError()
+#define EVUTIL_SET_SOCKET_ERROR(errcode) \
+ do { WSASetLastError(errcode); } while (0)
+#else
+#define EVUTIL_SOCKET_ERROR() (errno)
+#define EVUTIL_SET_SOCKET_ERROR(errcode) \
+ do { errno = (errcode); } while (0)
+#endif
+
+/*
+ * Manipulation functions for struct timeval
+ */
+#ifdef _EVENT_HAVE_TIMERADD
+#define evutil_timeradd(tvp, uvp, vvp) timeradd((tvp), (uvp), (vvp))
+#define evutil_timersub(tvp, uvp, vvp) timersub((tvp), (uvp), (vvp))
+#else
+#define evutil_timeradd(tvp, uvp, vvp) \
+ do { \
+ (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \
+ (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \
+ if ((vvp)->tv_usec >= 1000000) { \
+ (vvp)->tv_sec++; \
+ (vvp)->tv_usec -= 1000000; \
+ } \
+ } while (0)
+#define evutil_timersub(tvp, uvp, vvp) \
+ do { \
+ (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \
+ (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \
+ if ((vvp)->tv_usec < 0) { \
+ (vvp)->tv_sec--; \
+ (vvp)->tv_usec += 1000000; \
+ } \
+ } while (0)
+#endif /* !_EVENT_HAVE_HAVE_TIMERADD */
+
+#ifdef _EVENT_HAVE_TIMERCLEAR
+#define evutil_timerclear(tvp) timerclear(tvp)
+#else
+#define evutil_timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0
+#endif
+
+#define evutil_timercmp(tvp, uvp, cmp) \
+ (((tvp)->tv_sec == (uvp)->tv_sec) ? \
+ ((tvp)->tv_usec cmp (uvp)->tv_usec) : \
+ ((tvp)->tv_sec cmp (uvp)->tv_sec))
+
+#ifdef _EVENT_HAVE_TIMERISSET
+#define evutil_timerisset(tvp) timerisset(tvp)
+#else
+#define evutil_timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec)
+#endif
+
+
+/* big-int related functions */
+ev_int64_t evutil_strtoll(const char *s, char **endptr, int base);
+
+
+#ifdef _EVENT_HAVE_GETTIMEOFDAY
+#define evutil_gettimeofday(tv, tz) gettimeofday((tv), (tz))
+#else
+struct timezone;
+int evutil_gettimeofday(struct timeval *tv, struct timezone *tz);
+#endif
+
+int evutil_snprintf(char *buf, size_t buflen, const char *format, ...)
+#ifdef __GNUC__
+ __attribute__((format(printf, 3, 4)))
+#endif
+ ;
+int evutil_vsnprintf(char *buf, size_t buflen, const char *format, va_list ap);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _EVUTIL_H_ */
diff --git a/chromium/base/third_party/libevent/freebsd/config.h b/chromium/base/third_party/libevent/freebsd/config.h
new file mode 100644
index 00000000000..4fe3d6be66a
--- /dev/null
+++ b/chromium/base/third_party/libevent/freebsd/config.h
@@ -0,0 +1,266 @@
+/* config.h. Generated from config.h.in by configure. */
+/* config.h.in. Generated from configure.in by autoheader. */
+
+/* Define if clock_gettime is available in libc */
+#define DNS_USE_CPU_CLOCK_FOR_ID 1
+
+/* Define is no secure id variant is available */
+/* #undef DNS_USE_GETTIMEOFDAY_FOR_ID */
+
+/* Define to 1 if you have the `clock_gettime' function. */
+#define HAVE_CLOCK_GETTIME 1
+
+/* Define if /dev/poll is available */
+/* #undef HAVE_DEVPOLL */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define if your system supports the epoll system calls */
+/* #undef HAVE_EPOLL */
+
+/* Define to 1 if you have the `epoll_ctl' function. */
+/* #undef HAVE_EPOLL_CTL */
+
+/* Define if your system supports event ports */
+/* #undef HAVE_EVENT_PORTS */
+
+/* Define to 1 if you have the `fcntl' function. */
+#define HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if the system has the type `fd_mask'. */
+#define HAVE_FD_MASK 1
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#define HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `getegid' function. */
+#define HAVE_GETEGID 1
+
+/* Define to 1 if you have the `geteuid' function. */
+#define HAVE_GETEUID 1
+
+/* Define to 1 if you have the `getnameinfo' function. */
+#define HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the `inet_ntop' function. */
+#define HAVE_INET_NTOP 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `issetugid' function. */
+#define HAVE_ISSETUGID 1
+
+/* Define to 1 if you have the `kqueue' function. */
+#define HAVE_KQUEUE 1
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+/* #undef HAVE_LIBNSL */
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+/* #undef HAVE_LIBRESOLV */
+
+/* Define to 1 if you have the `rt' library (-lrt). */
+#define HAVE_LIBRT 1
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+/* #undef HAVE_LIBSOCKET */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <netinet/in6.h> header file. */
+/* #undef HAVE_NETINET_IN6_H */
+
+/* Define to 1 if you have the `poll' function. */
+#define HAVE_POLL 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define HAVE_POLL_H 1
+
+/* Define to 1 if you have the `port_create' function. */
+/* #undef HAVE_PORT_CREATE */
+
+/* Define to 1 if you have the <port.h> header file. */
+/* #undef HAVE_PORT_H */
+
+/* Define to 1 if you have the `select' function. */
+#define HAVE_SELECT 1
+
+/* Define if F_SETFD is defined in <fcntl.h> */
+#define HAVE_SETFD 1
+
+/* Define to 1 if you have the `sigaction' function. */
+#define HAVE_SIGACTION 1
+
+/* Define to 1 if you have the `signal' function. */
+#define HAVE_SIGNAL 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#define HAVE_STDARG_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+#define HAVE_STRLCPY 1
+
+/* Define to 1 if you have the `strsep' function. */
+#define HAVE_STRSEP 1
+
+/* Define to 1 if you have the `strtok_r' function. */
+#define HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the `strtoll' function. */
+#define HAVE_STRTOLL 1
+
+/* Define to 1 if the system has the type `struct in6_addr'. */
+#define HAVE_STRUCT_IN6_ADDR 1
+
+/* Define to 1 if you have the <sys/devpoll.h> header file. */
+/* #undef HAVE_SYS_DEVPOLL_H */
+
+/* Define to 1 if you have the <sys/epoll.h> header file. */
+/* #undef HAVE_SYS_EPOLL_H */
+
+/* Define to 1 if you have the <sys/event.h> header file. */
+#define HAVE_SYS_EVENT_H 1
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/queue.h> header file. */
+#define HAVE_SYS_QUEUE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
+#define HAVE_TAILQFOREACH 1
+
+/* Define if timeradd is defined in <sys/time.h> */
+#define HAVE_TIMERADD 1
+
+/* Define if timerclear is defined in <sys/time.h> */
+#define HAVE_TIMERCLEAR 1
+
+/* Define if timercmp is defined in <sys/time.h> */
+#define HAVE_TIMERCMP 1
+
+/* Define if timerisset is defined in <sys/time.h> */
+#define HAVE_TIMERISSET 1
+
+/* Define to 1 if the system has the type `uint16_t'. */
+#define HAVE_UINT16_T 1
+
+/* Define to 1 if the system has the type `uint32_t'. */
+#define HAVE_UINT32_T 1
+
+/* Define to 1 if the system has the type `uint64_t'. */
+#define HAVE_UINT64_T 1
+
+/* Define to 1 if the system has the type `uint8_t'. */
+#define HAVE_UINT8_T 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `vasprintf' function. */
+#define HAVE_VASPRINTF 1
+
+/* Define if kqueue works correctly with pipes */
+#define HAVE_WORKING_KQUEUE 1
+
+/* Name of package */
+#define PACKAGE "libevent"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION ""
+
+/* The size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 8
+
+/* The size of `long long', as computed by sizeof. */
+#define SIZEOF_LONG_LONG 8
+
+/* The size of `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Version number of package */
+#define VERSION "1.4.13-stable"
+
+/* Define to appropriate substitue if compiler doesnt have __func__ */
+/* #undef __func__ */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef pid_t */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* Define to unsigned int if you dont have it */
+/* #undef socklen_t */
diff --git a/chromium/base/third_party/libevent/freebsd/event-config.h b/chromium/base/third_party/libevent/freebsd/event-config.h
new file mode 100644
index 00000000000..be1eae4a890
--- /dev/null
+++ b/chromium/base/third_party/libevent/freebsd/event-config.h
@@ -0,0 +1,284 @@
+/* event-config.h
+ * Generated by autoconf; post-processed by libevent.
+ * Do not edit this file.
+ * Do not rely on macros in this file existing in later versions.
+ */
+#ifndef _EVENT_CONFIG_H_
+#define _EVENT_CONFIG_H_
+/* config.h. Generated from config.h.in by configure. */
+/* config.h.in. Generated from configure.in by autoheader. */
+
+/* Define if clock_gettime is available in libc */
+#define _EVENT_DNS_USE_CPU_CLOCK_FOR_ID 1
+
+/* Define is no secure id variant is available */
+/* #undef _EVENT_DNS_USE_GETTIMEOFDAY_FOR_ID */
+
+/* Define to 1 if you have the `clock_gettime' function. */
+#define _EVENT_HAVE_CLOCK_GETTIME 1
+
+/* Define if /dev/poll is available */
+/* #undef _EVENT_HAVE_DEVPOLL */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define _EVENT_HAVE_DLFCN_H 1
+
+/* Define if your system supports the epoll system calls */
+/* #undef _EVENT_HAVE_EPOLL */
+
+/* Define to 1 if you have the `epoll_ctl' function. */
+/* #undef _EVENT_HAVE_EPOLL_CTL */
+
+/* Define if your system supports event ports */
+/* #undef _EVENT_HAVE_EVENT_PORTS */
+
+/* Define to 1 if you have the `fcntl' function. */
+#define _EVENT_HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define _EVENT_HAVE_FCNTL_H 1
+
+/* Define to 1 if the system has the type `fd_mask'. */
+#define _EVENT_HAVE_FD_MASK 1
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#define _EVENT_HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `getegid' function. */
+#define _EVENT_HAVE_GETEGID 1
+
+/* Define to 1 if you have the `geteuid' function. */
+#define _EVENT_HAVE_GETEUID 1
+
+/* Define to 1 if you have the `getnameinfo' function. */
+#define _EVENT_HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define _EVENT_HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the `inet_ntop' function. */
+#define _EVENT_HAVE_INET_NTOP 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define _EVENT_HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `issetugid' function. */
+#define _EVENT_HAVE_ISSETUGID 1
+
+/* Define to 1 if you have the `kqueue' function. */
+#define _EVENT_HAVE_KQUEUE 1
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+/* #undef _EVENT_HAVE_LIBNSL */
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+/* #undef _EVENT_HAVE_LIBRESOLV */
+
+/* Define to 1 if you have the `rt' library (-lrt). */
+#define _EVENT_HAVE_LIBRT 1
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+/* #undef _EVENT_HAVE_LIBSOCKET */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define _EVENT_HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <netinet/in6.h> header file. */
+/* #undef _EVENT_HAVE_NETINET_IN6_H */
+
+/* Define to 1 if you have the `poll' function. */
+#define _EVENT_HAVE_POLL 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define _EVENT_HAVE_POLL_H 1
+
+/* Define to 1 if you have the `port_create' function. */
+/* #undef _EVENT_HAVE_PORT_CREATE */
+
+/* Define to 1 if you have the <port.h> header file. */
+/* #undef _EVENT_HAVE_PORT_H */
+
+/* Define to 1 if you have the `select' function. */
+#define _EVENT_HAVE_SELECT 1
+
+/* Define if F_SETFD is defined in <fcntl.h> */
+#define _EVENT_HAVE_SETFD 1
+
+/* Define to 1 if you have the `sigaction' function. */
+#define _EVENT_HAVE_SIGACTION 1
+
+/* Define to 1 if you have the `signal' function. */
+#define _EVENT_HAVE_SIGNAL 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define _EVENT_HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#define _EVENT_HAVE_STDARG_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define _EVENT_HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define _EVENT_HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define _EVENT_HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define _EVENT_HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+#define _EVENT_HAVE_STRLCPY 1
+
+/* Define to 1 if you have the `strsep' function. */
+#define _EVENT_HAVE_STRSEP 1
+
+/* Define to 1 if you have the `strtok_r' function. */
+#define _EVENT_HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the `strtoll' function. */
+#define _EVENT_HAVE_STRTOLL 1
+
+/* Define to 1 if the system has the type `struct in6_addr'. */
+#define _EVENT_HAVE_STRUCT_IN6_ADDR 1
+
+/* Define to 1 if you have the <sys/devpoll.h> header file. */
+/* #undef _EVENT_HAVE_SYS_DEVPOLL_H */
+
+/* Define to 1 if you have the <sys/epoll.h> header file. */
+/* #undef _EVENT_HAVE_SYS_EPOLL_H */
+
+/* Define to 1 if you have the <sys/event.h> header file. */
+#define _EVENT_HAVE_SYS_EVENT_H 1
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define _EVENT_HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define _EVENT_HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/queue.h> header file. */
+#define _EVENT_HAVE_SYS_QUEUE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define _EVENT_HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define _EVENT_HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define _EVENT_HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define _EVENT_HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define _EVENT_HAVE_SYS_TYPES_H 1
+
+/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
+#define _EVENT_HAVE_TAILQFOREACH 1
+
+/* Define if timeradd is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERADD 1
+
+/* Define if timerclear is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERCLEAR 1
+
+/* Define if timercmp is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERCMP 1
+
+/* Define if timerisset is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERISSET 1
+
+/* Define to 1 if the system has the type `uint16_t'. */
+#define _EVENT_HAVE_UINT16_T 1
+
+/* Define to 1 if the system has the type `uint32_t'. */
+#define _EVENT_HAVE_UINT32_T 1
+
+/* Define to 1 if the system has the type `uint64_t'. */
+#define _EVENT_HAVE_UINT64_T 1
+
+/* Define to 1 if the system has the type `uint8_t'. */
+#define _EVENT_HAVE_UINT8_T 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define _EVENT_HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `vasprintf' function. */
+#define _EVENT_HAVE_VASPRINTF 1
+
+/* Define if kqueue works correctly with pipes */
+#define _EVENT_HAVE_WORKING_KQUEUE 1
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+#define _EVENT_LT_OBJDIR ".libs/"
+
+/* Numeric representation of the version */
+#define _EVENT_NUMERIC_VERSION 0x01040f00
+
+/* Name of package */
+#define _EVENT_PACKAGE "libevent"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define _EVENT_PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define _EVENT_PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define _EVENT_PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define _EVENT_PACKAGE_TARNAME ""
+
+/* Define to the home page for this package. */
+#define _EVENT_PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define _EVENT_PACKAGE_VERSION ""
+
+/* The size of `int', as computed by sizeof. */
+#define _EVENT_SIZEOF_INT 4
+
+/* The size of `long', as computed by sizeof. */
+#define _EVENT_SIZEOF_LONG 8
+
+/* The size of `long long', as computed by sizeof. */
+#define _EVENT_SIZEOF_LONG_LONG 8
+
+/* The size of `short', as computed by sizeof. */
+#define _EVENT_SIZEOF_SHORT 2
+
+/* Define to 1 if you have the ANSI C header files. */
+#define _EVENT_STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define _EVENT_TIME_WITH_SYS_TIME 1
+
+/* Version number of package */
+#define _EVENT_VERSION "1.4.15"
+
+/* Define to appropriate substitue if compiler doesnt have __func__ */
+/* #undef _EVENT___func__ */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef _EVENT_const */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef _EVENT___cplusplus
+/* #undef _EVENT_inline */
+#endif
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef _EVENT_pid_t */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef _EVENT_size_t */
+
+/* Define to unsigned int if you dont have it */
+/* #undef _EVENT_socklen_t */
+#endif
diff --git a/chromium/base/third_party/libevent/http-internal.h b/chromium/base/third_party/libevent/http-internal.h
new file mode 100644
index 00000000000..9cd03cdd2bc
--- /dev/null
+++ b/chromium/base/third_party/libevent/http-internal.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2001 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * This header file contains definitions for dealing with HTTP requests
+ * that are internal to libevent. As user of the library, you should not
+ * need to know about these.
+ */
+
+#ifndef _HTTP_H_
+#define _HTTP_H_
+
+#define HTTP_CONNECT_TIMEOUT 45
+#define HTTP_WRITE_TIMEOUT 50
+#define HTTP_READ_TIMEOUT 50
+
+#define HTTP_PREFIX "http://"
+#define HTTP_DEFAULTPORT 80
+
+enum message_read_status {
+ ALL_DATA_READ = 1,
+ MORE_DATA_EXPECTED = 0,
+ DATA_CORRUPTED = -1,
+ REQUEST_CANCELED = -2
+};
+
+enum evhttp_connection_error {
+ EVCON_HTTP_TIMEOUT,
+ EVCON_HTTP_EOF,
+ EVCON_HTTP_INVALID_HEADER
+};
+
+struct evbuffer;
+struct addrinfo;
+struct evhttp_request;
+
+/* A stupid connection object - maybe make this a bufferevent later */
+
+enum evhttp_connection_state {
+ EVCON_DISCONNECTED, /**< not currently connected not trying either*/
+ EVCON_CONNECTING, /**< tries to currently connect */
+ EVCON_IDLE, /**< connection is established */
+ EVCON_READING_FIRSTLINE,/**< reading Request-Line (incoming conn) or
+ **< Status-Line (outgoing conn) */
+ EVCON_READING_HEADERS, /**< reading request/response headers */
+ EVCON_READING_BODY, /**< reading request/response body */
+ EVCON_READING_TRAILER, /**< reading request/response chunked trailer */
+ EVCON_WRITING /**< writing request/response headers/body */
+};
+
+struct event_base;
+
+struct evhttp_connection {
+ /* we use tailq only if they were created for an http server */
+ TAILQ_ENTRY(evhttp_connection) (next);
+
+ int fd;
+ struct event ev;
+ struct event close_ev;
+ struct evbuffer *input_buffer;
+ struct evbuffer *output_buffer;
+
+ char *bind_address; /* address to use for binding the src */
+ u_short bind_port; /* local port for binding the src */
+
+ char *address; /* address to connect to */
+ u_short port;
+
+ int flags;
+#define EVHTTP_CON_INCOMING 0x0001 /* only one request on it ever */
+#define EVHTTP_CON_OUTGOING 0x0002 /* multiple requests possible */
+#define EVHTTP_CON_CLOSEDETECT 0x0004 /* detecting if persistent close */
+
+ int timeout; /* timeout in seconds for events */
+ int retry_cnt; /* retry count */
+ int retry_max; /* maximum number of retries */
+
+ enum evhttp_connection_state state;
+
+ /* for server connections, the http server they are connected with */
+ struct evhttp *http_server;
+
+ TAILQ_HEAD(evcon_requestq, evhttp_request) requests;
+
+ void (*cb)(struct evhttp_connection *, void *);
+ void *cb_arg;
+
+ void (*closecb)(struct evhttp_connection *, void *);
+ void *closecb_arg;
+
+ struct event_base *base;
+};
+
+struct evhttp_cb {
+ TAILQ_ENTRY(evhttp_cb) next;
+
+ char *what;
+
+ void (*cb)(struct evhttp_request *req, void *);
+ void *cbarg;
+};
+
+/* both the http server as well as the rpc system need to queue connections */
+TAILQ_HEAD(evconq, evhttp_connection);
+
+/* each bound socket is stored in one of these */
+struct evhttp_bound_socket {
+ TAILQ_ENTRY(evhttp_bound_socket) (next);
+
+ struct event bind_ev;
+};
+
+struct evhttp {
+ TAILQ_HEAD(boundq, evhttp_bound_socket) sockets;
+
+ TAILQ_HEAD(httpcbq, evhttp_cb) callbacks;
+ struct evconq connections;
+
+ int timeout;
+
+ void (*gencb)(struct evhttp_request *req, void *);
+ void *gencbarg;
+
+ struct event_base *base;
+};
+
+/* resets the connection; can be reused for more requests */
+void evhttp_connection_reset(struct evhttp_connection *);
+
+/* connects if necessary */
+int evhttp_connection_connect(struct evhttp_connection *);
+
+/* notifies the current request that it failed; resets connection */
+void evhttp_connection_fail(struct evhttp_connection *,
+ enum evhttp_connection_error error);
+
+void evhttp_get_request(struct evhttp *, int, struct sockaddr *, socklen_t);
+
+int evhttp_hostportfile(char *, char **, u_short *, char **);
+
+int evhttp_parse_firstline(struct evhttp_request *, struct evbuffer*);
+int evhttp_parse_headers(struct evhttp_request *, struct evbuffer*);
+
+void evhttp_start_read(struct evhttp_connection *);
+void evhttp_make_header(struct evhttp_connection *, struct evhttp_request *);
+
+void evhttp_write_buffer(struct evhttp_connection *,
+ void (*)(struct evhttp_connection *, void *), void *);
+
+/* response sending HTML the data in the buffer */
+void evhttp_response_code(struct evhttp_request *, int, const char *);
+void evhttp_send_page(struct evhttp_request *, struct evbuffer *);
+
+#endif /* _HTTP_H */
diff --git a/chromium/base/third_party/libevent/http.c b/chromium/base/third_party/libevent/http.c
new file mode 100644
index 00000000000..4abce23934e
--- /dev/null
+++ b/chromium/base/third_party/libevent/http.c
@@ -0,0 +1,2885 @@
+/*
+ * Copyright (c) 2002-2006 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_SYS_IOCCOM_H
+#include <sys/ioccom.h>
+#endif
+
+#ifndef WIN32
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#endif
+
+#include <sys/queue.h>
+
+#ifndef WIN32
+#include <netinet/in.h>
+#include <netdb.h>
+#endif
+
+#ifdef WIN32
+#include <winsock2.h>
+#endif
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifndef WIN32
+#include <syslog.h>
+#endif
+#include <signal.h>
+#include <time.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#undef timeout_pending
+#undef timeout_initialized
+
+#include "strlcpy-internal.h"
+#include "event.h"
+#include "evhttp.h"
+#include "evutil.h"
+#include "log.h"
+#include "http-internal.h"
+
+#ifdef WIN32
+#define strcasecmp _stricmp
+#define strncasecmp _strnicmp
+#define strdup _strdup
+#endif
+
+#ifndef HAVE_GETNAMEINFO
+#define NI_MAXSERV 32
+#define NI_MAXHOST 1025
+
+#ifndef NI_NUMERICHOST
+#define NI_NUMERICHOST 1
+#endif
+
+#ifndef NI_NUMERICSERV
+#define NI_NUMERICSERV 2
+#endif
+
+static int
+fake_getnameinfo(const struct sockaddr *sa, size_t salen, char *host,
+ size_t hostlen, char *serv, size_t servlen, int flags)
+{
+ struct sockaddr_in *sin = (struct sockaddr_in *)sa;
+
+ if (serv != NULL) {
+ char tmpserv[16];
+ evutil_snprintf(tmpserv, sizeof(tmpserv),
+ "%d", ntohs(sin->sin_port));
+ if (strlcpy(serv, tmpserv, servlen) >= servlen)
+ return (-1);
+ }
+
+ if (host != NULL) {
+ if (flags & NI_NUMERICHOST) {
+ if (strlcpy(host, inet_ntoa(sin->sin_addr),
+ hostlen) >= hostlen)
+ return (-1);
+ else
+ return (0);
+ } else {
+ struct hostent *hp;
+ hp = gethostbyaddr((char *)&sin->sin_addr,
+ sizeof(struct in_addr), AF_INET);
+ if (hp == NULL)
+ return (-2);
+
+ if (strlcpy(host, hp->h_name, hostlen) >= hostlen)
+ return (-1);
+ else
+ return (0);
+ }
+ }
+ return (0);
+}
+
+#endif
+
+#ifndef HAVE_GETADDRINFO
+/* Apparently msvc2010 does have an addrinfo definition visible here */
+#if !defined(WIN32) || !defined(_MSC_VER) || (_MSC_VER < 1600)
+struct addrinfo {
+ int ai_family;
+ int ai_socktype;
+ int ai_protocol;
+ size_t ai_addrlen;
+ struct sockaddr *ai_addr;
+ struct addrinfo *ai_next;
+};
+#endif
+static int
+fake_getaddrinfo(const char *hostname, struct addrinfo *ai)
+{
+ struct hostent *he = NULL;
+ struct sockaddr_in *sa;
+ if (hostname) {
+ he = gethostbyname(hostname);
+ if (!he)
+ return (-1);
+ }
+ ai->ai_family = he ? he->h_addrtype : AF_INET;
+ ai->ai_socktype = SOCK_STREAM;
+ ai->ai_protocol = 0;
+ ai->ai_addrlen = sizeof(struct sockaddr_in);
+ if (NULL == (ai->ai_addr = malloc(ai->ai_addrlen)))
+ return (-1);
+ sa = (struct sockaddr_in*)ai->ai_addr;
+ memset(sa, 0, ai->ai_addrlen);
+ if (he) {
+ sa->sin_family = he->h_addrtype;
+ memcpy(&sa->sin_addr, he->h_addr_list[0], he->h_length);
+ } else {
+ sa->sin_family = AF_INET;
+ sa->sin_addr.s_addr = INADDR_ANY;
+ }
+ ai->ai_next = NULL;
+ return (0);
+}
+static void
+fake_freeaddrinfo(struct addrinfo *ai)
+{
+ free(ai->ai_addr);
+}
+#endif
+
+#ifndef MIN
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+
+/* wrapper for setting the base from the http server */
+#define EVHTTP_BASE_SET(x, y) do { \
+ if ((x)->base != NULL) event_base_set((x)->base, y); \
+} while (0)
+
+extern int debug;
+
+static int socket_connect(int fd, const char *address, unsigned short port);
+static int bind_socket_ai(struct addrinfo *, int reuse);
+static int bind_socket(const char *, u_short, int reuse);
+static void name_from_addr(struct sockaddr *, socklen_t, char **, char **);
+static int evhttp_associate_new_request_with_connection(
+ struct evhttp_connection *evcon);
+static void evhttp_connection_start_detectclose(
+ struct evhttp_connection *evcon);
+static void evhttp_connection_stop_detectclose(
+ struct evhttp_connection *evcon);
+static void evhttp_request_dispatch(struct evhttp_connection* evcon);
+static void evhttp_read_firstline(struct evhttp_connection *evcon,
+ struct evhttp_request *req);
+static void evhttp_read_header(struct evhttp_connection *evcon,
+ struct evhttp_request *req);
+static int evhttp_add_header_internal(struct evkeyvalq *headers,
+ const char *key, const char *value);
+static int evhttp_decode_uri_internal(const char *uri, size_t length,
+ char *ret, int always_decode_plus);
+
+void evhttp_read(int, short, void *);
+void evhttp_write(int, short, void *);
+
+#ifndef HAVE_STRSEP
+/* strsep replacement for platforms that lack it. Only works if
+ * del is one character long. */
+static char *
+strsep(char **s, const char *del)
+{
+ char *d, *tok;
+ assert(strlen(del) == 1);
+ if (!s || !*s)
+ return NULL;
+ tok = *s;
+ d = strstr(tok, del);
+ if (d) {
+ *d = '\0';
+ *s = d + 1;
+ } else
+ *s = NULL;
+ return tok;
+}
+#endif
+
+static const char *
+html_replace(char ch, char *buf)
+{
+ switch (ch) {
+ case '<':
+ return "&lt;";
+ case '>':
+ return "&gt;";
+ case '"':
+ return "&quot;";
+ case '\'':
+ return "&#039;";
+ case '&':
+ return "&amp;";
+ default:
+ break;
+ }
+
+ /* Echo the character back */
+ buf[0] = ch;
+ buf[1] = '\0';
+
+ return buf;
+}
+
+/*
+ * Replaces <, >, ", ' and & with &lt;, &gt;, &quot;,
+ * &#039; and &amp; correspondingly.
+ *
+ * The returned string needs to be freed by the caller.
+ */
+
+char *
+evhttp_htmlescape(const char *html)
+{
+ int i, new_size = 0, old_size = strlen(html);
+ char *escaped_html, *p;
+ char scratch_space[2];
+
+ for (i = 0; i < old_size; ++i)
+ new_size += strlen(html_replace(html[i], scratch_space));
+
+ p = escaped_html = malloc(new_size + 1);
+ if (escaped_html == NULL)
+ event_err(1, "%s: malloc(%d)", __func__, new_size + 1);
+ for (i = 0; i < old_size; ++i) {
+ const char *replaced = html_replace(html[i], scratch_space);
+ /* this is length checked */
+ strcpy(p, replaced);
+ p += strlen(replaced);
+ }
+
+ *p = '\0';
+
+ return (escaped_html);
+}
+
+static const char *
+evhttp_method(enum evhttp_cmd_type type)
+{
+ const char *method;
+
+ switch (type) {
+ case EVHTTP_REQ_GET:
+ method = "GET";
+ break;
+ case EVHTTP_REQ_POST:
+ method = "POST";
+ break;
+ case EVHTTP_REQ_HEAD:
+ method = "HEAD";
+ break;
+ default:
+ method = NULL;
+ break;
+ }
+
+ return (method);
+}
+
+static void
+evhttp_add_event(struct event *ev, int timeout, int default_timeout)
+{
+ if (timeout != 0) {
+ struct timeval tv;
+
+ evutil_timerclear(&tv);
+ tv.tv_sec = timeout != -1 ? timeout : default_timeout;
+ event_add(ev, &tv);
+ } else {
+ event_add(ev, NULL);
+ }
+}
+
+void
+evhttp_write_buffer(struct evhttp_connection *evcon,
+ void (*cb)(struct evhttp_connection *, void *), void *arg)
+{
+ event_debug(("%s: preparing to write buffer\n", __func__));
+
+ /* Set call back */
+ evcon->cb = cb;
+ evcon->cb_arg = arg;
+
+ /* check if the event is already pending */
+ if (event_pending(&evcon->ev, EV_WRITE|EV_TIMEOUT, NULL))
+ event_del(&evcon->ev);
+
+ event_set(&evcon->ev, evcon->fd, EV_WRITE, evhttp_write, evcon);
+ EVHTTP_BASE_SET(evcon, &evcon->ev);
+ evhttp_add_event(&evcon->ev, evcon->timeout, HTTP_WRITE_TIMEOUT);
+}
+
+static int
+evhttp_connected(struct evhttp_connection *evcon)
+{
+ switch (evcon->state) {
+ case EVCON_DISCONNECTED:
+ case EVCON_CONNECTING:
+ return (0);
+ case EVCON_IDLE:
+ case EVCON_READING_FIRSTLINE:
+ case EVCON_READING_HEADERS:
+ case EVCON_READING_BODY:
+ case EVCON_READING_TRAILER:
+ case EVCON_WRITING:
+ default:
+ return (1);
+ }
+}
+
+/*
+ * Create the headers needed for an HTTP request
+ */
+static void
+evhttp_make_header_request(struct evhttp_connection *evcon,
+ struct evhttp_request *req)
+{
+ const char *method;
+
+ evhttp_remove_header(req->output_headers, "Proxy-Connection");
+
+ /* Generate request line */
+ method = evhttp_method(req->type);
+ evbuffer_add_printf(evcon->output_buffer, "%s %s HTTP/%d.%d\r\n",
+ method, req->uri, req->major, req->minor);
+
+ /* Add the content length on a post request if missing */
+ if (req->type == EVHTTP_REQ_POST &&
+ evhttp_find_header(req->output_headers, "Content-Length") == NULL){
+ char size[22];
+ evutil_snprintf(size, sizeof(size), "%ld",
+ (long)EVBUFFER_LENGTH(req->output_buffer));
+ evhttp_add_header(req->output_headers, "Content-Length", size);
+ }
+}
+
+static int
+evhttp_is_connection_close(int flags, struct evkeyvalq* headers)
+{
+ if (flags & EVHTTP_PROXY_REQUEST) {
+ /* proxy connection */
+ const char *connection = evhttp_find_header(headers, "Proxy-Connection");
+ return (connection == NULL || strcasecmp(connection, "keep-alive") != 0);
+ } else {
+ const char *connection = evhttp_find_header(headers, "Connection");
+ return (connection != NULL && strcasecmp(connection, "close") == 0);
+ }
+}
+
+static int
+evhttp_is_connection_keepalive(struct evkeyvalq* headers)
+{
+ const char *connection = evhttp_find_header(headers, "Connection");
+ return (connection != NULL
+ && strncasecmp(connection, "keep-alive", 10) == 0);
+}
+
+static void
+evhttp_maybe_add_date_header(struct evkeyvalq *headers)
+{
+ if (evhttp_find_header(headers, "Date") == NULL) {
+ char date[50];
+#ifndef WIN32
+ struct tm cur;
+#endif
+ struct tm *cur_p;
+ time_t t = time(NULL);
+#ifdef WIN32
+ cur_p = gmtime(&t);
+#else
+ gmtime_r(&t, &cur);
+ cur_p = &cur;
+#endif
+ if (strftime(date, sizeof(date),
+ "%a, %d %b %Y %H:%M:%S GMT", cur_p) != 0) {
+ evhttp_add_header(headers, "Date", date);
+ }
+ }
+}
+
+static void
+evhttp_maybe_add_content_length_header(struct evkeyvalq *headers,
+ long content_length)
+{
+ if (evhttp_find_header(headers, "Transfer-Encoding") == NULL &&
+ evhttp_find_header(headers, "Content-Length") == NULL) {
+ char len[22];
+ evutil_snprintf(len, sizeof(len), "%ld", content_length);
+ evhttp_add_header(headers, "Content-Length", len);
+ }
+}
+
+/*
+ * Create the headers needed for an HTTP reply
+ */
+
+static void
+evhttp_make_header_response(struct evhttp_connection *evcon,
+ struct evhttp_request *req)
+{
+ int is_keepalive = evhttp_is_connection_keepalive(req->input_headers);
+ evbuffer_add_printf(evcon->output_buffer, "HTTP/%d.%d %d %s\r\n",
+ req->major, req->minor, req->response_code,
+ req->response_code_line);
+
+ if (req->major == 1) {
+ if (req->minor == 1)
+ evhttp_maybe_add_date_header(req->output_headers);
+
+ /*
+ * if the protocol is 1.0; and the connection was keep-alive
+ * we need to add a keep-alive header, too.
+ */
+ if (req->minor == 0 && is_keepalive)
+ evhttp_add_header(req->output_headers,
+ "Connection", "keep-alive");
+
+ if (req->minor == 1 || is_keepalive) {
+ /*
+ * we need to add the content length if the
+ * user did not give it, this is required for
+ * persistent connections to work.
+ */
+ evhttp_maybe_add_content_length_header(
+ req->output_headers,
+ (long)EVBUFFER_LENGTH(req->output_buffer));
+ }
+ }
+
+ /* Potentially add headers for unidentified content. */
+ if (EVBUFFER_LENGTH(req->output_buffer)) {
+ if (evhttp_find_header(req->output_headers,
+ "Content-Type") == NULL) {
+ evhttp_add_header(req->output_headers,
+ "Content-Type", "text/html; charset=ISO-8859-1");
+ }
+ }
+
+ /* if the request asked for a close, we send a close, too */
+ if (evhttp_is_connection_close(req->flags, req->input_headers)) {
+ evhttp_remove_header(req->output_headers, "Connection");
+ if (!(req->flags & EVHTTP_PROXY_REQUEST))
+ evhttp_add_header(req->output_headers, "Connection", "close");
+ evhttp_remove_header(req->output_headers, "Proxy-Connection");
+ }
+}
+
+void
+evhttp_make_header(struct evhttp_connection *evcon, struct evhttp_request *req)
+{
+ struct evkeyval *header;
+
+ /*
+ * Depending if this is a HTTP request or response, we might need to
+ * add some new headers or remove existing headers.
+ */
+ if (req->kind == EVHTTP_REQUEST) {
+ evhttp_make_header_request(evcon, req);
+ } else {
+ evhttp_make_header_response(evcon, req);
+ }
+
+ TAILQ_FOREACH(header, req->output_headers, next) {
+ evbuffer_add_printf(evcon->output_buffer, "%s: %s\r\n",
+ header->key, header->value);
+ }
+ evbuffer_add(evcon->output_buffer, "\r\n", 2);
+
+ if (EVBUFFER_LENGTH(req->output_buffer) > 0) {
+ /*
+ * For a request, we add the POST data, for a reply, this
+ * is the regular data.
+ */
+ evbuffer_add_buffer(evcon->output_buffer, req->output_buffer);
+ }
+}
+
+/* Separated host, port and file from URI */
+
+int
+evhttp_hostportfile(char *url, char **phost, u_short *pport, char **pfile)
+{
+ /* XXX not threadsafe. */
+ static char host[1024];
+ static char file[1024];
+ char *p;
+ const char *p2;
+ int len;
+ u_short port;
+
+ len = strlen(HTTP_PREFIX);
+ if (strncasecmp(url, HTTP_PREFIX, len))
+ return (-1);
+
+ url += len;
+
+ /* We might overrun */
+ if (strlcpy(host, url, sizeof (host)) >= sizeof(host))
+ return (-1);
+
+ p = strchr(host, '/');
+ if (p != NULL) {
+ *p = '\0';
+ p2 = p + 1;
+ } else
+ p2 = NULL;
+
+ if (pfile != NULL) {
+ /* Generate request file */
+ if (p2 == NULL)
+ p2 = "";
+ evutil_snprintf(file, sizeof(file), "/%s", p2);
+ }
+
+ p = strchr(host, ':');
+ if (p != NULL) {
+ *p = '\0';
+ port = atoi(p + 1);
+
+ if (port == 0)
+ return (-1);
+ } else
+ port = HTTP_DEFAULTPORT;
+
+ if (phost != NULL)
+ *phost = host;
+ if (pport != NULL)
+ *pport = port;
+ if (pfile != NULL)
+ *pfile = file;
+
+ return (0);
+}
+
+static int
+evhttp_connection_incoming_fail(struct evhttp_request *req,
+ enum evhttp_connection_error error)
+{
+ switch (error) {
+ case EVCON_HTTP_TIMEOUT:
+ case EVCON_HTTP_EOF:
+ /*
+ * these are cases in which we probably should just
+ * close the connection and not send a reply. this
+ * case may happen when a browser keeps a persistent
+ * connection open and we timeout on the read. when
+ * the request is still being used for sending, we
+ * need to disassociated it from the connection here.
+ */
+ if (!req->userdone) {
+ /* remove it so that it will not be freed */
+ TAILQ_REMOVE(&req->evcon->requests, req, next);
+ /* indicate that this request no longer has a
+ * connection object
+ */
+ req->evcon = NULL;
+ }
+ return (-1);
+ case EVCON_HTTP_INVALID_HEADER:
+ default: /* xxx: probably should just error on default */
+ /* the callback looks at the uri to determine errors */
+ if (req->uri) {
+ free(req->uri);
+ req->uri = NULL;
+ }
+
+ /*
+ * the callback needs to send a reply, once the reply has
+ * been send, the connection should get freed.
+ */
+ (*req->cb)(req, req->cb_arg);
+ }
+
+ return (0);
+}
+
+void
+evhttp_connection_fail(struct evhttp_connection *evcon,
+ enum evhttp_connection_error error)
+{
+ struct evhttp_request* req = TAILQ_FIRST(&evcon->requests);
+ void (*cb)(struct evhttp_request *, void *);
+ void *cb_arg;
+ assert(req != NULL);
+
+ if (evcon->flags & EVHTTP_CON_INCOMING) {
+ /*
+ * for incoming requests, there are two different
+ * failure cases. it's either a network level error
+ * or an http layer error. for problems on the network
+ * layer like timeouts we just drop the connections.
+ * For HTTP problems, we might have to send back a
+ * reply before the connection can be freed.
+ */
+ if (evhttp_connection_incoming_fail(req, error) == -1)
+ evhttp_connection_free(evcon);
+ return;
+ }
+
+ /* save the callback for later; the cb might free our object */
+ cb = req->cb;
+ cb_arg = req->cb_arg;
+
+ /* do not fail all requests; the next request is going to get
+ * send over a new connection. when a user cancels a request,
+ * all other pending requests should be processed as normal
+ */
+ TAILQ_REMOVE(&evcon->requests, req, next);
+ evhttp_request_free(req);
+
+ /* reset the connection */
+ evhttp_connection_reset(evcon);
+
+ /* We are trying the next request that was queued on us */
+ if (TAILQ_FIRST(&evcon->requests) != NULL)
+ evhttp_connection_connect(evcon);
+
+ /* inform the user */
+ if (cb != NULL)
+ (*cb)(NULL, cb_arg);
+}
+
+void
+evhttp_write(int fd, short what, void *arg)
+{
+ struct evhttp_connection *evcon = arg;
+ int n;
+
+ if (what == EV_TIMEOUT) {
+ evhttp_connection_fail(evcon, EVCON_HTTP_TIMEOUT);
+ return;
+ }
+
+ n = evbuffer_write(evcon->output_buffer, fd);
+ if (n == -1) {
+ event_debug(("%s: evbuffer_write", __func__));
+ evhttp_connection_fail(evcon, EVCON_HTTP_EOF);
+ return;
+ }
+
+ if (n == 0) {
+ event_debug(("%s: write nothing", __func__));
+ evhttp_connection_fail(evcon, EVCON_HTTP_EOF);
+ return;
+ }
+
+ if (EVBUFFER_LENGTH(evcon->output_buffer) != 0) {
+ evhttp_add_event(&evcon->ev,
+ evcon->timeout, HTTP_WRITE_TIMEOUT);
+ return;
+ }
+
+ /* Activate our call back */
+ if (evcon->cb != NULL)
+ (*evcon->cb)(evcon, evcon->cb_arg);
+}
+
+/**
+ * Advance the connection state.
+ * - If this is an outgoing connection, we've just processed the response;
+ * idle or close the connection.
+ * - If this is an incoming connection, we've just processed the request;
+ * respond.
+ */
+static void
+evhttp_connection_done(struct evhttp_connection *evcon)
+{
+ struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
+ int con_outgoing = evcon->flags & EVHTTP_CON_OUTGOING;
+
+ if (con_outgoing) {
+ /* idle or close the connection */
+ int need_close;
+ TAILQ_REMOVE(&evcon->requests, req, next);
+ req->evcon = NULL;
+
+ evcon->state = EVCON_IDLE;
+
+ need_close =
+ evhttp_is_connection_close(req->flags, req->input_headers)||
+ evhttp_is_connection_close(req->flags, req->output_headers);
+
+ /* check if we got asked to close the connection */
+ if (need_close)
+ evhttp_connection_reset(evcon);
+
+ if (TAILQ_FIRST(&evcon->requests) != NULL) {
+ /*
+ * We have more requests; reset the connection
+ * and deal with the next request.
+ */
+ if (!evhttp_connected(evcon))
+ evhttp_connection_connect(evcon);
+ else
+ evhttp_request_dispatch(evcon);
+ } else if (!need_close) {
+ /*
+ * The connection is going to be persistent, but we
+ * need to detect if the other side closes it.
+ */
+ evhttp_connection_start_detectclose(evcon);
+ }
+ } else if (evcon->state != EVCON_DISCONNECTED) {
+ /*
+ * incoming connection - we need to leave the request on the
+ * connection so that we can reply to it.
+ */
+ evcon->state = EVCON_WRITING;
+ }
+
+ /* notify the user of the request */
+ (*req->cb)(req, req->cb_arg);
+
+ /* if this was an outgoing request, we own and it's done. so free it */
+ if (con_outgoing) {
+ evhttp_request_free(req);
+ }
+}
+
+/*
+ * Handles reading from a chunked request.
+ * return ALL_DATA_READ:
+ * all data has been read
+ * return MORE_DATA_EXPECTED:
+ * more data is expected
+ * return DATA_CORRUPTED:
+ * data is corrupted
+ * return REQUEST_CANCLED:
+ * request was canceled by the user calling evhttp_cancel_request
+ */
+
+static enum message_read_status
+evhttp_handle_chunked_read(struct evhttp_request *req, struct evbuffer *buf)
+{
+ int len;
+
+ while ((len = EVBUFFER_LENGTH(buf)) > 0) {
+ if (req->ntoread < 0) {
+ /* Read chunk size */
+ ev_int64_t ntoread;
+ char *p = evbuffer_readline(buf);
+ char *endp;
+ int error;
+ if (p == NULL)
+ break;
+ /* the last chunk is on a new line? */
+ if (strlen(p) == 0) {
+ free(p);
+ continue;
+ }
+ ntoread = evutil_strtoll(p, &endp, 16);
+ error = (*p == '\0' ||
+ (*endp != '\0' && *endp != ' ') ||
+ ntoread < 0);
+ free(p);
+ if (error) {
+ /* could not get chunk size */
+ return (DATA_CORRUPTED);
+ }
+ req->ntoread = ntoread;
+ if (req->ntoread == 0) {
+ /* Last chunk */
+ return (ALL_DATA_READ);
+ }
+ continue;
+ }
+
+ /* don't have enough to complete a chunk; wait for more */
+ if (len < req->ntoread)
+ return (MORE_DATA_EXPECTED);
+
+ /* Completed chunk */
+ evbuffer_add(req->input_buffer,
+ EVBUFFER_DATA(buf), (size_t)req->ntoread);
+ evbuffer_drain(buf, (size_t)req->ntoread);
+ req->ntoread = -1;
+ if (req->chunk_cb != NULL) {
+ (*req->chunk_cb)(req, req->cb_arg);
+ evbuffer_drain(req->input_buffer,
+ EVBUFFER_LENGTH(req->input_buffer));
+ }
+ }
+
+ return (MORE_DATA_EXPECTED);
+}
+
+static void
+evhttp_read_trailer(struct evhttp_connection *evcon, struct evhttp_request *req)
+{
+ struct evbuffer *buf = evcon->input_buffer;
+
+ switch (evhttp_parse_headers(req, buf)) {
+ case DATA_CORRUPTED:
+ evhttp_connection_fail(evcon, EVCON_HTTP_INVALID_HEADER);
+ break;
+ case ALL_DATA_READ:
+ event_del(&evcon->ev);
+ evhttp_connection_done(evcon);
+ break;
+ case MORE_DATA_EXPECTED:
+ default:
+ evhttp_add_event(&evcon->ev, evcon->timeout,
+ HTTP_READ_TIMEOUT);
+ break;
+ }
+}
+
+static void
+evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req)
+{
+ struct evbuffer *buf = evcon->input_buffer;
+
+ if (req->chunked) {
+ switch (evhttp_handle_chunked_read(req, buf)) {
+ case ALL_DATA_READ:
+ /* finished last chunk */
+ evcon->state = EVCON_READING_TRAILER;
+ evhttp_read_trailer(evcon, req);
+ return;
+ case DATA_CORRUPTED:
+ /* corrupted data */
+ evhttp_connection_fail(evcon,
+ EVCON_HTTP_INVALID_HEADER);
+ return;
+ case REQUEST_CANCELED:
+ /* request canceled */
+ evhttp_request_free(req);
+ return;
+ case MORE_DATA_EXPECTED:
+ default:
+ break;
+ }
+ } else if (req->ntoread < 0) {
+ /* Read until connection close. */
+ evbuffer_add_buffer(req->input_buffer, buf);
+ } else if (EVBUFFER_LENGTH(buf) >= req->ntoread) {
+ /* Completed content length */
+ evbuffer_add(req->input_buffer, EVBUFFER_DATA(buf),
+ (size_t)req->ntoread);
+ evbuffer_drain(buf, (size_t)req->ntoread);
+ req->ntoread = 0;
+ evhttp_connection_done(evcon);
+ return;
+ }
+ /* Read more! */
+ event_set(&evcon->ev, evcon->fd, EV_READ, evhttp_read, evcon);
+ EVHTTP_BASE_SET(evcon, &evcon->ev);
+ evhttp_add_event(&evcon->ev, evcon->timeout, HTTP_READ_TIMEOUT);
+}
+
+/*
+ * Reads data into a buffer structure until no more data
+ * can be read on the file descriptor or we have read all
+ * the data that we wanted to read.
+ * Execute callback when done.
+ */
+
+void
+evhttp_read(int fd, short what, void *arg)
+{
+ struct evhttp_connection *evcon = arg;
+ struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
+ struct evbuffer *buf = evcon->input_buffer;
+ int n, len;
+
+ if (what == EV_TIMEOUT) {
+ evhttp_connection_fail(evcon, EVCON_HTTP_TIMEOUT);
+ return;
+ }
+ n = evbuffer_read(buf, fd, -1);
+ len = EVBUFFER_LENGTH(buf);
+ event_debug(("%s: got %d on %d\n", __func__, n, fd));
+
+ if (n == -1) {
+ if (errno != EINTR && errno != EAGAIN) {
+ event_debug(("%s: evbuffer_read", __func__));
+ evhttp_connection_fail(evcon, EVCON_HTTP_EOF);
+ } else {
+ evhttp_add_event(&evcon->ev, evcon->timeout,
+ HTTP_READ_TIMEOUT);
+ }
+ return;
+ } else if (n == 0) {
+ /* Connection closed */
+ evcon->state = EVCON_DISCONNECTED;
+ evhttp_connection_done(evcon);
+ return;
+ }
+
+ switch (evcon->state) {
+ case EVCON_READING_FIRSTLINE:
+ evhttp_read_firstline(evcon, req);
+ break;
+ case EVCON_READING_HEADERS:
+ evhttp_read_header(evcon, req);
+ break;
+ case EVCON_READING_BODY:
+ evhttp_read_body(evcon, req);
+ break;
+ case EVCON_READING_TRAILER:
+ evhttp_read_trailer(evcon, req);
+ break;
+ case EVCON_DISCONNECTED:
+ case EVCON_CONNECTING:
+ case EVCON_IDLE:
+ case EVCON_WRITING:
+ default:
+ event_errx(1, "%s: illegal connection state %d",
+ __func__, evcon->state);
+ }
+}
+
+static void
+evhttp_write_connectioncb(struct evhttp_connection *evcon, void *arg)
+{
+ /* This is after writing the request to the server */
+ struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
+ assert(req != NULL);
+
+ assert(evcon->state == EVCON_WRITING);
+
+ /* We are done writing our header and are now expecting the response */
+ req->kind = EVHTTP_RESPONSE;
+
+ evhttp_start_read(evcon);
+}
+
+/*
+ * Clean up a connection object
+ */
+
+void
+evhttp_connection_free(struct evhttp_connection *evcon)
+{
+ struct evhttp_request *req;
+
+ /* notify interested parties that this connection is going down */
+ if (evcon->fd != -1) {
+ if (evhttp_connected(evcon) && evcon->closecb != NULL)
+ (*evcon->closecb)(evcon, evcon->closecb_arg);
+ }
+
+ /* remove all requests that might be queued on this
+ * connection. for server connections, this should be empty.
+ * because it gets dequeued either in evhttp_connection_done or
+ * evhttp_connection_fail.
+ */
+ while ((req = TAILQ_FIRST(&evcon->requests)) != NULL) {
+ TAILQ_REMOVE(&evcon->requests, req, next);
+ evhttp_request_free(req);
+ }
+
+ if (evcon->http_server != NULL) {
+ struct evhttp *http = evcon->http_server;
+ TAILQ_REMOVE(&http->connections, evcon, next);
+ }
+
+ if (event_initialized(&evcon->close_ev))
+ event_del(&evcon->close_ev);
+
+ if (event_initialized(&evcon->ev))
+ event_del(&evcon->ev);
+
+ if (evcon->fd != -1)
+ EVUTIL_CLOSESOCKET(evcon->fd);
+
+ if (evcon->bind_address != NULL)
+ free(evcon->bind_address);
+
+ if (evcon->address != NULL)
+ free(evcon->address);
+
+ if (evcon->input_buffer != NULL)
+ evbuffer_free(evcon->input_buffer);
+
+ if (evcon->output_buffer != NULL)
+ evbuffer_free(evcon->output_buffer);
+
+ free(evcon);
+}
+
+void
+evhttp_connection_set_local_address(struct evhttp_connection *evcon,
+ const char *address)
+{
+ assert(evcon->state == EVCON_DISCONNECTED);
+ if (evcon->bind_address)
+ free(evcon->bind_address);
+ if ((evcon->bind_address = strdup(address)) == NULL)
+ event_err(1, "%s: strdup", __func__);
+}
+
+void
+evhttp_connection_set_local_port(struct evhttp_connection *evcon,
+ unsigned short port)
+{
+ assert(evcon->state == EVCON_DISCONNECTED);
+ evcon->bind_port = port;
+}
+
+static void
+evhttp_request_dispatch(struct evhttp_connection* evcon)
+{
+ struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
+
+ /* this should not usually happy but it's possible */
+ if (req == NULL)
+ return;
+
+ /* delete possible close detection events */
+ evhttp_connection_stop_detectclose(evcon);
+
+ /* we assume that the connection is connected already */
+ assert(evcon->state == EVCON_IDLE);
+
+ evcon->state = EVCON_WRITING;
+
+ /* Create the header from the store arguments */
+ evhttp_make_header(evcon, req);
+
+ evhttp_write_buffer(evcon, evhttp_write_connectioncb, NULL);
+}
+
+/* Reset our connection state */
+void
+evhttp_connection_reset(struct evhttp_connection *evcon)
+{
+ if (event_initialized(&evcon->ev))
+ event_del(&evcon->ev);
+
+ if (evcon->fd != -1) {
+ /* inform interested parties about connection close */
+ if (evhttp_connected(evcon) && evcon->closecb != NULL)
+ (*evcon->closecb)(evcon, evcon->closecb_arg);
+
+ EVUTIL_CLOSESOCKET(evcon->fd);
+ evcon->fd = -1;
+ }
+ evcon->state = EVCON_DISCONNECTED;
+
+ evbuffer_drain(evcon->input_buffer,
+ EVBUFFER_LENGTH(evcon->input_buffer));
+ evbuffer_drain(evcon->output_buffer,
+ EVBUFFER_LENGTH(evcon->output_buffer));
+}
+
+static void
+evhttp_detect_close_cb(int fd, short what, void *arg)
+{
+ struct evhttp_connection *evcon = arg;
+ evhttp_connection_reset(evcon);
+}
+
+static void
+evhttp_connection_start_detectclose(struct evhttp_connection *evcon)
+{
+ evcon->flags |= EVHTTP_CON_CLOSEDETECT;
+
+ if (event_initialized(&evcon->close_ev))
+ event_del(&evcon->close_ev);
+ event_set(&evcon->close_ev, evcon->fd, EV_READ,
+ evhttp_detect_close_cb, evcon);
+ EVHTTP_BASE_SET(evcon, &evcon->close_ev);
+ event_add(&evcon->close_ev, NULL);
+}
+
+static void
+evhttp_connection_stop_detectclose(struct evhttp_connection *evcon)
+{
+ evcon->flags &= ~EVHTTP_CON_CLOSEDETECT;
+ event_del(&evcon->close_ev);
+}
+
+static void
+evhttp_connection_retry(int fd, short what, void *arg)
+{
+ struct evhttp_connection *evcon = arg;
+
+ evcon->state = EVCON_DISCONNECTED;
+ evhttp_connection_connect(evcon);
+}
+
+/*
+ * Call back for asynchronous connection attempt.
+ */
+
+static void
+evhttp_connectioncb(int fd, short what, void *arg)
+{
+ struct evhttp_connection *evcon = arg;
+ int error;
+ socklen_t errsz = sizeof(error);
+
+ if (what == EV_TIMEOUT) {
+ event_debug(("%s: connection timeout for \"%s:%d\" on %d",
+ __func__, evcon->address, evcon->port, evcon->fd));
+ goto cleanup;
+ }
+
+ /* Check if the connection completed */
+ if (getsockopt(evcon->fd, SOL_SOCKET, SO_ERROR, (void*)&error,
+ &errsz) == -1) {
+ event_debug(("%s: getsockopt for \"%s:%d\" on %d",
+ __func__, evcon->address, evcon->port, evcon->fd));
+ goto cleanup;
+ }
+
+ if (error) {
+ event_debug(("%s: connect failed for \"%s:%d\" on %d: %s",
+ __func__, evcon->address, evcon->port, evcon->fd,
+ strerror(error)));
+ goto cleanup;
+ }
+
+ /* We are connected to the server now */
+ event_debug(("%s: connected to \"%s:%d\" on %d\n",
+ __func__, evcon->address, evcon->port, evcon->fd));
+
+ /* Reset the retry count as we were successful in connecting */
+ evcon->retry_cnt = 0;
+ evcon->state = EVCON_IDLE;
+
+ /* try to start requests that have queued up on this connection */
+ evhttp_request_dispatch(evcon);
+ return;
+
+ cleanup:
+ if (evcon->retry_max < 0 || evcon->retry_cnt < evcon->retry_max) {
+ evtimer_set(&evcon->ev, evhttp_connection_retry, evcon);
+ EVHTTP_BASE_SET(evcon, &evcon->ev);
+ evhttp_add_event(&evcon->ev, MIN(3600, 2 << evcon->retry_cnt),
+ HTTP_CONNECT_TIMEOUT);
+ evcon->retry_cnt++;
+ return;
+ }
+ evhttp_connection_reset(evcon);
+
+ /* for now, we just signal all requests by executing their callbacks */
+ while (TAILQ_FIRST(&evcon->requests) != NULL) {
+ struct evhttp_request *request = TAILQ_FIRST(&evcon->requests);
+ TAILQ_REMOVE(&evcon->requests, request, next);
+ request->evcon = NULL;
+
+ /* we might want to set an error here */
+ request->cb(request, request->cb_arg);
+ evhttp_request_free(request);
+ }
+}
+
+/*
+ * Check if we got a valid response code.
+ */
+
+static int
+evhttp_valid_response_code(int code)
+{
+ if (code == 0)
+ return (0);
+
+ return (1);
+}
+
+/* Parses the status line of a web server */
+
+static int
+evhttp_parse_response_line(struct evhttp_request *req, char *line)
+{
+ char *protocol;
+ char *number;
+ const char *readable = "";
+
+ protocol = strsep(&line, " ");
+ if (line == NULL)
+ return (-1);
+ number = strsep(&line, " ");
+ if (line != NULL)
+ readable = line;
+
+ if (strcmp(protocol, "HTTP/1.0") == 0) {
+ req->major = 1;
+ req->minor = 0;
+ } else if (strcmp(protocol, "HTTP/1.1") == 0) {
+ req->major = 1;
+ req->minor = 1;
+ } else {
+ event_debug(("%s: bad protocol \"%s\"",
+ __func__, protocol));
+ return (-1);
+ }
+
+ req->response_code = atoi(number);
+ if (!evhttp_valid_response_code(req->response_code)) {
+ event_debug(("%s: bad response code \"%s\"",
+ __func__, number));
+ return (-1);
+ }
+
+ if ((req->response_code_line = strdup(readable)) == NULL)
+ event_err(1, "%s: strdup", __func__);
+
+ return (0);
+}
+
+/* Parse the first line of a HTTP request */
+
+static int
+evhttp_parse_request_line(struct evhttp_request *req, char *line)
+{
+ char *method;
+ char *uri;
+ char *version;
+
+ /* Parse the request line */
+ method = strsep(&line, " ");
+ if (line == NULL)
+ return (-1);
+ uri = strsep(&line, " ");
+ if (line == NULL)
+ return (-1);
+ version = strsep(&line, " ");
+ if (line != NULL)
+ return (-1);
+
+ /* First line */
+ if (strcmp(method, "GET") == 0) {
+ req->type = EVHTTP_REQ_GET;
+ } else if (strcmp(method, "POST") == 0) {
+ req->type = EVHTTP_REQ_POST;
+ } else if (strcmp(method, "HEAD") == 0) {
+ req->type = EVHTTP_REQ_HEAD;
+ } else {
+ event_debug(("%s: bad method %s on request %p from %s",
+ __func__, method, req, req->remote_host));
+ return (-1);
+ }
+
+ if (strcmp(version, "HTTP/1.0") == 0) {
+ req->major = 1;
+ req->minor = 0;
+ } else if (strcmp(version, "HTTP/1.1") == 0) {
+ req->major = 1;
+ req->minor = 1;
+ } else {
+ event_debug(("%s: bad version %s on request %p from %s",
+ __func__, version, req, req->remote_host));
+ return (-1);
+ }
+
+ if ((req->uri = strdup(uri)) == NULL) {
+ event_debug(("%s: strdup", __func__));
+ return (-1);
+ }
+
+ /* determine if it's a proxy request */
+ if (strlen(req->uri) > 0 && req->uri[0] != '/')
+ req->flags |= EVHTTP_PROXY_REQUEST;
+
+ return (0);
+}
+
+const char *
+evhttp_find_header(const struct evkeyvalq *headers, const char *key)
+{
+ struct evkeyval *header;
+
+ TAILQ_FOREACH(header, headers, next) {
+ if (strcasecmp(header->key, key) == 0)
+ return (header->value);
+ }
+
+ return (NULL);
+}
+
+void
+evhttp_clear_headers(struct evkeyvalq *headers)
+{
+ struct evkeyval *header;
+
+ for (header = TAILQ_FIRST(headers);
+ header != NULL;
+ header = TAILQ_FIRST(headers)) {
+ TAILQ_REMOVE(headers, header, next);
+ free(header->key);
+ free(header->value);
+ free(header);
+ }
+}
+
+/*
+ * Returns 0, if the header was successfully removed.
+ * Returns -1, if the header could not be found.
+ */
+
+int
+evhttp_remove_header(struct evkeyvalq *headers, const char *key)
+{
+ struct evkeyval *header;
+
+ TAILQ_FOREACH(header, headers, next) {
+ if (strcasecmp(header->key, key) == 0)
+ break;
+ }
+
+ if (header == NULL)
+ return (-1);
+
+ /* Free and remove the header that we found */
+ TAILQ_REMOVE(headers, header, next);
+ free(header->key);
+ free(header->value);
+ free(header);
+
+ return (0);
+}
+
+static int
+evhttp_header_is_valid_value(const char *value)
+{
+ const char *p = value;
+
+ while ((p = strpbrk(p, "\r\n")) != NULL) {
+ /* we really expect only one new line */
+ p += strspn(p, "\r\n");
+ /* we expect a space or tab for continuation */
+ if (*p != ' ' && *p != '\t')
+ return (0);
+ }
+ return (1);
+}
+
+int
+evhttp_add_header(struct evkeyvalq *headers,
+ const char *key, const char *value)
+{
+ event_debug(("%s: key: %s val: %s\n", __func__, key, value));
+
+ if (strchr(key, '\r') != NULL || strchr(key, '\n') != NULL) {
+ /* drop illegal headers */
+ event_debug(("%s: dropping illegal header key\n", __func__));
+ return (-1);
+ }
+
+ if (!evhttp_header_is_valid_value(value)) {
+ event_debug(("%s: dropping illegal header value\n", __func__));
+ return (-1);
+ }
+
+ return (evhttp_add_header_internal(headers, key, value));
+}
+
+static int
+evhttp_add_header_internal(struct evkeyvalq *headers,
+ const char *key, const char *value)
+{
+ struct evkeyval *header = calloc(1, sizeof(struct evkeyval));
+ if (header == NULL) {
+ event_warn("%s: calloc", __func__);
+ return (-1);
+ }
+ if ((header->key = strdup(key)) == NULL) {
+ free(header);
+ event_warn("%s: strdup", __func__);
+ return (-1);
+ }
+ if ((header->value = strdup(value)) == NULL) {
+ free(header->key);
+ free(header);
+ event_warn("%s: strdup", __func__);
+ return (-1);
+ }
+
+ TAILQ_INSERT_TAIL(headers, header, next);
+
+ return (0);
+}
+
+/*
+ * Parses header lines from a request or a response into the specified
+ * request object given an event buffer.
+ *
+ * Returns
+ * DATA_CORRUPTED on error
+ * MORE_DATA_EXPECTED when we need to read more headers
+ * ALL_DATA_READ when all headers have been read.
+ */
+
+enum message_read_status
+evhttp_parse_firstline(struct evhttp_request *req, struct evbuffer *buffer)
+{
+ char *line;
+ enum message_read_status status = ALL_DATA_READ;
+
+ line = evbuffer_readline(buffer);
+ if (line == NULL)
+ return (MORE_DATA_EXPECTED);
+
+ switch (req->kind) {
+ case EVHTTP_REQUEST:
+ if (evhttp_parse_request_line(req, line) == -1)
+ status = DATA_CORRUPTED;
+ break;
+ case EVHTTP_RESPONSE:
+ if (evhttp_parse_response_line(req, line) == -1)
+ status = DATA_CORRUPTED;
+ break;
+ default:
+ status = DATA_CORRUPTED;
+ }
+
+ free(line);
+ return (status);
+}
+
+static int
+evhttp_append_to_last_header(struct evkeyvalq *headers, const char *line)
+{
+ struct evkeyval *header = TAILQ_LAST(headers, evkeyvalq);
+ char *newval;
+ size_t old_len, line_len;
+
+ if (header == NULL)
+ return (-1);
+
+ old_len = strlen(header->value);
+ line_len = strlen(line);
+
+ newval = realloc(header->value, old_len + line_len + 1);
+ if (newval == NULL)
+ return (-1);
+
+ memcpy(newval + old_len, line, line_len + 1);
+ header->value = newval;
+
+ return (0);
+}
+
+enum message_read_status
+evhttp_parse_headers(struct evhttp_request *req, struct evbuffer* buffer)
+{
+ char *line;
+ enum message_read_status status = MORE_DATA_EXPECTED;
+
+ struct evkeyvalq* headers = req->input_headers;
+ while ((line = evbuffer_readline(buffer))
+ != NULL) {
+ char *skey, *svalue;
+
+ if (*line == '\0') { /* Last header - Done */
+ status = ALL_DATA_READ;
+ free(line);
+ break;
+ }
+
+ /* Check if this is a continuation line */
+ if (*line == ' ' || *line == '\t') {
+ if (evhttp_append_to_last_header(headers, line) == -1)
+ goto error;
+ free(line);
+ continue;
+ }
+
+ /* Processing of header lines */
+ svalue = line;
+ skey = strsep(&svalue, ":");
+ if (svalue == NULL)
+ goto error;
+
+ svalue += strspn(svalue, " ");
+
+ if (evhttp_add_header(headers, skey, svalue) == -1)
+ goto error;
+
+ free(line);
+ }
+
+ return (status);
+
+ error:
+ free(line);
+ return (DATA_CORRUPTED);
+}
+
+static int
+evhttp_get_body_length(struct evhttp_request *req)
+{
+ struct evkeyvalq *headers = req->input_headers;
+ const char *content_length;
+ const char *connection;
+
+ content_length = evhttp_find_header(headers, "Content-Length");
+ connection = evhttp_find_header(headers, "Connection");
+
+ if (content_length == NULL && connection == NULL)
+ req->ntoread = -1;
+ else if (content_length == NULL &&
+ strcasecmp(connection, "Close") != 0) {
+ /* Bad combination, we don't know when it will end */
+ event_warnx("%s: we got no content length, but the "
+ "server wants to keep the connection open: %s.",
+ __func__, connection);
+ return (-1);
+ } else if (content_length == NULL) {
+ req->ntoread = -1;
+ } else {
+ char *endp;
+ ev_int64_t ntoread = evutil_strtoll(content_length, &endp, 10);
+ if (*content_length == '\0' || *endp != '\0' || ntoread < 0) {
+ event_debug(("%s: illegal content length: %s",
+ __func__, content_length));
+ return (-1);
+ }
+ req->ntoread = ntoread;
+ }
+
+ event_debug(("%s: bytes to read: %lld (in buffer %ld)\n",
+ __func__, req->ntoread,
+ EVBUFFER_LENGTH(req->evcon->input_buffer)));
+
+ return (0);
+}
+
+static void
+evhttp_get_body(struct evhttp_connection *evcon, struct evhttp_request *req)
+{
+ const char *xfer_enc;
+
+ /* If this is a request without a body, then we are done */
+ if (req->kind == EVHTTP_REQUEST && req->type != EVHTTP_REQ_POST) {
+ evhttp_connection_done(evcon);
+ return;
+ }
+ evcon->state = EVCON_READING_BODY;
+ xfer_enc = evhttp_find_header(req->input_headers, "Transfer-Encoding");
+ if (xfer_enc != NULL && strcasecmp(xfer_enc, "chunked") == 0) {
+ req->chunked = 1;
+ req->ntoread = -1;
+ } else {
+ if (evhttp_get_body_length(req) == -1) {
+ evhttp_connection_fail(evcon,
+ EVCON_HTTP_INVALID_HEADER);
+ return;
+ }
+ }
+ evhttp_read_body(evcon, req);
+}
+
+static void
+evhttp_read_firstline(struct evhttp_connection *evcon,
+ struct evhttp_request *req)
+{
+ enum message_read_status res;
+
+ res = evhttp_parse_firstline(req, evcon->input_buffer);
+ if (res == DATA_CORRUPTED) {
+ /* Error while reading, terminate */
+ event_debug(("%s: bad header lines on %d\n",
+ __func__, evcon->fd));
+ evhttp_connection_fail(evcon, EVCON_HTTP_INVALID_HEADER);
+ return;
+ } else if (res == MORE_DATA_EXPECTED) {
+ /* Need more header lines */
+ evhttp_add_event(&evcon->ev,
+ evcon->timeout, HTTP_READ_TIMEOUT);
+ return;
+ }
+
+ evcon->state = EVCON_READING_HEADERS;
+ evhttp_read_header(evcon, req);
+}
+
+static void
+evhttp_read_header(struct evhttp_connection *evcon, struct evhttp_request *req)
+{
+ enum message_read_status res;
+ int fd = evcon->fd;
+
+ res = evhttp_parse_headers(req, evcon->input_buffer);
+ if (res == DATA_CORRUPTED) {
+ /* Error while reading, terminate */
+ event_debug(("%s: bad header lines on %d\n", __func__, fd));
+ evhttp_connection_fail(evcon, EVCON_HTTP_INVALID_HEADER);
+ return;
+ } else if (res == MORE_DATA_EXPECTED) {
+ /* Need more header lines */
+ evhttp_add_event(&evcon->ev,
+ evcon->timeout, HTTP_READ_TIMEOUT);
+ return;
+ }
+
+ /* Done reading headers, do the real work */
+ switch (req->kind) {
+ case EVHTTP_REQUEST:
+ event_debug(("%s: checking for post data on %d\n",
+ __func__, fd));
+ evhttp_get_body(evcon, req);
+ break;
+
+ case EVHTTP_RESPONSE:
+ if (req->response_code == HTTP_NOCONTENT ||
+ req->response_code == HTTP_NOTMODIFIED ||
+ (req->response_code >= 100 && req->response_code < 200)) {
+ event_debug(("%s: skipping body for code %d\n",
+ __func__, req->response_code));
+ evhttp_connection_done(evcon);
+ } else {
+ event_debug(("%s: start of read body for %s on %d\n",
+ __func__, req->remote_host, fd));
+ evhttp_get_body(evcon, req);
+ }
+ break;
+
+ default:
+ event_warnx("%s: bad header on %d", __func__, fd);
+ evhttp_connection_fail(evcon, EVCON_HTTP_INVALID_HEADER);
+ break;
+ }
+}
+
+/*
+ * Creates a TCP connection to the specified port and executes a callback
+ * when finished. Failure or sucess is indicate by the passed connection
+ * object.
+ *
+ * Although this interface accepts a hostname, it is intended to take
+ * only numeric hostnames so that non-blocking DNS resolution can
+ * happen elsewhere.
+ */
+
+struct evhttp_connection *
+evhttp_connection_new(const char *address, unsigned short port)
+{
+ struct evhttp_connection *evcon = NULL;
+
+ event_debug(("Attempting connection to %s:%d\n", address, port));
+
+ if ((evcon = calloc(1, sizeof(struct evhttp_connection))) == NULL) {
+ event_warn("%s: calloc failed", __func__);
+ goto error;
+ }
+
+ evcon->fd = -1;
+ evcon->port = port;
+
+ evcon->timeout = -1;
+ evcon->retry_cnt = evcon->retry_max = 0;
+
+ if ((evcon->address = strdup(address)) == NULL) {
+ event_warn("%s: strdup failed", __func__);
+ goto error;
+ }
+
+ if ((evcon->input_buffer = evbuffer_new()) == NULL) {
+ event_warn("%s: evbuffer_new failed", __func__);
+ goto error;
+ }
+
+ if ((evcon->output_buffer = evbuffer_new()) == NULL) {
+ event_warn("%s: evbuffer_new failed", __func__);
+ goto error;
+ }
+
+ evcon->state = EVCON_DISCONNECTED;
+ TAILQ_INIT(&evcon->requests);
+
+ return (evcon);
+
+ error:
+ if (evcon != NULL)
+ evhttp_connection_free(evcon);
+ return (NULL);
+}
+
+void evhttp_connection_set_base(struct evhttp_connection *evcon,
+ struct event_base *base)
+{
+ assert(evcon->base == NULL);
+ assert(evcon->state == EVCON_DISCONNECTED);
+ evcon->base = base;
+}
+
+void
+evhttp_connection_set_timeout(struct evhttp_connection *evcon,
+ int timeout_in_secs)
+{
+ evcon->timeout = timeout_in_secs;
+}
+
+void
+evhttp_connection_set_retries(struct evhttp_connection *evcon,
+ int retry_max)
+{
+ evcon->retry_max = retry_max;
+}
+
+void
+evhttp_connection_set_closecb(struct evhttp_connection *evcon,
+ void (*cb)(struct evhttp_connection *, void *), void *cbarg)
+{
+ evcon->closecb = cb;
+ evcon->closecb_arg = cbarg;
+}
+
+void
+evhttp_connection_get_peer(struct evhttp_connection *evcon,
+ char **address, u_short *port)
+{
+ *address = evcon->address;
+ *port = evcon->port;
+}
+
+int
+evhttp_connection_connect(struct evhttp_connection *evcon)
+{
+ if (evcon->state == EVCON_CONNECTING)
+ return (0);
+
+ evhttp_connection_reset(evcon);
+
+ assert(!(evcon->flags & EVHTTP_CON_INCOMING));
+ evcon->flags |= EVHTTP_CON_OUTGOING;
+
+ evcon->fd = bind_socket(
+ evcon->bind_address, evcon->bind_port, 0 /*reuse*/);
+ if (evcon->fd == -1) {
+ event_debug(("%s: failed to bind to \"%s\"",
+ __func__, evcon->bind_address));
+ return (-1);
+ }
+
+ if (socket_connect(evcon->fd, evcon->address, evcon->port) == -1) {
+ EVUTIL_CLOSESOCKET(evcon->fd); evcon->fd = -1;
+ return (-1);
+ }
+
+ /* Set up a callback for successful connection setup */
+ event_set(&evcon->ev, evcon->fd, EV_WRITE, evhttp_connectioncb, evcon);
+ EVHTTP_BASE_SET(evcon, &evcon->ev);
+ evhttp_add_event(&evcon->ev, evcon->timeout, HTTP_CONNECT_TIMEOUT);
+
+ evcon->state = EVCON_CONNECTING;
+
+ return (0);
+}
+
+/*
+ * Starts an HTTP request on the provided evhttp_connection object.
+ * If the connection object is not connected to the web server already,
+ * this will start the connection.
+ */
+
+int
+evhttp_make_request(struct evhttp_connection *evcon,
+ struct evhttp_request *req,
+ enum evhttp_cmd_type type, const char *uri)
+{
+ /* We are making a request */
+ req->kind = EVHTTP_REQUEST;
+ req->type = type;
+ if (req->uri != NULL)
+ free(req->uri);
+ if ((req->uri = strdup(uri)) == NULL)
+ event_err(1, "%s: strdup", __func__);
+
+ /* Set the protocol version if it is not supplied */
+ if (!req->major && !req->minor) {
+ req->major = 1;
+ req->minor = 1;
+ }
+
+ assert(req->evcon == NULL);
+ req->evcon = evcon;
+ assert(!(req->flags & EVHTTP_REQ_OWN_CONNECTION));
+
+ TAILQ_INSERT_TAIL(&evcon->requests, req, next);
+
+ /* If the connection object is not connected; make it so */
+ if (!evhttp_connected(evcon))
+ return (evhttp_connection_connect(evcon));
+
+ /*
+ * If it's connected already and we are the first in the queue,
+ * then we can dispatch this request immediately. Otherwise, it
+ * will be dispatched once the pending requests are completed.
+ */
+ if (TAILQ_FIRST(&evcon->requests) == req)
+ evhttp_request_dispatch(evcon);
+
+ return (0);
+}
+
+/*
+ * Reads data from file descriptor into request structure
+ * Request structure needs to be set up correctly.
+ */
+
+void
+evhttp_start_read(struct evhttp_connection *evcon)
+{
+ /* Set up an event to read the headers */
+ if (event_initialized(&evcon->ev))
+ event_del(&evcon->ev);
+ event_set(&evcon->ev, evcon->fd, EV_READ, evhttp_read, evcon);
+ EVHTTP_BASE_SET(evcon, &evcon->ev);
+
+ evhttp_add_event(&evcon->ev, evcon->timeout, HTTP_READ_TIMEOUT);
+ evcon->state = EVCON_READING_FIRSTLINE;
+}
+
+static void
+evhttp_send_done(struct evhttp_connection *evcon, void *arg)
+{
+ int need_close;
+ struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
+ TAILQ_REMOVE(&evcon->requests, req, next);
+
+ /* delete possible close detection events */
+ evhttp_connection_stop_detectclose(evcon);
+
+ need_close =
+ (req->minor == 0 &&
+ !evhttp_is_connection_keepalive(req->input_headers))||
+ evhttp_is_connection_close(req->flags, req->input_headers) ||
+ evhttp_is_connection_close(req->flags, req->output_headers);
+
+ assert(req->flags & EVHTTP_REQ_OWN_CONNECTION);
+ evhttp_request_free(req);
+
+ if (need_close) {
+ evhttp_connection_free(evcon);
+ return;
+ }
+
+ /* we have a persistent connection; try to accept another request. */
+ if (evhttp_associate_new_request_with_connection(evcon) == -1)
+ evhttp_connection_free(evcon);
+}
+
+/*
+ * Returns an error page.
+ */
+
+void
+evhttp_send_error(struct evhttp_request *req, int error, const char *reason)
+{
+#define ERR_FORMAT "<HTML><HEAD>\n" \
+ "<TITLE>%d %s</TITLE>\n" \
+ "</HEAD><BODY>\n" \
+ "<H1>Method Not Implemented</H1>\n" \
+ "Invalid method in request<P>\n" \
+ "</BODY></HTML>\n"
+
+ struct evbuffer *buf = evbuffer_new();
+
+ /* close the connection on error */
+ evhttp_add_header(req->output_headers, "Connection", "close");
+
+ evhttp_response_code(req, error, reason);
+
+ evbuffer_add_printf(buf, ERR_FORMAT, error, reason);
+
+ evhttp_send_page(req, buf);
+
+ evbuffer_free(buf);
+#undef ERR_FORMAT
+}
+
+/* Requires that headers and response code are already set up */
+
+static inline void
+evhttp_send(struct evhttp_request *req, struct evbuffer *databuf)
+{
+ struct evhttp_connection *evcon = req->evcon;
+
+ if (evcon == NULL) {
+ evhttp_request_free(req);
+ return;
+ }
+
+ assert(TAILQ_FIRST(&evcon->requests) == req);
+
+ /* we expect no more calls form the user on this request */
+ req->userdone = 1;
+
+ /* xxx: not sure if we really should expose the data buffer this way */
+ if (databuf != NULL)
+ evbuffer_add_buffer(req->output_buffer, databuf);
+
+ /* Adds headers to the response */
+ evhttp_make_header(evcon, req);
+
+ evhttp_write_buffer(evcon, evhttp_send_done, NULL);
+}
+
+void
+evhttp_send_reply(struct evhttp_request *req, int code, const char *reason,
+ struct evbuffer *databuf)
+{
+ evhttp_response_code(req, code, reason);
+
+ evhttp_send(req, databuf);
+}
+
+void
+evhttp_send_reply_start(struct evhttp_request *req, int code,
+ const char *reason)
+{
+ evhttp_response_code(req, code, reason);
+ if (req->major == 1 && req->minor == 1) {
+ /* use chunked encoding for HTTP/1.1 */
+ evhttp_add_header(req->output_headers, "Transfer-Encoding",
+ "chunked");
+ req->chunked = 1;
+ }
+ evhttp_make_header(req->evcon, req);
+ evhttp_write_buffer(req->evcon, NULL, NULL);
+}
+
+void
+evhttp_send_reply_chunk(struct evhttp_request *req, struct evbuffer *databuf)
+{
+ struct evhttp_connection *evcon = req->evcon;
+
+ if (evcon == NULL)
+ return;
+
+ if (req->chunked) {
+ evbuffer_add_printf(evcon->output_buffer, "%x\r\n",
+ (unsigned)EVBUFFER_LENGTH(databuf));
+ }
+ evbuffer_add_buffer(evcon->output_buffer, databuf);
+ if (req->chunked) {
+ evbuffer_add(evcon->output_buffer, "\r\n", 2);
+ }
+ evhttp_write_buffer(evcon, NULL, NULL);
+}
+
+void
+evhttp_send_reply_end(struct evhttp_request *req)
+{
+ struct evhttp_connection *evcon = req->evcon;
+
+ if (evcon == NULL) {
+ evhttp_request_free(req);
+ return;
+ }
+
+ /* we expect no more calls form the user on this request */
+ req->userdone = 1;
+
+ if (req->chunked) {
+ evbuffer_add(req->evcon->output_buffer, "0\r\n\r\n", 5);
+ evhttp_write_buffer(req->evcon, evhttp_send_done, NULL);
+ req->chunked = 0;
+ } else if (!event_pending(&evcon->ev, EV_WRITE|EV_TIMEOUT, NULL)) {
+ /* let the connection know that we are done with the request */
+ evhttp_send_done(evcon, NULL);
+ } else {
+ /* make the callback execute after all data has been written */
+ evcon->cb = evhttp_send_done;
+ evcon->cb_arg = NULL;
+ }
+}
+
+void
+evhttp_response_code(struct evhttp_request *req, int code, const char *reason)
+{
+ req->kind = EVHTTP_RESPONSE;
+ req->response_code = code;
+ if (req->response_code_line != NULL)
+ free(req->response_code_line);
+ req->response_code_line = strdup(reason);
+}
+
+void
+evhttp_send_page(struct evhttp_request *req, struct evbuffer *databuf)
+{
+ if (!req->major || !req->minor) {
+ req->major = 1;
+ req->minor = 1;
+ }
+
+ if (req->kind != EVHTTP_RESPONSE)
+ evhttp_response_code(req, 200, "OK");
+
+ evhttp_clear_headers(req->output_headers);
+ evhttp_add_header(req->output_headers, "Content-Type", "text/html");
+ evhttp_add_header(req->output_headers, "Connection", "close");
+
+ evhttp_send(req, databuf);
+}
+
+static const char uri_chars[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0,
+ /* 64 */
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0,
+ /* 128 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 192 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+/*
+ * Helper functions to encode/decode a URI.
+ * The returned string must be freed by the caller.
+ */
+char *
+evhttp_encode_uri(const char *uri)
+{
+ struct evbuffer *buf = evbuffer_new();
+ char *p;
+
+ for (p = (char *)uri; *p != '\0'; p++) {
+ if (uri_chars[(u_char)(*p)]) {
+ evbuffer_add(buf, p, 1);
+ } else {
+ evbuffer_add_printf(buf, "%%%02X", (u_char)(*p));
+ }
+ }
+ evbuffer_add(buf, "", 1);
+ p = strdup((char *)EVBUFFER_DATA(buf));
+ evbuffer_free(buf);
+
+ return (p);
+}
+
+/*
+ * @param always_decode_plus: when true we transform plus to space even
+ * if we have not seen a ?.
+ */
+static int
+evhttp_decode_uri_internal(
+ const char *uri, size_t length, char *ret, int always_decode_plus)
+{
+ char c;
+ int i, j, in_query = always_decode_plus;
+
+ for (i = j = 0; uri[i] != '\0'; i++) {
+ c = uri[i];
+ if (c == '?') {
+ in_query = 1;
+ } else if (c == '+' && in_query) {
+ c = ' ';
+ } else if (c == '%' && isxdigit((unsigned char)uri[i+1]) &&
+ isxdigit((unsigned char)uri[i+2])) {
+ char tmp[] = { uri[i+1], uri[i+2], '\0' };
+ c = (char)strtol(tmp, NULL, 16);
+ i += 2;
+ }
+ ret[j++] = c;
+ }
+ ret[j] = '\0';
+
+ return (j);
+}
+
+char *
+evhttp_decode_uri(const char *uri)
+{
+ char *ret;
+
+ if ((ret = malloc(strlen(uri) + 1)) == NULL)
+ event_err(1, "%s: malloc(%lu)", __func__,
+ (unsigned long)(strlen(uri) + 1));
+
+ evhttp_decode_uri_internal(uri, strlen(uri),
+ ret, 0 /*always_decode_plus*/);
+
+ return (ret);
+}
+
+/*
+ * Helper function to parse out arguments in a query.
+ * The arguments are separated by key and value.
+ */
+
+void
+evhttp_parse_query(const char *uri, struct evkeyvalq *headers)
+{
+ char *line;
+ char *argument;
+ char *p;
+
+ TAILQ_INIT(headers);
+
+ /* No arguments - we are done */
+ if (strchr(uri, '?') == NULL)
+ return;
+
+ if ((line = strdup(uri)) == NULL)
+ event_err(1, "%s: strdup", __func__);
+
+
+ argument = line;
+
+ /* We already know that there has to be a ? */
+ strsep(&argument, "?");
+
+ p = argument;
+ while (p != NULL && *p != '\0') {
+ char *key, *value, *decoded_value;
+ argument = strsep(&p, "&");
+
+ value = argument;
+ key = strsep(&value, "=");
+ if (value == NULL)
+ goto error;
+
+ if ((decoded_value = malloc(strlen(value) + 1)) == NULL)
+ event_err(1, "%s: malloc", __func__);
+
+ evhttp_decode_uri_internal(value, strlen(value),
+ decoded_value, 1 /*always_decode_plus*/);
+ event_debug(("Query Param: %s -> %s\n", key, decoded_value));
+ evhttp_add_header_internal(headers, key, decoded_value);
+ free(decoded_value);
+ }
+
+ error:
+ free(line);
+}
+
+static struct evhttp_cb *
+evhttp_dispatch_callback(struct httpcbq *callbacks, struct evhttp_request *req)
+{
+ struct evhttp_cb *cb;
+ size_t offset = 0;
+
+ /* Test for different URLs */
+ char *p = strchr(req->uri, '?');
+ if (p != NULL)
+ offset = (size_t)(p - req->uri);
+
+ TAILQ_FOREACH(cb, callbacks, next) {
+ int res = 0;
+ if (p == NULL) {
+ res = strcmp(cb->what, req->uri) == 0;
+ } else {
+ res = ((strncmp(cb->what, req->uri, offset) == 0) &&
+ (cb->what[offset] == '\0'));
+ }
+
+ if (res)
+ return (cb);
+ }
+
+ return (NULL);
+}
+
+static void
+evhttp_handle_request(struct evhttp_request *req, void *arg)
+{
+ struct evhttp *http = arg;
+ struct evhttp_cb *cb = NULL;
+
+ event_debug(("%s: req->uri=%s", __func__, req->uri));
+ if (req->uri == NULL) {
+ event_debug(("%s: bad request", __func__));
+ if (req->evcon->state == EVCON_DISCONNECTED) {
+ evhttp_connection_fail(req->evcon, EVCON_HTTP_EOF);
+ } else {
+ event_debug(("%s: sending error", __func__));
+ evhttp_send_error(req, HTTP_BADREQUEST, "Bad Request");
+ }
+ return;
+ }
+
+ if ((cb = evhttp_dispatch_callback(&http->callbacks, req)) != NULL) {
+ (*cb->cb)(req, cb->cbarg);
+ return;
+ }
+
+ /* Generic call back */
+ if (http->gencb) {
+ (*http->gencb)(req, http->gencbarg);
+ return;
+ } else {
+ /* We need to send a 404 here */
+#define ERR_FORMAT "<html><head>" \
+ "<title>404 Not Found</title>" \
+ "</head><body>" \
+ "<h1>Not Found</h1>" \
+ "<p>The requested URL %s was not found on this server.</p>"\
+ "</body></html>\n"
+
+ char *escaped_html = evhttp_htmlescape(req->uri);
+ struct evbuffer *buf = evbuffer_new();
+
+ evhttp_response_code(req, HTTP_NOTFOUND, "Not Found");
+
+ evbuffer_add_printf(buf, ERR_FORMAT, escaped_html);
+
+ free(escaped_html);
+
+ evhttp_send_page(req, buf);
+
+ evbuffer_free(buf);
+#undef ERR_FORMAT
+ }
+}
+
+static void
+accept_socket(int fd, short what, void *arg)
+{
+ struct evhttp *http = arg;
+ struct sockaddr_storage ss;
+ socklen_t addrlen = sizeof(ss);
+ int nfd;
+
+ if ((nfd = accept(fd, (struct sockaddr *)&ss, &addrlen)) == -1) {
+ if (errno != EAGAIN && errno != EINTR)
+ event_warn("%s: bad accept", __func__);
+ return;
+ }
+ if (evutil_make_socket_nonblocking(nfd) < 0)
+ return;
+
+ evhttp_get_request(http, nfd, (struct sockaddr *)&ss, addrlen);
+}
+
+int
+evhttp_bind_socket(struct evhttp *http, const char *address, u_short port)
+{
+ int fd;
+ int res;
+
+ if ((fd = bind_socket(address, port, 1 /*reuse*/)) == -1)
+ return (-1);
+
+ if (listen(fd, 128) == -1) {
+ event_warn("%s: listen", __func__);
+ EVUTIL_CLOSESOCKET(fd);
+ return (-1);
+ }
+
+ res = evhttp_accept_socket(http, fd);
+
+ if (res != -1)
+ event_debug(("Bound to port %d - Awaiting connections ... ",
+ port));
+
+ return (res);
+}
+
+int
+evhttp_accept_socket(struct evhttp *http, int fd)
+{
+ struct evhttp_bound_socket *bound;
+ struct event *ev;
+ int res;
+
+ bound = malloc(sizeof(struct evhttp_bound_socket));
+ if (bound == NULL)
+ return (-1);
+
+ ev = &bound->bind_ev;
+
+ /* Schedule the socket for accepting */
+ event_set(ev, fd, EV_READ | EV_PERSIST, accept_socket, http);
+ EVHTTP_BASE_SET(http, ev);
+
+ res = event_add(ev, NULL);
+
+ if (res == -1) {
+ free(bound);
+ return (-1);
+ }
+
+ TAILQ_INSERT_TAIL(&http->sockets, bound, next);
+
+ return (0);
+}
+
+static struct evhttp*
+evhttp_new_object(void)
+{
+ struct evhttp *http = NULL;
+
+ if ((http = calloc(1, sizeof(struct evhttp))) == NULL) {
+ event_warn("%s: calloc", __func__);
+ return (NULL);
+ }
+
+ http->timeout = -1;
+
+ TAILQ_INIT(&http->sockets);
+ TAILQ_INIT(&http->callbacks);
+ TAILQ_INIT(&http->connections);
+
+ return (http);
+}
+
+struct evhttp *
+evhttp_new(struct event_base *base)
+{
+ struct evhttp *http = evhttp_new_object();
+
+ http->base = base;
+
+ return (http);
+}
+
+/*
+ * Start a web server on the specified address and port.
+ */
+
+struct evhttp *
+evhttp_start(const char *address, u_short port)
+{
+ struct evhttp *http = evhttp_new_object();
+
+ if (evhttp_bind_socket(http, address, port) == -1) {
+ free(http);
+ return (NULL);
+ }
+
+ return (http);
+}
+
+void
+evhttp_free(struct evhttp* http)
+{
+ struct evhttp_cb *http_cb;
+ struct evhttp_connection *evcon;
+ struct evhttp_bound_socket *bound;
+ int fd;
+
+ /* Remove the accepting part */
+ while ((bound = TAILQ_FIRST(&http->sockets)) != NULL) {
+ TAILQ_REMOVE(&http->sockets, bound, next);
+
+ fd = bound->bind_ev.ev_fd;
+ event_del(&bound->bind_ev);
+ EVUTIL_CLOSESOCKET(fd);
+
+ free(bound);
+ }
+
+ while ((evcon = TAILQ_FIRST(&http->connections)) != NULL) {
+ /* evhttp_connection_free removes the connection */
+ evhttp_connection_free(evcon);
+ }
+
+ while ((http_cb = TAILQ_FIRST(&http->callbacks)) != NULL) {
+ TAILQ_REMOVE(&http->callbacks, http_cb, next);
+ free(http_cb->what);
+ free(http_cb);
+ }
+
+ free(http);
+}
+
+void
+evhttp_set_timeout(struct evhttp* http, int timeout_in_secs)
+{
+ http->timeout = timeout_in_secs;
+}
+
+void
+evhttp_set_cb(struct evhttp *http, const char *uri,
+ void (*cb)(struct evhttp_request *, void *), void *cbarg)
+{
+ struct evhttp_cb *http_cb;
+
+ if ((http_cb = calloc(1, sizeof(struct evhttp_cb))) == NULL)
+ event_err(1, "%s: calloc", __func__);
+
+ http_cb->what = strdup(uri);
+ http_cb->cb = cb;
+ http_cb->cbarg = cbarg;
+
+ TAILQ_INSERT_TAIL(&http->callbacks, http_cb, next);
+}
+
+int
+evhttp_del_cb(struct evhttp *http, const char *uri)
+{
+ struct evhttp_cb *http_cb;
+
+ TAILQ_FOREACH(http_cb, &http->callbacks, next) {
+ if (strcmp(http_cb->what, uri) == 0)
+ break;
+ }
+ if (http_cb == NULL)
+ return (-1);
+
+ TAILQ_REMOVE(&http->callbacks, http_cb, next);
+ free(http_cb->what);
+ free(http_cb);
+
+ return (0);
+}
+
+void
+evhttp_set_gencb(struct evhttp *http,
+ void (*cb)(struct evhttp_request *, void *), void *cbarg)
+{
+ http->gencb = cb;
+ http->gencbarg = cbarg;
+}
+
+/*
+ * Request related functions
+ */
+
+struct evhttp_request *
+evhttp_request_new(void (*cb)(struct evhttp_request *, void *), void *arg)
+{
+ struct evhttp_request *req = NULL;
+
+ /* Allocate request structure */
+ if ((req = calloc(1, sizeof(struct evhttp_request))) == NULL) {
+ event_warn("%s: calloc", __func__);
+ goto error;
+ }
+
+ req->kind = EVHTTP_RESPONSE;
+ req->input_headers = calloc(1, sizeof(struct evkeyvalq));
+ if (req->input_headers == NULL) {
+ event_warn("%s: calloc", __func__);
+ goto error;
+ }
+ TAILQ_INIT(req->input_headers);
+
+ req->output_headers = calloc(1, sizeof(struct evkeyvalq));
+ if (req->output_headers == NULL) {
+ event_warn("%s: calloc", __func__);
+ goto error;
+ }
+ TAILQ_INIT(req->output_headers);
+
+ if ((req->input_buffer = evbuffer_new()) == NULL) {
+ event_warn("%s: evbuffer_new", __func__);
+ goto error;
+ }
+
+ if ((req->output_buffer = evbuffer_new()) == NULL) {
+ event_warn("%s: evbuffer_new", __func__);
+ goto error;
+ }
+
+ req->cb = cb;
+ req->cb_arg = arg;
+
+ return (req);
+
+ error:
+ if (req != NULL)
+ evhttp_request_free(req);
+ return (NULL);
+}
+
+void
+evhttp_request_free(struct evhttp_request *req)
+{
+ if (req->remote_host != NULL)
+ free(req->remote_host);
+ if (req->uri != NULL)
+ free(req->uri);
+ if (req->response_code_line != NULL)
+ free(req->response_code_line);
+
+ evhttp_clear_headers(req->input_headers);
+ free(req->input_headers);
+
+ evhttp_clear_headers(req->output_headers);
+ free(req->output_headers);
+
+ if (req->input_buffer != NULL)
+ evbuffer_free(req->input_buffer);
+
+ if (req->output_buffer != NULL)
+ evbuffer_free(req->output_buffer);
+
+ free(req);
+}
+
+struct evhttp_connection *
+evhttp_request_get_connection(struct evhttp_request *req)
+{
+ return req->evcon;
+}
+
+
+void
+evhttp_request_set_chunked_cb(struct evhttp_request *req,
+ void (*cb)(struct evhttp_request *, void *))
+{
+ req->chunk_cb = cb;
+}
+
+/*
+ * Allows for inspection of the request URI
+ */
+
+const char *
+evhttp_request_uri(struct evhttp_request *req) {
+ if (req->uri == NULL)
+ event_debug(("%s: request %p has no uri\n", __func__, req));
+ return (req->uri);
+}
+
+/*
+ * Takes a file descriptor to read a request from.
+ * The callback is executed once the whole request has been read.
+ */
+
+static struct evhttp_connection*
+evhttp_get_request_connection(
+ struct evhttp* http,
+ int fd, struct sockaddr *sa, socklen_t salen)
+{
+ struct evhttp_connection *evcon;
+ char *hostname = NULL, *portname = NULL;
+
+ name_from_addr(sa, salen, &hostname, &portname);
+ if (hostname == NULL || portname == NULL) {
+ if (hostname) free(hostname);
+ if (portname) free(portname);
+ return (NULL);
+ }
+
+ event_debug(("%s: new request from %s:%s on %d\n",
+ __func__, hostname, portname, fd));
+
+ /* we need a connection object to put the http request on */
+ evcon = evhttp_connection_new(hostname, atoi(portname));
+ free(hostname);
+ free(portname);
+ if (evcon == NULL)
+ return (NULL);
+
+ /* associate the base if we have one*/
+ evhttp_connection_set_base(evcon, http->base);
+
+ evcon->flags |= EVHTTP_CON_INCOMING;
+ evcon->state = EVCON_READING_FIRSTLINE;
+
+ evcon->fd = fd;
+
+ return (evcon);
+}
+
+static int
+evhttp_associate_new_request_with_connection(struct evhttp_connection *evcon)
+{
+ struct evhttp *http = evcon->http_server;
+ struct evhttp_request *req;
+ if ((req = evhttp_request_new(evhttp_handle_request, http)) == NULL)
+ return (-1);
+
+ req->evcon = evcon; /* the request ends up owning the connection */
+ req->flags |= EVHTTP_REQ_OWN_CONNECTION;
+
+ TAILQ_INSERT_TAIL(&evcon->requests, req, next);
+
+ req->kind = EVHTTP_REQUEST;
+
+ if ((req->remote_host = strdup(evcon->address)) == NULL)
+ event_err(1, "%s: strdup", __func__);
+ req->remote_port = evcon->port;
+
+ evhttp_start_read(evcon);
+
+ return (0);
+}
+
+void
+evhttp_get_request(struct evhttp *http, int fd,
+ struct sockaddr *sa, socklen_t salen)
+{
+ struct evhttp_connection *evcon;
+
+ evcon = evhttp_get_request_connection(http, fd, sa, salen);
+ if (evcon == NULL)
+ return;
+
+ /* the timeout can be used by the server to close idle connections */
+ if (http->timeout != -1)
+ evhttp_connection_set_timeout(evcon, http->timeout);
+
+ /*
+ * if we want to accept more than one request on a connection,
+ * we need to know which http server it belongs to.
+ */
+ evcon->http_server = http;
+ TAILQ_INSERT_TAIL(&http->connections, evcon, next);
+
+ if (evhttp_associate_new_request_with_connection(evcon) == -1)
+ evhttp_connection_free(evcon);
+}
+
+
+/*
+ * Network helper functions that we do not want to export to the rest of
+ * the world.
+ */
+#if 0 /* Unused */
+static struct addrinfo *
+addr_from_name(char *address)
+{
+#ifdef HAVE_GETADDRINFO
+ struct addrinfo ai, *aitop;
+ int ai_result;
+
+ memset(&ai, 0, sizeof(ai));
+ ai.ai_family = AF_INET;
+ ai.ai_socktype = SOCK_RAW;
+ ai.ai_flags = 0;
+ if ((ai_result = getaddrinfo(address, NULL, &ai, &aitop)) != 0) {
+ if ( ai_result == EAI_SYSTEM )
+ event_warn("getaddrinfo");
+ else
+ event_warnx("getaddrinfo: %s", gai_strerror(ai_result));
+ }
+
+ return (aitop);
+#else
+ assert(0);
+ return NULL; /* XXXXX Use gethostbyname, if this function is ever used. */
+#endif
+}
+#endif
+
+static void
+name_from_addr(struct sockaddr *sa, socklen_t salen,
+ char **phost, char **pport)
+{
+ char ntop[NI_MAXHOST];
+ char strport[NI_MAXSERV];
+ int ni_result;
+
+#ifdef HAVE_GETNAMEINFO
+ ni_result = getnameinfo(sa, salen,
+ ntop, sizeof(ntop), strport, sizeof(strport),
+ NI_NUMERICHOST|NI_NUMERICSERV);
+
+ if (ni_result != 0) {
+ if (ni_result == EAI_SYSTEM)
+ event_err(1, "getnameinfo failed");
+ else
+ event_errx(1, "getnameinfo failed: %s", gai_strerror(ni_result));
+ return;
+ }
+#else
+ ni_result = fake_getnameinfo(sa, salen,
+ ntop, sizeof(ntop), strport, sizeof(strport),
+ NI_NUMERICHOST|NI_NUMERICSERV);
+ if (ni_result != 0)
+ return;
+#endif
+ *phost = strdup(ntop);
+ *pport = strdup(strport);
+}
+
+/* Create a non-blocking socket and bind it */
+/* todo: rename this function */
+static int
+bind_socket_ai(struct addrinfo *ai, int reuse)
+{
+ int fd, on = 1, r;
+ int serrno;
+
+ /* Create listen socket */
+ fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (fd == -1) {
+ event_warn("socket");
+ return (-1);
+ }
+
+ if (evutil_make_socket_nonblocking(fd) < 0)
+ goto out;
+
+#ifndef WIN32
+ if (fcntl(fd, F_SETFD, 1) == -1) {
+ event_warn("fcntl(F_SETFD)");
+ goto out;
+ }
+#endif
+
+ setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on));
+ if (reuse) {
+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
+ (void *)&on, sizeof(on));
+ }
+
+ if (ai != NULL) {
+ r = bind(fd, ai->ai_addr, ai->ai_addrlen);
+ if (r == -1)
+ goto out;
+ }
+
+ return (fd);
+
+ out:
+ serrno = EVUTIL_SOCKET_ERROR();
+ EVUTIL_CLOSESOCKET(fd);
+ EVUTIL_SET_SOCKET_ERROR(serrno);
+ return (-1);
+}
+
+static struct addrinfo *
+make_addrinfo(const char *address, u_short port)
+{
+ struct addrinfo *aitop = NULL;
+
+#ifdef HAVE_GETADDRINFO
+ struct addrinfo ai;
+ char strport[NI_MAXSERV];
+ int ai_result;
+
+ memset(&ai, 0, sizeof(ai));
+ ai.ai_family = AF_INET;
+ ai.ai_socktype = SOCK_STREAM;
+ ai.ai_flags = AI_PASSIVE; /* turn NULL host name into INADDR_ANY */
+ evutil_snprintf(strport, sizeof(strport), "%d", port);
+ if ((ai_result = getaddrinfo(address, strport, &ai, &aitop)) != 0) {
+ if ( ai_result == EAI_SYSTEM )
+ event_warn("getaddrinfo");
+ else
+ event_warnx("getaddrinfo: %s", gai_strerror(ai_result));
+ return (NULL);
+ }
+#else
+ static int cur;
+ static struct addrinfo ai[2]; /* We will be returning the address of some of this memory so it has to last even after this call. */
+ if (++cur == 2) cur = 0; /* allow calling this function twice */
+
+ if (fake_getaddrinfo(address, &ai[cur]) < 0) {
+ event_warn("fake_getaddrinfo");
+ return (NULL);
+ }
+ aitop = &ai[cur];
+ ((struct sockaddr_in *) aitop->ai_addr)->sin_port = htons(port);
+#endif
+
+ return (aitop);
+}
+
+static int
+bind_socket(const char *address, u_short port, int reuse)
+{
+ int fd;
+ struct addrinfo *aitop = NULL;
+
+ /* just create an unbound socket */
+ if (address == NULL && port == 0)
+ return bind_socket_ai(NULL, 0);
+
+ aitop = make_addrinfo(address, port);
+
+ if (aitop == NULL)
+ return (-1);
+
+ fd = bind_socket_ai(aitop, reuse);
+
+#ifdef HAVE_GETADDRINFO
+ freeaddrinfo(aitop);
+#else
+ fake_freeaddrinfo(aitop);
+#endif
+
+ return (fd);
+}
+
+static int
+socket_connect(int fd, const char *address, unsigned short port)
+{
+ struct addrinfo *ai = make_addrinfo(address, port);
+ int res = -1;
+
+ if (ai == NULL) {
+ event_debug(("%s: make_addrinfo: \"%s:%d\"",
+ __func__, address, port));
+ return (-1);
+ }
+
+ if (connect(fd, ai->ai_addr, ai->ai_addrlen) == -1) {
+#ifdef WIN32
+ int tmp_error = WSAGetLastError();
+ if (tmp_error != WSAEWOULDBLOCK && tmp_error != WSAEINVAL &&
+ tmp_error != WSAEINPROGRESS) {
+ goto out;
+ }
+#else
+ if (errno != EINPROGRESS) {
+ goto out;
+ }
+#endif
+ }
+
+ /* everything is fine */
+ res = 0;
+
+out:
+#ifdef HAVE_GETADDRINFO
+ freeaddrinfo(ai);
+#else
+ fake_freeaddrinfo(ai);
+#endif
+
+ return (res);
+}
diff --git a/chromium/base/third_party/libevent/kqueue.c b/chromium/base/third_party/libevent/kqueue.c
new file mode 100644
index 00000000000..ee740eec1d6
--- /dev/null
+++ b/chromium/base/third_party/libevent/kqueue.c
@@ -0,0 +1,455 @@
+/* $OpenBSD: kqueue.c,v 1.5 2002/07/10 14:41:31 art Exp $ */
+
+/*
+ * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define _GNU_SOURCE 1
+
+#include <sys/types.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <sys/_libevent_time.h>
+#endif
+#include <sys/queue.h>
+#include <sys/event.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif
+
+/* Some platforms apparently define the udata field of struct kevent as
+ * intptr_t, whereas others define it as void*. There doesn't seem to be an
+ * easy way to tell them apart via autoconf, so we need to use OS macros. */
+#if defined(HAVE_INTTYPES_H) && !defined(__OpenBSD__) && !defined(__FreeBSD__) && !defined(__darwin__) && !defined(__APPLE__)
+#define PTR_TO_UDATA(x) ((intptr_t)(x))
+#else
+#define PTR_TO_UDATA(x) (x)
+#endif
+
+#include "event.h"
+#include "event-internal.h"
+#include "log.h"
+#include "evsignal.h"
+
+#define EVLIST_X_KQINKERNEL 0x1000
+
+#define NEVENT 64
+
+struct kqop {
+ struct kevent *changes;
+ int nchanges;
+ struct kevent *events;
+ struct event_list evsigevents[NSIG];
+ int nevents;
+ int kq;
+ pid_t pid;
+};
+
+static void *kq_init (struct event_base *);
+static int kq_add (void *, struct event *);
+static int kq_del (void *, struct event *);
+static int kq_dispatch (struct event_base *, void *, struct timeval *);
+static int kq_insert (struct kqop *, struct kevent *);
+static void kq_dealloc (struct event_base *, void *);
+
+const struct eventop kqops = {
+ "kqueue",
+ kq_init,
+ kq_add,
+ kq_del,
+ kq_dispatch,
+ kq_dealloc,
+ 1 /* need reinit */
+};
+
+static void *
+kq_init(struct event_base *base)
+{
+ int i, kq;
+ struct kqop *kqueueop;
+
+ /* Disable kqueue when this environment variable is set */
+ if (evutil_getenv("EVENT_NOKQUEUE"))
+ return (NULL);
+
+ if (!(kqueueop = calloc(1, sizeof(struct kqop))))
+ return (NULL);
+
+ /* Initalize the kernel queue */
+
+ if ((kq = kqueue()) == -1) {
+ event_warn("kqueue");
+ free (kqueueop);
+ return (NULL);
+ }
+
+ kqueueop->kq = kq;
+
+ kqueueop->pid = getpid();
+
+ /* Initalize fields */
+ kqueueop->changes = malloc(NEVENT * sizeof(struct kevent));
+ if (kqueueop->changes == NULL) {
+ free (kqueueop);
+ return (NULL);
+ }
+ kqueueop->events = malloc(NEVENT * sizeof(struct kevent));
+ if (kqueueop->events == NULL) {
+ free (kqueueop->changes);
+ free (kqueueop);
+ return (NULL);
+ }
+ kqueueop->nevents = NEVENT;
+
+ /* we need to keep track of multiple events per signal */
+ for (i = 0; i < NSIG; ++i) {
+ TAILQ_INIT(&kqueueop->evsigevents[i]);
+ }
+
+ /* Check for Mac OS X kqueue bug. */
+ memset(&kqueueop->changes[0], 0, sizeof kqueueop->changes[0]);
+ kqueueop->changes[0].ident = -1;
+ kqueueop->changes[0].filter = EVFILT_READ;
+ kqueueop->changes[0].flags = EV_ADD;
+ /*
+ * If kqueue works, then kevent will succeed, and it will
+ * stick an error in events[0]. If kqueue is broken, then
+ * kevent will fail.
+ */
+ if (kevent(kq,
+ kqueueop->changes, 1, kqueueop->events, NEVENT, NULL) != 1 ||
+ kqueueop->events[0].ident != -1 ||
+ kqueueop->events[0].flags != EV_ERROR) {
+ event_warn("%s: detected broken kqueue; not using.", __func__);
+ free(kqueueop->changes);
+ free(kqueueop->events);
+ free(kqueueop);
+ close(kq);
+ return (NULL);
+ }
+
+ return (kqueueop);
+}
+
+static int
+kq_insert(struct kqop *kqop, struct kevent *kev)
+{
+ int nevents = kqop->nevents;
+
+ if (kqop->nchanges == nevents) {
+ struct kevent *newchange;
+ struct kevent *newresult;
+
+ nevents *= 2;
+
+ newchange = realloc(kqop->changes,
+ nevents * sizeof(struct kevent));
+ if (newchange == NULL) {
+ event_warn("%s: malloc", __func__);
+ return (-1);
+ }
+ kqop->changes = newchange;
+
+ newresult = realloc(kqop->events,
+ nevents * sizeof(struct kevent));
+
+ /*
+ * If we fail, we don't have to worry about freeing,
+ * the next realloc will pick it up.
+ */
+ if (newresult == NULL) {
+ event_warn("%s: malloc", __func__);
+ return (-1);
+ }
+ kqop->events = newresult;
+
+ kqop->nevents = nevents;
+ }
+
+ memcpy(&kqop->changes[kqop->nchanges++], kev, sizeof(struct kevent));
+
+ event_debug(("%s: fd %d %s%s",
+ __func__, (int)kev->ident,
+ kev->filter == EVFILT_READ ? "EVFILT_READ" : "EVFILT_WRITE",
+ kev->flags == EV_DELETE ? " (del)" : ""));
+
+ return (0);
+}
+
+static void
+kq_sighandler(int sig)
+{
+ /* Do nothing here */
+}
+
+static int
+kq_dispatch(struct event_base *base, void *arg, struct timeval *tv)
+{
+ struct kqop *kqop = arg;
+ struct kevent *changes = kqop->changes;
+ struct kevent *events = kqop->events;
+ struct event *ev;
+ struct timespec ts, *ts_p = NULL;
+ int i, res;
+
+ if (tv != NULL) {
+ TIMEVAL_TO_TIMESPEC(tv, &ts);
+ ts_p = &ts;
+ }
+
+ res = kevent(kqop->kq, changes, kqop->nchanges,
+ events, kqop->nevents, ts_p);
+ kqop->nchanges = 0;
+ if (res == -1) {
+ if (errno != EINTR) {
+ event_warn("kevent");
+ return (-1);
+ }
+
+ return (0);
+ }
+
+ event_debug(("%s: kevent reports %d", __func__, res));
+
+ for (i = 0; i < res; i++) {
+ int which = 0;
+
+ if (events[i].flags & EV_ERROR) {
+ /*
+ * Error messages that can happen, when a delete fails.
+ * EBADF happens when the file discriptor has been
+ * closed,
+ * ENOENT when the file discriptor was closed and
+ * then reopened.
+ * EINVAL for some reasons not understood; EINVAL
+ * should not be returned ever; but FreeBSD does :-\
+ * An error is also indicated when a callback deletes
+ * an event we are still processing. In that case
+ * the data field is set to ENOENT.
+ */
+ if (events[i].data == EBADF ||
+ events[i].data == EINVAL ||
+ events[i].data == ENOENT)
+ continue;
+ errno = events[i].data;
+ return (-1);
+ }
+
+ if (events[i].filter == EVFILT_READ) {
+ which |= EV_READ;
+ } else if (events[i].filter == EVFILT_WRITE) {
+ which |= EV_WRITE;
+ } else if (events[i].filter == EVFILT_SIGNAL) {
+ which |= EV_SIGNAL;
+ }
+
+ if (!which)
+ continue;
+
+ if (events[i].filter == EVFILT_SIGNAL) {
+ struct event_list *head =
+ (struct event_list *)events[i].udata;
+ TAILQ_FOREACH(ev, head, ev_signal_next) {
+ event_active(ev, which, events[i].data);
+ }
+ } else {
+ ev = (struct event *)events[i].udata;
+
+ if (!(ev->ev_events & EV_PERSIST))
+ ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
+
+ event_active(ev, which, 1);
+ }
+ }
+
+ return (0);
+}
+
+
+static int
+kq_add(void *arg, struct event *ev)
+{
+ struct kqop *kqop = arg;
+ struct kevent kev;
+
+ if (ev->ev_events & EV_SIGNAL) {
+ int nsignal = EVENT_SIGNAL(ev);
+
+ assert(nsignal >= 0 && nsignal < NSIG);
+ if (TAILQ_EMPTY(&kqop->evsigevents[nsignal])) {
+ struct timespec timeout = { 0, 0 };
+
+ memset(&kev, 0, sizeof(kev));
+ kev.ident = nsignal;
+ kev.filter = EVFILT_SIGNAL;
+ kev.flags = EV_ADD;
+ kev.udata = PTR_TO_UDATA(&kqop->evsigevents[nsignal]);
+
+ /* Be ready for the signal if it is sent any
+ * time between now and the next call to
+ * kq_dispatch. */
+ if (kevent(kqop->kq, &kev, 1, NULL, 0, &timeout) == -1)
+ return (-1);
+
+ if (_evsignal_set_handler(ev->ev_base, nsignal,
+ kq_sighandler) == -1)
+ return (-1);
+ }
+
+ TAILQ_INSERT_TAIL(&kqop->evsigevents[nsignal], ev,
+ ev_signal_next);
+ ev->ev_flags |= EVLIST_X_KQINKERNEL;
+ return (0);
+ }
+
+ if (ev->ev_events & EV_READ) {
+ memset(&kev, 0, sizeof(kev));
+ kev.ident = ev->ev_fd;
+ kev.filter = EVFILT_READ;
+#ifdef NOTE_EOF
+ /* Make it behave like select() and poll() */
+ kev.fflags = NOTE_EOF;
+#endif
+ kev.flags = EV_ADD;
+ if (!(ev->ev_events & EV_PERSIST))
+ kev.flags |= EV_ONESHOT;
+ kev.udata = PTR_TO_UDATA(ev);
+
+ if (kq_insert(kqop, &kev) == -1)
+ return (-1);
+
+ ev->ev_flags |= EVLIST_X_KQINKERNEL;
+ }
+
+ if (ev->ev_events & EV_WRITE) {
+ memset(&kev, 0, sizeof(kev));
+ kev.ident = ev->ev_fd;
+ kev.filter = EVFILT_WRITE;
+ kev.flags = EV_ADD;
+ if (!(ev->ev_events & EV_PERSIST))
+ kev.flags |= EV_ONESHOT;
+ kev.udata = PTR_TO_UDATA(ev);
+
+ if (kq_insert(kqop, &kev) == -1)
+ return (-1);
+
+ ev->ev_flags |= EVLIST_X_KQINKERNEL;
+ }
+
+ return (0);
+}
+
+static int
+kq_del(void *arg, struct event *ev)
+{
+ struct kqop *kqop = arg;
+ struct kevent kev;
+
+ if (!(ev->ev_flags & EVLIST_X_KQINKERNEL))
+ return (0);
+
+ if (ev->ev_events & EV_SIGNAL) {
+ int nsignal = EVENT_SIGNAL(ev);
+ struct timespec timeout = { 0, 0 };
+
+ assert(nsignal >= 0 && nsignal < NSIG);
+ TAILQ_REMOVE(&kqop->evsigevents[nsignal], ev, ev_signal_next);
+ if (TAILQ_EMPTY(&kqop->evsigevents[nsignal])) {
+ memset(&kev, 0, sizeof(kev));
+ kev.ident = nsignal;
+ kev.filter = EVFILT_SIGNAL;
+ kev.flags = EV_DELETE;
+
+ /* Because we insert signal events
+ * immediately, we need to delete them
+ * immediately, too */
+ if (kevent(kqop->kq, &kev, 1, NULL, 0, &timeout) == -1)
+ return (-1);
+
+ if (_evsignal_restore_handler(ev->ev_base,
+ nsignal) == -1)
+ return (-1);
+ }
+
+ ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
+ return (0);
+ }
+
+ if (ev->ev_events & EV_READ) {
+ memset(&kev, 0, sizeof(kev));
+ kev.ident = ev->ev_fd;
+ kev.filter = EVFILT_READ;
+ kev.flags = EV_DELETE;
+
+ if (kq_insert(kqop, &kev) == -1)
+ return (-1);
+
+ ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
+ }
+
+ if (ev->ev_events & EV_WRITE) {
+ memset(&kev, 0, sizeof(kev));
+ kev.ident = ev->ev_fd;
+ kev.filter = EVFILT_WRITE;
+ kev.flags = EV_DELETE;
+
+ if (kq_insert(kqop, &kev) == -1)
+ return (-1);
+
+ ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
+ }
+
+ return (0);
+}
+
+static void
+kq_dealloc(struct event_base *base, void *arg)
+{
+ struct kqop *kqop = arg;
+
+ evsignal_dealloc(base);
+
+ if (kqop->changes)
+ free(kqop->changes);
+ if (kqop->events)
+ free(kqop->events);
+ if (kqop->kq >= 0 && kqop->pid == getpid())
+ close(kqop->kq);
+
+ memset(kqop, 0, sizeof(struct kqop));
+ free(kqop);
+}
diff --git a/chromium/base/third_party/libevent/libevent.gyp b/chromium/base/third_party/libevent/libevent.gyp
new file mode 100644
index 00000000000..581aa892a80
--- /dev/null
+++ b/chromium/base/third_party/libevent/libevent.gyp
@@ -0,0 +1,64 @@
+# 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.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'libevent',
+ 'product_name': 'event',
+ 'type': 'static_library',
+ 'toolsets': ['host', 'target'],
+ 'sources': [
+ 'buffer.c',
+ 'evbuffer.c',
+ 'evdns.c',
+ 'event.c',
+ 'event_tagging.c',
+ 'evrpc.c',
+ 'evutil.c',
+ 'http.c',
+ 'log.c',
+ 'poll.c',
+ 'select.c',
+ 'signal.c',
+ 'strlcpy.c',
+ ],
+ 'defines': [
+ 'HAVE_CONFIG_H',
+ ],
+ 'include_dirs': [
+ '../../..',
+ ],
+ 'conditions': [
+ # libevent has platform-specific implementation files. Since its
+ # native build uses autoconf, platform-specific config.h files are
+ # provided and live in platform-specific directories.
+ [ 'OS == "linux" or (OS == "android" and _toolset == "host")', {
+ 'sources': [ 'epoll.c' ],
+ 'include_dirs': [ 'linux' ],
+ 'link_settings': {
+ 'libraries': [
+ # We need rt for clock_gettime().
+ # TODO(port) Maybe on FreeBSD as well?
+ '-lrt',
+ ],
+ },
+ }],
+ [ 'OS == "android" and _toolset == "target"', {
+ # On android, clock_gettime() is in libc.so, so no need to link librt.
+ 'sources': [ 'epoll.c' ],
+ 'include_dirs': [ 'android' ],
+ }],
+ [ 'OS == "mac" or OS == "ios" or os_bsd==1', {
+ 'sources': [ 'kqueue.c' ],
+ 'include_dirs': [ 'mac' ]
+ }],
+ [ 'OS == "solaris"', {
+ 'sources': [ 'devpoll.c', 'evport.c' ],
+ 'include_dirs': [ 'solaris' ]
+ }],
+ ],
+ },
+ ],
+}
diff --git a/chromium/base/third_party/libevent/libevent_nacl_nonsfi.gyp b/chromium/base/third_party/libevent/libevent_nacl_nonsfi.gyp
new file mode 100644
index 00000000000..91e2557b765
--- /dev/null
+++ b/chromium/base/third_party/libevent/libevent_nacl_nonsfi.gyp
@@ -0,0 +1,47 @@
+# 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.
+
+{
+ 'includes': [
+ '../../../build/common_untrusted.gypi',
+ ],
+ 'conditions': [
+ ['disable_nacl==0 and disable_nacl_untrusted==0', {
+ 'targets': [
+ {
+ 'target_name': 'event_nacl_nonsfi',
+ 'type': 'none',
+ 'sources': [
+ 'buffer.c',
+ 'evbuffer.c',
+ 'event.c',
+ 'evutil.c',
+ 'log.c',
+ 'poll.c',
+ 'strlcpy.c',
+ 'nacl_nonsfi/config.h',
+ 'nacl_nonsfi/event-config.h',
+ 'nacl_nonsfi/random.c',
+ 'nacl_nonsfi/signal_stub.c',
+ ],
+ 'defines': [
+ 'HAVE_CONFIG_H',
+ ],
+ 'include_dirs': [
+ 'nacl_nonsfi',
+ ],
+ 'variables': {
+ 'nacl_untrusted_build': 1,
+ 'nlib_target': 'libevent_nacl_nonsfi.a',
+ 'build_glibc': 0,
+ 'build_newlib': 0,
+ 'build_irt': 0,
+ 'build_pnacl_newlib': 0,
+ 'build_nonsfi_helper': 1,
+ },
+ },
+ ],
+ }],
+ ],
+}
diff --git a/chromium/base/third_party/libevent/linux/config.h b/chromium/base/third_party/libevent/linux/config.h
new file mode 100644
index 00000000000..c01ceb536ab
--- /dev/null
+++ b/chromium/base/third_party/libevent/linux/config.h
@@ -0,0 +1,266 @@
+/* config.h. Generated from config.h.in by configure. */
+/* config.h.in. Generated from configure.in by autoheader. */
+
+/* Define if clock_gettime is available in libc */
+#define DNS_USE_CPU_CLOCK_FOR_ID 1
+
+/* Define is no secure id variant is available */
+/* #undef DNS_USE_GETTIMEOFDAY_FOR_ID */
+
+/* Define to 1 if you have the `clock_gettime' function. */
+#define HAVE_CLOCK_GETTIME 1
+
+/* Define if /dev/poll is available */
+/* #undef HAVE_DEVPOLL */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define if your system supports the epoll system calls */
+#define HAVE_EPOLL 1
+
+/* Define to 1 if you have the `epoll_ctl' function. */
+#define HAVE_EPOLL_CTL 1
+
+/* Define if your system supports event ports */
+/* #undef HAVE_EVENT_PORTS */
+
+/* Define to 1 if you have the `fcntl' function. */
+#define HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if the system has the type `fd_mask'. */
+#define HAVE_FD_MASK 1
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#define HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `getegid' function. */
+#define HAVE_GETEGID 1
+
+/* Define to 1 if you have the `geteuid' function. */
+#define HAVE_GETEUID 1
+
+/* Define to 1 if you have the `getnameinfo' function. */
+#define HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the `inet_ntop' function. */
+#define HAVE_INET_NTOP 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `issetugid' function. */
+/* #undef HAVE_ISSETUGID */
+
+/* Define to 1 if you have the `kqueue' function. */
+/* #undef HAVE_KQUEUE */
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+#define HAVE_LIBNSL 1
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+#define HAVE_LIBRESOLV 1
+
+/* Define to 1 if you have the `rt' library (-lrt). */
+#define HAVE_LIBRT 1
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+/* #undef HAVE_LIBSOCKET */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <netinet/in6.h> header file. */
+/* #undef HAVE_NETINET_IN6_H */
+
+/* Define to 1 if you have the `poll' function. */
+#define HAVE_POLL 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define HAVE_POLL_H 1
+
+/* Define to 1 if you have the `port_create' function. */
+/* #undef HAVE_PORT_CREATE */
+
+/* Define to 1 if you have the <port.h> header file. */
+/* #undef HAVE_PORT_H */
+
+/* Define to 1 if you have the `select' function. */
+#define HAVE_SELECT 1
+
+/* Define if F_SETFD is defined in <fcntl.h> */
+#define HAVE_SETFD 1
+
+/* Define to 1 if you have the `sigaction' function. */
+#define HAVE_SIGACTION 1
+
+/* Define to 1 if you have the `signal' function. */
+#define HAVE_SIGNAL 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#define HAVE_STDARG_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+/* #undef HAVE_STRLCPY */
+
+/* Define to 1 if you have the `strsep' function. */
+#define HAVE_STRSEP 1
+
+/* Define to 1 if you have the `strtok_r' function. */
+#define HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the `strtoll' function. */
+#define HAVE_STRTOLL 1
+
+/* Define to 1 if the system has the type `struct in6_addr'. */
+#define HAVE_STRUCT_IN6_ADDR 1
+
+/* Define to 1 if you have the <sys/devpoll.h> header file. */
+/* #undef HAVE_SYS_DEVPOLL_H */
+
+/* Define to 1 if you have the <sys/epoll.h> header file. */
+#define HAVE_SYS_EPOLL_H 1
+
+/* Define to 1 if you have the <sys/event.h> header file. */
+/* #undef HAVE_SYS_EVENT_H */
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/queue.h> header file. */
+#define HAVE_SYS_QUEUE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
+#define HAVE_TAILQFOREACH 1
+
+/* Define if timeradd is defined in <sys/time.h> */
+#define HAVE_TIMERADD 1
+
+/* Define if timerclear is defined in <sys/time.h> */
+#define HAVE_TIMERCLEAR 1
+
+/* Define if timercmp is defined in <sys/time.h> */
+#define HAVE_TIMERCMP 1
+
+/* Define if timerisset is defined in <sys/time.h> */
+#define HAVE_TIMERISSET 1
+
+/* Define to 1 if the system has the type `uint16_t'. */
+#define HAVE_UINT16_T 1
+
+/* Define to 1 if the system has the type `uint32_t'. */
+#define HAVE_UINT32_T 1
+
+/* Define to 1 if the system has the type `uint64_t'. */
+#define HAVE_UINT64_T 1
+
+/* Define to 1 if the system has the type `uint8_t'. */
+#define HAVE_UINT8_T 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `vasprintf' function. */
+#define HAVE_VASPRINTF 1
+
+/* Define if kqueue works correctly with pipes */
+/* #undef HAVE_WORKING_KQUEUE */
+
+/* Name of package */
+#define PACKAGE "libevent"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION ""
+
+/* The size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 8
+
+/* The size of `long long', as computed by sizeof. */
+#define SIZEOF_LONG_LONG 8
+
+/* The size of `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Version number of package */
+#define VERSION "1.4.13-stable"
+
+/* Define to appropriate substitue if compiler doesnt have __func__ */
+/* #undef __func__ */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef pid_t */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* Define to unsigned int if you dont have it */
+/* #undef socklen_t */
diff --git a/chromium/base/third_party/libevent/linux/event-config.h b/chromium/base/third_party/libevent/linux/event-config.h
new file mode 100644
index 00000000000..22032539432
--- /dev/null
+++ b/chromium/base/third_party/libevent/linux/event-config.h
@@ -0,0 +1,284 @@
+/* event-config.h
+ * Generated by autoconf; post-processed by libevent.
+ * Do not edit this file.
+ * Do not rely on macros in this file existing in later versions.
+ */
+#ifndef _EVENT_CONFIG_H_
+#define _EVENT_CONFIG_H_
+/* config.h. Generated from config.h.in by configure. */
+/* config.h.in. Generated from configure.in by autoheader. */
+
+/* Define if clock_gettime is available in libc */
+#define _EVENT_DNS_USE_CPU_CLOCK_FOR_ID 1
+
+/* Define is no secure id variant is available */
+/* #undef _EVENT_DNS_USE_GETTIMEOFDAY_FOR_ID */
+
+/* Define to 1 if you have the `clock_gettime' function. */
+#define _EVENT_HAVE_CLOCK_GETTIME 1
+
+/* Define if /dev/poll is available */
+/* #undef _EVENT_HAVE_DEVPOLL */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define _EVENT_HAVE_DLFCN_H 1
+
+/* Define if your system supports the epoll system calls */
+#define _EVENT_HAVE_EPOLL 1
+
+/* Define to 1 if you have the `epoll_ctl' function. */
+#define _EVENT_HAVE_EPOLL_CTL 1
+
+/* Define if your system supports event ports */
+/* #undef _EVENT_HAVE_EVENT_PORTS */
+
+/* Define to 1 if you have the `fcntl' function. */
+#define _EVENT_HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define _EVENT_HAVE_FCNTL_H 1
+
+/* Define to 1 if the system has the type `fd_mask'. */
+#define _EVENT_HAVE_FD_MASK 1
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#define _EVENT_HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `getegid' function. */
+#define _EVENT_HAVE_GETEGID 1
+
+/* Define to 1 if you have the `geteuid' function. */
+#define _EVENT_HAVE_GETEUID 1
+
+/* Define to 1 if you have the `getnameinfo' function. */
+#define _EVENT_HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define _EVENT_HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the `inet_ntop' function. */
+#define _EVENT_HAVE_INET_NTOP 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define _EVENT_HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `issetugid' function. */
+/* #undef _EVENT_HAVE_ISSETUGID */
+
+/* Define to 1 if you have the `kqueue' function. */
+/* #undef _EVENT_HAVE_KQUEUE */
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+#define _EVENT_HAVE_LIBNSL 1
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+#define _EVENT_HAVE_LIBRESOLV 1
+
+/* Define to 1 if you have the `rt' library (-lrt). */
+#define _EVENT_HAVE_LIBRT 1
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+/* #undef _EVENT_HAVE_LIBSOCKET */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define _EVENT_HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <netinet/in6.h> header file. */
+/* #undef _EVENT_HAVE_NETINET_IN6_H */
+
+/* Define to 1 if you have the `poll' function. */
+#define _EVENT_HAVE_POLL 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define _EVENT_HAVE_POLL_H 1
+
+/* Define to 1 if you have the `port_create' function. */
+/* #undef _EVENT_HAVE_PORT_CREATE */
+
+/* Define to 1 if you have the <port.h> header file. */
+/* #undef _EVENT_HAVE_PORT_H */
+
+/* Define to 1 if you have the `select' function. */
+#define _EVENT_HAVE_SELECT 1
+
+/* Define if F_SETFD is defined in <fcntl.h> */
+#define _EVENT_HAVE_SETFD 1
+
+/* Define to 1 if you have the `sigaction' function. */
+#define _EVENT_HAVE_SIGACTION 1
+
+/* Define to 1 if you have the `signal' function. */
+#define _EVENT_HAVE_SIGNAL 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define _EVENT_HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#define _EVENT_HAVE_STDARG_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define _EVENT_HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define _EVENT_HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define _EVENT_HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define _EVENT_HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+/* #undef _EVENT_HAVE_STRLCPY */
+
+/* Define to 1 if you have the `strsep' function. */
+#define _EVENT_HAVE_STRSEP 1
+
+/* Define to 1 if you have the `strtok_r' function. */
+#define _EVENT_HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the `strtoll' function. */
+#define _EVENT_HAVE_STRTOLL 1
+
+/* Define to 1 if the system has the type `struct in6_addr'. */
+#define _EVENT_HAVE_STRUCT_IN6_ADDR 1
+
+/* Define to 1 if you have the <sys/devpoll.h> header file. */
+/* #undef _EVENT_HAVE_SYS_DEVPOLL_H */
+
+/* Define to 1 if you have the <sys/epoll.h> header file. */
+#define _EVENT_HAVE_SYS_EPOLL_H 1
+
+/* Define to 1 if you have the <sys/event.h> header file. */
+/* #undef _EVENT_HAVE_SYS_EVENT_H */
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define _EVENT_HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define _EVENT_HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/queue.h> header file. */
+#define _EVENT_HAVE_SYS_QUEUE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define _EVENT_HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define _EVENT_HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define _EVENT_HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define _EVENT_HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define _EVENT_HAVE_SYS_TYPES_H 1
+
+/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
+#define _EVENT_HAVE_TAILQFOREACH 1
+
+/* Define if timeradd is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERADD 1
+
+/* Define if timerclear is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERCLEAR 1
+
+/* Define if timercmp is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERCMP 1
+
+/* Define if timerisset is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERISSET 1
+
+/* Define to 1 if the system has the type `uint16_t'. */
+#define _EVENT_HAVE_UINT16_T 1
+
+/* Define to 1 if the system has the type `uint32_t'. */
+#define _EVENT_HAVE_UINT32_T 1
+
+/* Define to 1 if the system has the type `uint64_t'. */
+#define _EVENT_HAVE_UINT64_T 1
+
+/* Define to 1 if the system has the type `uint8_t'. */
+#define _EVENT_HAVE_UINT8_T 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define _EVENT_HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `vasprintf' function. */
+#define _EVENT_HAVE_VASPRINTF 1
+
+/* Define if kqueue works correctly with pipes */
+/* #undef _EVENT_HAVE_WORKING_KQUEUE */
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+#define _EVENT_LT_OBJDIR ".libs/"
+
+/* Numeric representation of the version */
+#define _EVENT_NUMERIC_VERSION 0x01040f00
+
+/* Name of package */
+#define _EVENT_PACKAGE "libevent"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define _EVENT_PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define _EVENT_PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define _EVENT_PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define _EVENT_PACKAGE_TARNAME ""
+
+/* Define to the home page for this package. */
+#define _EVENT_PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define _EVENT_PACKAGE_VERSION ""
+
+/* The size of `int', as computed by sizeof. */
+#define _EVENT_SIZEOF_INT 4
+
+/* The size of `long', as computed by sizeof. */
+#define _EVENT_SIZEOF_LONG 8
+
+/* The size of `long long', as computed by sizeof. */
+#define _EVENT_SIZEOF_LONG_LONG 8
+
+/* The size of `short', as computed by sizeof. */
+#define _EVENT_SIZEOF_SHORT 2
+
+/* Define to 1 if you have the ANSI C header files. */
+#define _EVENT_STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define _EVENT_TIME_WITH_SYS_TIME 1
+
+/* Version number of package */
+#define _EVENT_VERSION "1.4.15"
+
+/* Define to appropriate substitue if compiler doesnt have __func__ */
+/* #undef _EVENT___func__ */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef _EVENT_const */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef _EVENT___cplusplus
+/* #undef _EVENT_inline */
+#endif
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef _EVENT_pid_t */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef _EVENT_size_t */
+
+/* Define to unsigned int if you dont have it */
+/* #undef _EVENT_socklen_t */
+#endif
diff --git a/chromium/base/third_party/libevent/log.c b/chromium/base/third_party/libevent/log.c
new file mode 100644
index 00000000000..48ebb2691c2
--- /dev/null
+++ b/chromium/base/third_party/libevent/log.c
@@ -0,0 +1,187 @@
+/* $OpenBSD: err.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */
+
+/*
+ * log.c
+ *
+ * Based on err.c, which was adapted from OpenBSD libc *err* *warn* code.
+ *
+ * Copyright (c) 2005 Nick Mathewson <nickm@freehaven.net>
+ *
+ * Copyright (c) 2000 Dug Song <dugsong@monkey.org>
+ *
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#endif
+#include <sys/types.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <sys/_libevent_time.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include "event.h"
+
+#include "log.h"
+#include "evutil.h"
+
+static void _warn_helper(int severity, int log_errno, const char *fmt,
+ va_list ap);
+static void event_log(int severity, const char *msg);
+
+void
+event_err(int eval, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ _warn_helper(_EVENT_LOG_ERR, errno, fmt, ap);
+ va_end(ap);
+ exit(eval);
+}
+
+void
+event_warn(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ _warn_helper(_EVENT_LOG_WARN, errno, fmt, ap);
+ va_end(ap);
+}
+
+void
+event_errx(int eval, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ _warn_helper(_EVENT_LOG_ERR, -1, fmt, ap);
+ va_end(ap);
+ exit(eval);
+}
+
+void
+event_warnx(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ _warn_helper(_EVENT_LOG_WARN, -1, fmt, ap);
+ va_end(ap);
+}
+
+void
+event_msgx(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ _warn_helper(_EVENT_LOG_MSG, -1, fmt, ap);
+ va_end(ap);
+}
+
+void
+_event_debugx(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ _warn_helper(_EVENT_LOG_DEBUG, -1, fmt, ap);
+ va_end(ap);
+}
+
+static void
+_warn_helper(int severity, int log_errno, const char *fmt, va_list ap)
+{
+ char buf[1024];
+ size_t len;
+
+ if (fmt != NULL)
+ evutil_vsnprintf(buf, sizeof(buf), fmt, ap);
+ else
+ buf[0] = '\0';
+
+ if (log_errno >= 0) {
+ len = strlen(buf);
+ if (len < sizeof(buf) - 3) {
+ evutil_snprintf(buf + len, sizeof(buf) - len, ": %s",
+ strerror(log_errno));
+ }
+ }
+
+ event_log(severity, buf);
+}
+
+static event_log_cb log_fn = NULL;
+
+void
+event_set_log_callback(event_log_cb cb)
+{
+ log_fn = cb;
+}
+
+static void
+event_log(int severity, const char *msg)
+{
+ if (log_fn)
+ log_fn(severity, msg);
+ else {
+ const char *severity_str;
+ switch (severity) {
+ case _EVENT_LOG_DEBUG:
+ severity_str = "debug";
+ break;
+ case _EVENT_LOG_MSG:
+ severity_str = "msg";
+ break;
+ case _EVENT_LOG_WARN:
+ severity_str = "warn";
+ break;
+ case _EVENT_LOG_ERR:
+ severity_str = "err";
+ break;
+ default:
+ severity_str = "???";
+ break;
+ }
+ (void)fprintf(stderr, "[%s] %s\n", severity_str, msg);
+ }
+}
diff --git a/chromium/base/third_party/libevent/log.h b/chromium/base/third_party/libevent/log.h
new file mode 100644
index 00000000000..7bc6632b8dd
--- /dev/null
+++ b/chromium/base/third_party/libevent/log.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2000-2004 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _LOG_H_
+#define _LOG_H_
+
+#ifdef __GNUC__
+#define EV_CHECK_FMT(a,b) __attribute__((format(printf, a, b)))
+#else
+#define EV_CHECK_FMT(a,b)
+#endif
+
+void event_err(int eval, const char *fmt, ...) EV_CHECK_FMT(2,3);
+void event_warn(const char *fmt, ...) EV_CHECK_FMT(1,2);
+void event_errx(int eval, const char *fmt, ...) EV_CHECK_FMT(2,3);
+void event_warnx(const char *fmt, ...) EV_CHECK_FMT(1,2);
+void event_msgx(const char *fmt, ...) EV_CHECK_FMT(1,2);
+void _event_debugx(const char *fmt, ...) EV_CHECK_FMT(1,2);
+
+#ifdef USE_DEBUG
+#define event_debug(x) _event_debugx x
+#else
+#define event_debug(x) do {;} while (0)
+#endif
+
+#undef EV_CHECK_FMT
+
+#endif
diff --git a/chromium/base/third_party/libevent/m4/.dummy b/chromium/base/third_party/libevent/m4/.dummy
new file mode 100644
index 00000000000..a0a72d601e1
--- /dev/null
+++ b/chromium/base/third_party/libevent/m4/.dummy
@@ -0,0 +1 @@
+(This dummy file exists so that git will create the m4 directory)
diff --git a/chromium/base/third_party/libevent/mac/config.h b/chromium/base/third_party/libevent/mac/config.h
new file mode 100644
index 00000000000..f73f0c63292
--- /dev/null
+++ b/chromium/base/third_party/libevent/mac/config.h
@@ -0,0 +1,266 @@
+/* config.h. Generated from config.h.in by configure. */
+/* config.h.in. Generated from configure.in by autoheader. */
+
+/* Define if clock_gettime is available in libc */
+/* #undef DNS_USE_CPU_CLOCK_FOR_ID */
+
+/* Define is no secure id variant is available */
+#define DNS_USE_GETTIMEOFDAY_FOR_ID 1
+
+/* Define to 1 if you have the `clock_gettime' function. */
+/* #undef HAVE_CLOCK_GETTIME */
+
+/* Define if /dev/poll is available */
+/* #undef HAVE_DEVPOLL */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define if your system supports the epoll system calls */
+/* #undef HAVE_EPOLL */
+
+/* Define to 1 if you have the `epoll_ctl' function. */
+/* #undef HAVE_EPOLL_CTL */
+
+/* Define if your system supports event ports */
+/* #undef HAVE_EVENT_PORTS */
+
+/* Define to 1 if you have the `fcntl' function. */
+#define HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if the system has the type `fd_mask'. */
+#define HAVE_FD_MASK 1
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#define HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `getegid' function. */
+#define HAVE_GETEGID 1
+
+/* Define to 1 if you have the `geteuid' function. */
+#define HAVE_GETEUID 1
+
+/* Define to 1 if you have the `getnameinfo' function. */
+#define HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the `inet_ntop' function. */
+#define HAVE_INET_NTOP 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `issetugid' function. */
+#define HAVE_ISSETUGID 1
+
+/* Define to 1 if you have the `kqueue' function. */
+#define HAVE_KQUEUE 1
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+/* #undef HAVE_LIBNSL */
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+#define HAVE_LIBRESOLV 1
+
+/* Define to 1 if you have the `rt' library (-lrt). */
+/* #undef HAVE_LIBRT */
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+/* #undef HAVE_LIBSOCKET */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <netinet/in6.h> header file. */
+/* #undef HAVE_NETINET_IN6_H */
+
+/* Define to 1 if you have the `poll' function. */
+#define HAVE_POLL 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define HAVE_POLL_H 1
+
+/* Define to 1 if you have the `port_create' function. */
+/* #undef HAVE_PORT_CREATE */
+
+/* Define to 1 if you have the <port.h> header file. */
+/* #undef HAVE_PORT_H */
+
+/* Define to 1 if you have the `select' function. */
+#define HAVE_SELECT 1
+
+/* Define if F_SETFD is defined in <fcntl.h> */
+#define HAVE_SETFD 1
+
+/* Define to 1 if you have the `sigaction' function. */
+#define HAVE_SIGACTION 1
+
+/* Define to 1 if you have the `signal' function. */
+#define HAVE_SIGNAL 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#define HAVE_STDARG_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+#define HAVE_STRLCPY 1
+
+/* Define to 1 if you have the `strsep' function. */
+#define HAVE_STRSEP 1
+
+/* Define to 1 if you have the `strtok_r' function. */
+#define HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the `strtoll' function. */
+#define HAVE_STRTOLL 1
+
+/* Define to 1 if the system has the type `struct in6_addr'. */
+#define HAVE_STRUCT_IN6_ADDR 1
+
+/* Define to 1 if you have the <sys/devpoll.h> header file. */
+/* #undef HAVE_SYS_DEVPOLL_H */
+
+/* Define to 1 if you have the <sys/epoll.h> header file. */
+/* #undef HAVE_SYS_EPOLL_H */
+
+/* Define to 1 if you have the <sys/event.h> header file. */
+#define HAVE_SYS_EVENT_H 1
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/queue.h> header file. */
+#define HAVE_SYS_QUEUE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
+#define HAVE_TAILQFOREACH 1
+
+/* Define if timeradd is defined in <sys/time.h> */
+#define HAVE_TIMERADD 1
+
+/* Define if timerclear is defined in <sys/time.h> */
+#define HAVE_TIMERCLEAR 1
+
+/* Define if timercmp is defined in <sys/time.h> */
+#define HAVE_TIMERCMP 1
+
+/* Define if timerisset is defined in <sys/time.h> */
+#define HAVE_TIMERISSET 1
+
+/* Define to 1 if the system has the type `uint16_t'. */
+#define HAVE_UINT16_T 1
+
+/* Define to 1 if the system has the type `uint32_t'. */
+#define HAVE_UINT32_T 1
+
+/* Define to 1 if the system has the type `uint64_t'. */
+#define HAVE_UINT64_T 1
+
+/* Define to 1 if the system has the type `uint8_t'. */
+#define HAVE_UINT8_T 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `vasprintf' function. */
+#define HAVE_VASPRINTF 1
+
+/* Define if kqueue works correctly with pipes */
+#define HAVE_WORKING_KQUEUE 1
+
+/* Name of package */
+#define PACKAGE "libevent"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION ""
+
+/* The size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 4
+
+/* The size of `long long', as computed by sizeof. */
+#define SIZEOF_LONG_LONG 8
+
+/* The size of `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Version number of package */
+#define VERSION "1.4.13-stable"
+
+/* Define to appropriate substitue if compiler doesnt have __func__ */
+/* #undef __func__ */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef pid_t */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* Define to unsigned int if you dont have it */
+/* #undef socklen_t */
diff --git a/chromium/base/third_party/libevent/mac/event-config.h b/chromium/base/third_party/libevent/mac/event-config.h
new file mode 100644
index 00000000000..92e212d0b6a
--- /dev/null
+++ b/chromium/base/third_party/libevent/mac/event-config.h
@@ -0,0 +1,284 @@
+/* event-config.h
+ * Generated by autoconf; post-processed by libevent.
+ * Do not edit this file.
+ * Do not rely on macros in this file existing in later versions.
+ */
+#ifndef _EVENT_CONFIG_H_
+#define _EVENT_CONFIG_H_
+/* config.h. Generated from config.h.in by configure. */
+/* config.h.in. Generated from configure.in by autoheader. */
+
+/* Define if clock_gettime is available in libc */
+/* #undef _EVENT_DNS_USE_CPU_CLOCK_FOR_ID */
+
+/* Define is no secure id variant is available */
+#define _EVENT_DNS_USE_GETTIMEOFDAY_FOR_ID 1
+
+/* Define to 1 if you have the `clock_gettime' function. */
+/* #undef _EVENT_HAVE_CLOCK_GETTIME */
+
+/* Define if /dev/poll is available */
+/* #undef _EVENT_HAVE_DEVPOLL */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define _EVENT_HAVE_DLFCN_H 1
+
+/* Define if your system supports the epoll system calls */
+/* #undef _EVENT_HAVE_EPOLL */
+
+/* Define to 1 if you have the `epoll_ctl' function. */
+/* #undef _EVENT_HAVE_EPOLL_CTL */
+
+/* Define if your system supports event ports */
+/* #undef _EVENT_HAVE_EVENT_PORTS */
+
+/* Define to 1 if you have the `fcntl' function. */
+#define _EVENT_HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define _EVENT_HAVE_FCNTL_H 1
+
+/* Define to 1 if the system has the type `fd_mask'. */
+#define _EVENT_HAVE_FD_MASK 1
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#define _EVENT_HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `getegid' function. */
+#define _EVENT_HAVE_GETEGID 1
+
+/* Define to 1 if you have the `geteuid' function. */
+#define _EVENT_HAVE_GETEUID 1
+
+/* Define to 1 if you have the `getnameinfo' function. */
+#define _EVENT_HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define _EVENT_HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the `inet_ntop' function. */
+#define _EVENT_HAVE_INET_NTOP 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define _EVENT_HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `issetugid' function. */
+#define _EVENT_HAVE_ISSETUGID 1
+
+/* Define to 1 if you have the `kqueue' function. */
+#define _EVENT_HAVE_KQUEUE 1
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+/* #undef _EVENT_HAVE_LIBNSL */
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+#define _EVENT_HAVE_LIBRESOLV 1
+
+/* Define to 1 if you have the `rt' library (-lrt). */
+/* #undef _EVENT_HAVE_LIBRT */
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+/* #undef _EVENT_HAVE_LIBSOCKET */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define _EVENT_HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <netinet/in6.h> header file. */
+/* #undef _EVENT_HAVE_NETINET_IN6_H */
+
+/* Define to 1 if you have the `poll' function. */
+#define _EVENT_HAVE_POLL 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define _EVENT_HAVE_POLL_H 1
+
+/* Define to 1 if you have the `port_create' function. */
+/* #undef _EVENT_HAVE_PORT_CREATE */
+
+/* Define to 1 if you have the <port.h> header file. */
+/* #undef _EVENT_HAVE_PORT_H */
+
+/* Define to 1 if you have the `select' function. */
+#define _EVENT_HAVE_SELECT 1
+
+/* Define if F_SETFD is defined in <fcntl.h> */
+#define _EVENT_HAVE_SETFD 1
+
+/* Define to 1 if you have the `sigaction' function. */
+#define _EVENT_HAVE_SIGACTION 1
+
+/* Define to 1 if you have the `signal' function. */
+#define _EVENT_HAVE_SIGNAL 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define _EVENT_HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#define _EVENT_HAVE_STDARG_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define _EVENT_HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define _EVENT_HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define _EVENT_HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define _EVENT_HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+#define _EVENT_HAVE_STRLCPY 1
+
+/* Define to 1 if you have the `strsep' function. */
+#define _EVENT_HAVE_STRSEP 1
+
+/* Define to 1 if you have the `strtok_r' function. */
+#define _EVENT_HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the `strtoll' function. */
+#define _EVENT_HAVE_STRTOLL 1
+
+/* Define to 1 if the system has the type `struct in6_addr'. */
+#define _EVENT_HAVE_STRUCT_IN6_ADDR 1
+
+/* Define to 1 if you have the <sys/devpoll.h> header file. */
+/* #undef _EVENT_HAVE_SYS_DEVPOLL_H */
+
+/* Define to 1 if you have the <sys/epoll.h> header file. */
+/* #undef _EVENT_HAVE_SYS_EPOLL_H */
+
+/* Define to 1 if you have the <sys/event.h> header file. */
+#define _EVENT_HAVE_SYS_EVENT_H 1
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define _EVENT_HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define _EVENT_HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/queue.h> header file. */
+#define _EVENT_HAVE_SYS_QUEUE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define _EVENT_HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define _EVENT_HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define _EVENT_HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define _EVENT_HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define _EVENT_HAVE_SYS_TYPES_H 1
+
+/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
+#define _EVENT_HAVE_TAILQFOREACH 1
+
+/* Define if timeradd is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERADD 1
+
+/* Define if timerclear is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERCLEAR 1
+
+/* Define if timercmp is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERCMP 1
+
+/* Define if timerisset is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERISSET 1
+
+/* Define to 1 if the system has the type `uint16_t'. */
+#define _EVENT_HAVE_UINT16_T 1
+
+/* Define to 1 if the system has the type `uint32_t'. */
+#define _EVENT_HAVE_UINT32_T 1
+
+/* Define to 1 if the system has the type `uint64_t'. */
+#define _EVENT_HAVE_UINT64_T 1
+
+/* Define to 1 if the system has the type `uint8_t'. */
+#define _EVENT_HAVE_UINT8_T 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define _EVENT_HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `vasprintf' function. */
+#define _EVENT_HAVE_VASPRINTF 1
+
+/* Define if kqueue works correctly with pipes */
+#define _EVENT_HAVE_WORKING_KQUEUE 1
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+#define _EVENT_LT_OBJDIR ".libs/"
+
+/* Numeric representation of the version */
+#define _EVENT_NUMERIC_VERSION 0x01040f00
+
+/* Name of package */
+#define _EVENT_PACKAGE "libevent"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define _EVENT_PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define _EVENT_PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define _EVENT_PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define _EVENT_PACKAGE_TARNAME ""
+
+/* Define to the home page for this package. */
+#define _EVENT_PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define _EVENT_PACKAGE_VERSION ""
+
+/* The size of `int', as computed by sizeof. */
+#define _EVENT_SIZEOF_INT 4
+
+/* The size of `long', as computed by sizeof. */
+#define _EVENT_SIZEOF_LONG 4
+
+/* The size of `long long', as computed by sizeof. */
+#define _EVENT_SIZEOF_LONG_LONG 8
+
+/* The size of `short', as computed by sizeof. */
+#define _EVENT_SIZEOF_SHORT 2
+
+/* Define to 1 if you have the ANSI C header files. */
+#define _EVENT_STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define _EVENT_TIME_WITH_SYS_TIME 1
+
+/* Version number of package */
+#define _EVENT_VERSION "1.4.15"
+
+/* Define to appropriate substitue if compiler doesnt have __func__ */
+/* #undef _EVENT___func__ */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef _EVENT_const */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef _EVENT___cplusplus
+/* #undef _EVENT_inline */
+#endif
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef _EVENT_pid_t */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef _EVENT_size_t */
+
+/* Define to unsigned int if you dont have it */
+/* #undef _EVENT_socklen_t */
+#endif
diff --git a/chromium/base/third_party/libevent/min_heap.h b/chromium/base/third_party/libevent/min_heap.h
new file mode 100644
index 00000000000..14d8e370c2b
--- /dev/null
+++ b/chromium/base/third_party/libevent/min_heap.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2006 Maxim Yegorushkin <maxim.yegorushkin@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _MIN_HEAP_H_
+#define _MIN_HEAP_H_
+
+#include "event.h"
+#include "evutil.h"
+
+typedef struct min_heap
+{
+ struct event** p;
+ unsigned n, a;
+} min_heap_t;
+
+static inline void min_heap_ctor(min_heap_t* s);
+static inline void min_heap_dtor(min_heap_t* s);
+static inline void min_heap_elem_init(struct event* e);
+static inline int min_heap_elem_greater(struct event *a, struct event *b);
+static inline int min_heap_empty(min_heap_t* s);
+static inline unsigned min_heap_size(min_heap_t* s);
+static inline struct event* min_heap_top(min_heap_t* s);
+static inline int min_heap_reserve(min_heap_t* s, unsigned n);
+static inline int min_heap_push(min_heap_t* s, struct event* e);
+static inline struct event* min_heap_pop(min_heap_t* s);
+static inline int min_heap_erase(min_heap_t* s, struct event* e);
+static inline void min_heap_shift_up_(min_heap_t* s, unsigned hole_index, struct event* e);
+static inline void min_heap_shift_down_(min_heap_t* s, unsigned hole_index, struct event* e);
+
+int min_heap_elem_greater(struct event *a, struct event *b)
+{
+ return evutil_timercmp(&a->ev_timeout, &b->ev_timeout, >);
+}
+
+void min_heap_ctor(min_heap_t* s) { s->p = 0; s->n = 0; s->a = 0; }
+void min_heap_dtor(min_heap_t* s) { if(s->p) free(s->p); }
+void min_heap_elem_init(struct event* e) { e->min_heap_idx = -1; }
+int min_heap_empty(min_heap_t* s) { return 0u == s->n; }
+unsigned min_heap_size(min_heap_t* s) { return s->n; }
+struct event* min_heap_top(min_heap_t* s) { return s->n ? *s->p : 0; }
+
+int min_heap_push(min_heap_t* s, struct event* e)
+{
+ if(min_heap_reserve(s, s->n + 1))
+ return -1;
+ min_heap_shift_up_(s, s->n++, e);
+ return 0;
+}
+
+struct event* min_heap_pop(min_heap_t* s)
+{
+ if(s->n)
+ {
+ struct event* e = *s->p;
+ min_heap_shift_down_(s, 0u, s->p[--s->n]);
+ e->min_heap_idx = -1;
+ return e;
+ }
+ return 0;
+}
+
+int min_heap_erase(min_heap_t* s, struct event* e)
+{
+ if(((unsigned int)-1) != e->min_heap_idx)
+ {
+ struct event *last = s->p[--s->n];
+ unsigned parent = (e->min_heap_idx - 1) / 2;
+ /* we replace e with the last element in the heap. We might need to
+ shift it upward if it is less than its parent, or downward if it is
+ greater than one or both its children. Since the children are known
+ to be less than the parent, it can't need to shift both up and
+ down. */
+ if (e->min_heap_idx > 0 && min_heap_elem_greater(s->p[parent], last))
+ min_heap_shift_up_(s, e->min_heap_idx, last);
+ else
+ min_heap_shift_down_(s, e->min_heap_idx, last);
+ e->min_heap_idx = -1;
+ return 0;
+ }
+ return -1;
+}
+
+int min_heap_reserve(min_heap_t* s, unsigned n)
+{
+ if(s->a < n)
+ {
+ struct event** p;
+ unsigned a = s->a ? s->a * 2 : 8;
+ if(a < n)
+ a = n;
+ if(!(p = (struct event**)realloc(s->p, a * sizeof *p)))
+ return -1;
+ s->p = p;
+ s->a = a;
+ }
+ return 0;
+}
+
+void min_heap_shift_up_(min_heap_t* s, unsigned hole_index, struct event* e)
+{
+ unsigned parent = (hole_index - 1) / 2;
+ while(hole_index && min_heap_elem_greater(s->p[parent], e))
+ {
+ (s->p[hole_index] = s->p[parent])->min_heap_idx = hole_index;
+ hole_index = parent;
+ parent = (hole_index - 1) / 2;
+ }
+ (s->p[hole_index] = e)->min_heap_idx = hole_index;
+}
+
+void min_heap_shift_down_(min_heap_t* s, unsigned hole_index, struct event* e)
+{
+ unsigned min_child = 2 * (hole_index + 1);
+ while(min_child <= s->n)
+ {
+ min_child -= min_child == s->n || min_heap_elem_greater(s->p[min_child], s->p[min_child - 1]);
+ if(!(min_heap_elem_greater(e, s->p[min_child])))
+ break;
+ (s->p[hole_index] = s->p[min_child])->min_heap_idx = hole_index;
+ hole_index = min_child;
+ min_child = 2 * (hole_index + 1);
+ }
+ min_heap_shift_up_(s, hole_index, e);
+}
+
+#endif /* _MIN_HEAP_H_ */
diff --git a/chromium/base/third_party/libevent/nacl_nonsfi/config.h b/chromium/base/third_party/libevent/nacl_nonsfi/config.h
new file mode 100644
index 00000000000..60c9dfe774c
--- /dev/null
+++ b/chromium/base/third_party/libevent/nacl_nonsfi/config.h
@@ -0,0 +1,273 @@
+/* Copied from Linux version and changed the features according the PNaCl
+ * toolchain for the Non-SFI binary build, which is close to one under the
+ * linux/ directory. The built binary will be running under Linux directly,
+ * actually.
+ */
+
+/* Define if clock_gettime is available in libc */
+#define DNS_USE_CPU_CLOCK_FOR_ID 1
+
+/* Define is no secure id variant is available */
+/* #undef DNS_USE_GETTIMEOFDAY_FOR_ID */
+
+/* Define to 1 if you have the `clock_gettime' function. */
+#define HAVE_CLOCK_GETTIME 1
+
+/* Define if /dev/poll is available */
+/* #undef HAVE_DEVPOLL */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+/* #undef HAVE_DLFCN_H */
+
+/* Define if your system supports the epoll system calls */
+/* #undef HAVE_EPOLL */
+
+/* Define to 1 if you have the `epoll_ctl' function. */
+/* #undef HAVE_EPOLL_CTL */
+
+/* Define if your system supports event ports */
+/* #undef HAVE_EVENT_PORTS */
+
+/* Define to 1 if you have the `fcntl' function. */
+#define HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if the system has the type `fd_mask'. */
+#define HAVE_FD_MASK 1
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#define HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `getegid' function. */
+#define HAVE_GETEGID 1
+
+/* Define to 1 if you have the `geteuid' function. */
+#define HAVE_GETEUID 1
+
+/* Define to 1 if you have the `getnameinfo' function. */
+#define HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the `inet_ntop' function. */
+#define HAVE_INET_NTOP 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `issetugid' function. */
+/* #undef HAVE_ISSETUGID */
+
+/* Define to 1 if you have the `kqueue' function. */
+/* #undef HAVE_KQUEUE */
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+#define HAVE_LIBNSL 1
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+#define HAVE_LIBRESOLV 1
+
+/* Define to 1 if you have the `rt' library (-lrt). */
+#define HAVE_LIBRT 1
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+/* #undef HAVE_LIBSOCKET */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <netinet/in6.h> header file. */
+/* #undef HAVE_NETINET_IN6_H */
+
+/* Define to 1 if you have the `poll' function. */
+#define HAVE_POLL 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define HAVE_POLL_H 1
+
+/* Define to 1 if you have the `port_create' function. */
+/* #undef HAVE_PORT_CREATE */
+
+/* Define to 1 if you have the <port.h> header file. */
+/* #undef HAVE_PORT_H */
+
+/* Define to 1 if you have the `select' function. */
+/* #undef HAVE_SELECT */
+
+/* Define if F_SETFD is defined in <fcntl.h> */
+#define HAVE_SETFD 1
+
+/* Note: The PNaCl toolchain prodives linux ABI's sigaction, named
+ * linux_sigaction() in native_client/src/nonsfi/linux/linux_sys_private.c,
+ * but newlib ABI sigaction() is not provided.
+ */
+/* Define to 1 if you have the `sigaction' function. */
+/* #undef HAVE_SIGACTION */
+
+/* Define to 1 if you have the `signal' function. */
+/* #undef HAVE_SIGNAL */
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#define HAVE_STDARG_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+/* #undef HAVE_STRLCPY */
+
+/* Define to 1 if you have the `strsep' function. */
+#define HAVE_STRSEP 1
+
+/* Define to 1 if you have the `strtok_r' function. */
+#define HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the `strtoll' function. */
+#define HAVE_STRTOLL 1
+
+/* Define to 1 if the system has the type `struct in6_addr'. */
+#define HAVE_STRUCT_IN6_ADDR 1
+
+/* Define to 1 if you have the <sys/devpoll.h> header file. */
+/* #undef HAVE_SYS_DEVPOLL_H */
+
+/* Define to 1 if you have the <sys/epoll.h> header file. */
+#define HAVE_SYS_EPOLL_H 1
+
+/* Define to 1 if you have the <sys/event.h> header file. */
+/* #undef HAVE_SYS_EVENT_H */
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+/* #undef HAVE_SYS_IOCTL_H */
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/queue.h> header file. */
+#define HAVE_SYS_QUEUE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+/* #undef HAVE_SYS_SELECT_H */
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
+#define HAVE_TAILQFOREACH 1
+
+/* Define if timeradd is defined in <sys/time.h> */
+/* #undef HAVE_TIMERADD */
+
+/* Define if timerclear is defined in <sys/time.h> */
+/* #undef HAVE_TIMERCLEAR */
+
+/* Define if timercmp is defined in <sys/time.h> */
+/* #undef HAVE_TIMERCMP */
+
+/* Define if timerisset is defined in <sys/time.h> */
+/* #undef HAVE_TIMERISSET */
+
+/* Define to 1 if the system has the type `uint16_t'. */
+#define HAVE_UINT16_T 1
+
+/* Define to 1 if the system has the type `uint32_t'. */
+#define HAVE_UINT32_T 1
+
+/* Define to 1 if the system has the type `uint64_t'. */
+#define HAVE_UINT64_T 1
+
+/* Define to 1 if the system has the type `uint8_t'. */
+#define HAVE_UINT8_T 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `vasprintf' function. */
+/* #undef HAVE_VASPRINTF */
+
+/* Define if kqueue works correctly with pipes */
+/* #undef HAVE_WORKING_KQUEUE */
+
+/* Name of package */
+#define PACKAGE "libevent_nacl"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION ""
+
+/* The size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 8
+
+/* The size of `long long', as computed by sizeof. */
+#define SIZEOF_LONG_LONG 8
+
+/* The size of `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Version number of package */
+#define VERSION "1.4.13-stable"
+
+/* Define to appropriate substitue if compiler doesnt have __func__ */
+/* #undef __func__ */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef pid_t */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* Define to unsigned int if you dont have it */
+/* #undef socklen_t */
diff --git a/chromium/base/third_party/libevent/nacl_nonsfi/event-config.h b/chromium/base/third_party/libevent/nacl_nonsfi/event-config.h
new file mode 100644
index 00000000000..fe28043f302
--- /dev/null
+++ b/chromium/base/third_party/libevent/nacl_nonsfi/event-config.h
@@ -0,0 +1,290 @@
+/* Copied from Linux version and changed the features according the PNaCl
+ * toolchain for the Non-SFI binary build, which is close to one under the
+ * linux/ directory. The built binary will be running under Linux directly,
+ * actually.
+ */
+
+#ifndef _EVENT_CONFIG_H_
+#define _EVENT_CONFIG_H_
+
+/* Define if clock_gettime is available in libc */
+#define _EVENT_DNS_USE_CPU_CLOCK_FOR_ID 1
+
+/* Define is no secure id variant is available */
+/* #undef _EVENT_DNS_USE_GETTIMEOFDAY_FOR_ID */
+
+/* Define to 1 if you have the `clock_gettime' function. */
+#define _EVENT_HAVE_CLOCK_GETTIME 1
+
+/* Define if /dev/poll is available */
+/* #undef _EVENT_HAVE_DEVPOLL */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define _EVENT_HAVE_DLFCN_H 1
+
+/* Define if your system supports the epoll system calls */
+/* #undef _EVENT_HAVE_EPOLL */
+
+/* Define to 1 if you have the `epoll_ctl' function. */
+/* #undef _EVENT_HAVE_EPOLL_CTL */
+
+/* Define if your system supports event ports */
+/* #undef _EVENT_HAVE_EVENT_PORTS */
+
+/* Define to 1 if you have the `fcntl' function. */
+#define _EVENT_HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define _EVENT_HAVE_FCNTL_H 1
+
+/* Define to 1 if the system has the type `fd_mask'. */
+#define _EVENT_HAVE_FD_MASK 1
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#define _EVENT_HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `getegid' function. */
+#define _EVENT_HAVE_GETEGID 1
+
+/* Define to 1 if you have the `geteuid' function. */
+#define _EVENT_HAVE_GETEUID 1
+
+/* Define to 1 if you have the `getnameinfo' function. */
+#define _EVENT_HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define _EVENT_HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the `inet_ntop' function. */
+#define _EVENT_HAVE_INET_NTOP 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define _EVENT_HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `issetugid' function. */
+/* #undef _EVENT_HAVE_ISSETUGID */
+
+/* Define to 1 if you have the `kqueue' function. */
+/* #undef _EVENT_HAVE_KQUEUE */
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+#define _EVENT_HAVE_LIBNSL 1
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+#define _EVENT_HAVE_LIBRESOLV 1
+
+/* Define to 1 if you have the `rt' library (-lrt). */
+#define _EVENT_HAVE_LIBRT 1
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+/* #undef _EVENT_HAVE_LIBSOCKET */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define _EVENT_HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <netinet/in6.h> header file. */
+/* #undef _EVENT_HAVE_NETINET_IN6_H */
+
+/* Define to 1 if you have the `poll' function. */
+#define _EVENT_HAVE_POLL 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define _EVENT_HAVE_POLL_H 1
+
+/* Define to 1 if you have the `port_create' function. */
+/* #undef _EVENT_HAVE_PORT_CREATE */
+
+/* Define to 1 if you have the <port.h> header file. */
+/* #undef _EVENT_HAVE_PORT_H */
+
+/* Define to 1 if you have the `select' function. */
+/* #undef _EVENT_HAVE_SELECT */
+
+/* Define if F_SETFD is defined in <fcntl.h> */
+#define _EVENT_HAVE_SETFD 1
+
+/* Define to 1 if you have the `sigaction' function. */
+/* #undef _EVENT_HAVE_SIGACTION */
+
+/* Define to 1 if you have the `signal' function. */
+#define _EVENT_HAVE_SIGNAL 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define _EVENT_HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#define _EVENT_HAVE_STDARG_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define _EVENT_HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define _EVENT_HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define _EVENT_HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define _EVENT_HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+/* #undef _EVENT_HAVE_STRLCPY */
+
+/* Define to 1 if you have the `strsep' function. */
+#define _EVENT_HAVE_STRSEP 1
+
+/* Define to 1 if you have the `strtok_r' function. */
+#define _EVENT_HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the `strtoll' function. */
+#define _EVENT_HAVE_STRTOLL 1
+
+/* Define to 1 if the system has the type `struct in6_addr'. */
+#define _EVENT_HAVE_STRUCT_IN6_ADDR 1
+
+/* Define to 1 if you have the <sys/devpoll.h> header file. */
+/* #undef _EVENT_HAVE_SYS_DEVPOLL_H */
+
+/* Define to 1 if you have the <sys/epoll.h> header file. */
+/* #undef _EVENT_HAVE_SYS_EPOLL_H */
+
+/* Define to 1 if you have the <sys/event.h> header file. */
+/* #undef _EVENT_HAVE_SYS_EVENT_H */
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+/* #undef _EVENT_HAVE_SYS_IOCTL_H */
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define _EVENT_HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/queue.h> header file. */
+#define _EVENT_HAVE_SYS_QUEUE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define _EVENT_HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define _EVENT_HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define _EVENT_HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define _EVENT_HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define _EVENT_HAVE_SYS_TYPES_H 1
+
+/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
+#define _EVENT_HAVE_TAILQFOREACH 1
+
+/* Define if timeradd is defined in <sys/time.h> */
+/* #undef _EVENT_HAVE_TIMERADD */
+
+/* Define if timerclear is defined in <sys/time.h> */
+/* #undef _EVENT_HAVE_TIMERCLEAR */
+
+/* Define if timercmp is defined in <sys/time.h> */
+/* #undef _EVENT_HAVE_TIMERCMP */
+
+/* Define if timerisset is defined in <sys/time.h> */
+/* #undef _EVENT_HAVE_TIMERISSET */
+
+/* Define to 1 if the system has the type `uint16_t'. */
+#define _EVENT_HAVE_UINT16_T 1
+
+/* Define to 1 if the system has the type `uint32_t'. */
+#define _EVENT_HAVE_UINT32_T 1
+
+/* Define to 1 if the system has the type `uint64_t'. */
+#define _EVENT_HAVE_UINT64_T 1
+
+/* Define to 1 if the system has the type `uint8_t'. */
+#define _EVENT_HAVE_UINT8_T 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define _EVENT_HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `vasprintf' function. */
+#define _EVENT_HAVE_VASPRINTF 1
+
+/* Define if kqueue works correctly with pipes */
+/* #undef _EVENT_HAVE_WORKING_KQUEUE */
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+#define _EVENT_LT_OBJDIR ".libs/"
+
+/* Numeric representation of the version */
+#define _EVENT_NUMERIC_VERSION 0x01040f00
+
+/* Name of package */
+#define _EVENT_PACKAGE "libevent_nacl"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define _EVENT_PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define _EVENT_PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define _EVENT_PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define _EVENT_PACKAGE_TARNAME ""
+
+/* Define to the home page for this package. */
+#define _EVENT_PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define _EVENT_PACKAGE_VERSION ""
+
+/* The size of `int', as computed by sizeof. */
+#define _EVENT_SIZEOF_INT 4
+
+/* The size of `long', as computed by sizeof. */
+#define _EVENT_SIZEOF_LONG 8
+
+/* The size of `long long', as computed by sizeof. */
+#define _EVENT_SIZEOF_LONG_LONG 8
+
+/* The size of `short', as computed by sizeof. */
+#define _EVENT_SIZEOF_SHORT 2
+
+/* Define to 1 if you have the ANSI C header files. */
+#define _EVENT_STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define _EVENT_TIME_WITH_SYS_TIME 1
+
+/* Version number of package */
+#define _EVENT_VERSION "1.4.15"
+
+/* Define to appropriate substitue if compiler doesnt have __func__ */
+/* #undef _EVENT___func__ */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef _EVENT_const */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef _EVENT___cplusplus
+/* #undef _EVENT_inline */
+#endif
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef _EVENT_pid_t */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef _EVENT_size_t */
+
+/* Define to unsigned int if you dont have it */
+/* #undef _EVENT_socklen_t */
+
+/* Work around for __native_client_nonsfi__ build. random() is not provided
+ * by the newlib-based PNaCl toolchain, so here we declare it. Please see also
+ * nacl_nonsfi/random.c for more details.
+ */
+long int random();
+
+#endif
diff --git a/chromium/base/third_party/libevent/nacl_nonsfi/random.c b/chromium/base/third_party/libevent/nacl_nonsfi/random.c
new file mode 100644
index 00000000000..3577dd508ac
--- /dev/null
+++ b/chromium/base/third_party/libevent/nacl_nonsfi/random.c
@@ -0,0 +1,13 @@
+/* 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 <stdlib.h>
+
+/* The newlib-based PNaCl toolchain does not provide random(). So, here we
+ * define it. It just redirects to the rand(), which is provided by the
+ * toolchain. */
+long int random() {
+ return rand();
+}
diff --git a/chromium/base/third_party/libevent/nacl_nonsfi/signal_stub.c b/chromium/base/third_party/libevent/nacl_nonsfi/signal_stub.c
new file mode 100644
index 00000000000..0399e8c1453
--- /dev/null
+++ b/chromium/base/third_party/libevent/nacl_nonsfi/signal_stub.c
@@ -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.
+ */
+
+/*
+ * In nacl_helper_nonsfi, socketpair() is unavailable. In libevent, it is used
+ * to notify of a signal handler invocation, which is unused in
+ * nacl_helper_nonsfi. Unfortunately, there is no macro to disable the feature,
+ * so we stub out the signal module entirely.
+ */
+
+
+#include <signal.h>
+#include <stdlib.h>
+#include <sys/queue.h>
+
+/* config.h must be included before any other libevent header is included. */
+#include "config.h"
+
+#include "base/third_party/libevent/event-internal.h"
+#include "base/third_party/libevent/event.h"
+#include "base/third_party/libevent/evsignal.h"
+
+
+struct event_base *evsignal_base = 0;
+
+int evsignal_init(struct event_base *base) {
+ /* Do nothing, and return success. */
+ return 0;
+}
+
+void evsignal_process(struct event_base *base) {
+}
+
+int evsignal_add(struct event *event) {
+ /* Do nothing, and return an error. */
+ return -1;
+}
+
+int evsignal_del(struct event *event) {
+ /* Do nothing, and return an error. */
+ return -1;
+}
+
+void evsignal_dealloc(struct event_base *base) {
+}
diff --git a/chromium/base/third_party/libevent/poll.c b/chromium/base/third_party/libevent/poll.c
new file mode 100644
index 00000000000..2aa245b3717
--- /dev/null
+++ b/chromium/base/third_party/libevent/poll.c
@@ -0,0 +1,379 @@
+/* $OpenBSD: poll.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */
+
+/*
+ * Copyright 2000-2003 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <sys/_libevent_time.h>
+#endif
+#include <sys/queue.h>
+#include <poll.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#ifdef CHECK_INVARIANTS
+#include <assert.h>
+#endif
+
+#include "event.h"
+#include "event-internal.h"
+#include "evsignal.h"
+#include "log.h"
+
+struct pollop {
+ int event_count; /* Highest number alloc */
+ int nfds; /* Size of event_* */
+ int fd_count; /* Size of idxplus1_by_fd */
+ struct pollfd *event_set;
+ struct event **event_r_back;
+ struct event **event_w_back;
+ int *idxplus1_by_fd; /* Index into event_set by fd; we add 1 so
+ * that 0 (which is easy to memset) can mean
+ * "no entry." */
+};
+
+static void *poll_init (struct event_base *);
+static int poll_add (void *, struct event *);
+static int poll_del (void *, struct event *);
+static int poll_dispatch (struct event_base *, void *, struct timeval *);
+static void poll_dealloc (struct event_base *, void *);
+
+const struct eventop pollops = {
+ "poll",
+ poll_init,
+ poll_add,
+ poll_del,
+ poll_dispatch,
+ poll_dealloc,
+ 0
+};
+
+static void *
+poll_init(struct event_base *base)
+{
+ struct pollop *pollop;
+
+ /* Disable poll when this environment variable is set */
+ if (evutil_getenv("EVENT_NOPOLL"))
+ return (NULL);
+
+ if (!(pollop = calloc(1, sizeof(struct pollop))))
+ return (NULL);
+
+ evsignal_init(base);
+
+ return (pollop);
+}
+
+#ifdef CHECK_INVARIANTS
+static void
+poll_check_ok(struct pollop *pop)
+{
+ int i, idx;
+ struct event *ev;
+
+ for (i = 0; i < pop->fd_count; ++i) {
+ idx = pop->idxplus1_by_fd[i]-1;
+ if (idx < 0)
+ continue;
+ assert(pop->event_set[idx].fd == i);
+ if (pop->event_set[idx].events & POLLIN) {
+ ev = pop->event_r_back[idx];
+ assert(ev);
+ assert(ev->ev_events & EV_READ);
+ assert(ev->ev_fd == i);
+ }
+ if (pop->event_set[idx].events & POLLOUT) {
+ ev = pop->event_w_back[idx];
+ assert(ev);
+ assert(ev->ev_events & EV_WRITE);
+ assert(ev->ev_fd == i);
+ }
+ }
+ for (i = 0; i < pop->nfds; ++i) {
+ struct pollfd *pfd = &pop->event_set[i];
+ assert(pop->idxplus1_by_fd[pfd->fd] == i+1);
+ }
+}
+#else
+#define poll_check_ok(pop)
+#endif
+
+static int
+poll_dispatch(struct event_base *base, void *arg, struct timeval *tv)
+{
+ int res, i, j, msec = -1, nfds;
+ struct pollop *pop = arg;
+
+ poll_check_ok(pop);
+
+ if (tv != NULL)
+ msec = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000;
+
+ nfds = pop->nfds;
+ res = poll(pop->event_set, nfds, msec);
+
+ if (res == -1) {
+ if (errno != EINTR) {
+ event_warn("poll");
+ return (-1);
+ }
+
+ evsignal_process(base);
+ return (0);
+ } else if (base->sig.evsignal_caught) {
+ evsignal_process(base);
+ }
+
+ event_debug(("%s: poll reports %d", __func__, res));
+
+ if (res == 0 || nfds == 0)
+ return (0);
+
+ i = random() % nfds;
+ for (j = 0; j < nfds; j++) {
+ struct event *r_ev = NULL, *w_ev = NULL;
+ int what;
+ if (++i == nfds)
+ i = 0;
+ what = pop->event_set[i].revents;
+
+ if (!what)
+ continue;
+
+ res = 0;
+
+ /* If the file gets closed notify */
+ if (what & (POLLHUP|POLLERR))
+ what |= POLLIN|POLLOUT;
+ if (what & POLLIN) {
+ res |= EV_READ;
+ r_ev = pop->event_r_back[i];
+ }
+ if (what & POLLOUT) {
+ res |= EV_WRITE;
+ w_ev = pop->event_w_back[i];
+ }
+ if (res == 0)
+ continue;
+
+ if (r_ev && (res & r_ev->ev_events)) {
+ event_active(r_ev, res & r_ev->ev_events, 1);
+ }
+ if (w_ev && w_ev != r_ev && (res & w_ev->ev_events)) {
+ event_active(w_ev, res & w_ev->ev_events, 1);
+ }
+ }
+
+ return (0);
+}
+
+static int
+poll_add(void *arg, struct event *ev)
+{
+ struct pollop *pop = arg;
+ struct pollfd *pfd = NULL;
+ int i;
+
+ if (ev->ev_events & EV_SIGNAL)
+ return (evsignal_add(ev));
+ if (!(ev->ev_events & (EV_READ|EV_WRITE)))
+ return (0);
+
+ poll_check_ok(pop);
+ if (pop->nfds + 1 >= pop->event_count) {
+ struct pollfd *tmp_event_set;
+ struct event **tmp_event_r_back;
+ struct event **tmp_event_w_back;
+ int tmp_event_count;
+
+ if (pop->event_count < 32)
+ tmp_event_count = 32;
+ else
+ tmp_event_count = pop->event_count * 2;
+
+ /* We need more file descriptors */
+ tmp_event_set = realloc(pop->event_set,
+ tmp_event_count * sizeof(struct pollfd));
+ if (tmp_event_set == NULL) {
+ event_warn("realloc");
+ return (-1);
+ }
+ pop->event_set = tmp_event_set;
+
+ tmp_event_r_back = realloc(pop->event_r_back,
+ tmp_event_count * sizeof(struct event *));
+ if (tmp_event_r_back == NULL) {
+ /* event_set overallocated; that's okay. */
+ event_warn("realloc");
+ return (-1);
+ }
+ pop->event_r_back = tmp_event_r_back;
+
+ tmp_event_w_back = realloc(pop->event_w_back,
+ tmp_event_count * sizeof(struct event *));
+ if (tmp_event_w_back == NULL) {
+ /* event_set and event_r_back overallocated; that's
+ * okay. */
+ event_warn("realloc");
+ return (-1);
+ }
+ pop->event_w_back = tmp_event_w_back;
+
+ pop->event_count = tmp_event_count;
+ }
+ if (ev->ev_fd >= pop->fd_count) {
+ int *tmp_idxplus1_by_fd;
+ int new_count;
+ if (pop->fd_count < 32)
+ new_count = 32;
+ else
+ new_count = pop->fd_count * 2;
+ while (new_count <= ev->ev_fd)
+ new_count *= 2;
+ tmp_idxplus1_by_fd =
+ realloc(pop->idxplus1_by_fd, new_count * sizeof(int));
+ if (tmp_idxplus1_by_fd == NULL) {
+ event_warn("realloc");
+ return (-1);
+ }
+ pop->idxplus1_by_fd = tmp_idxplus1_by_fd;
+ memset(pop->idxplus1_by_fd + pop->fd_count,
+ 0, sizeof(int)*(new_count - pop->fd_count));
+ pop->fd_count = new_count;
+ }
+
+ i = pop->idxplus1_by_fd[ev->ev_fd] - 1;
+ if (i >= 0) {
+ pfd = &pop->event_set[i];
+ } else {
+ i = pop->nfds++;
+ pfd = &pop->event_set[i];
+ pfd->events = 0;
+ pfd->fd = ev->ev_fd;
+ pop->event_w_back[i] = pop->event_r_back[i] = NULL;
+ pop->idxplus1_by_fd[ev->ev_fd] = i + 1;
+ }
+
+ pfd->revents = 0;
+ if (ev->ev_events & EV_WRITE) {
+ pfd->events |= POLLOUT;
+ pop->event_w_back[i] = ev;
+ }
+ if (ev->ev_events & EV_READ) {
+ pfd->events |= POLLIN;
+ pop->event_r_back[i] = ev;
+ }
+ poll_check_ok(pop);
+
+ return (0);
+}
+
+/*
+ * Nothing to be done here.
+ */
+
+static int
+poll_del(void *arg, struct event *ev)
+{
+ struct pollop *pop = arg;
+ struct pollfd *pfd = NULL;
+ int i;
+
+ if (ev->ev_events & EV_SIGNAL)
+ return (evsignal_del(ev));
+
+ if (!(ev->ev_events & (EV_READ|EV_WRITE)))
+ return (0);
+
+ poll_check_ok(pop);
+ i = pop->idxplus1_by_fd[ev->ev_fd] - 1;
+ if (i < 0)
+ return (-1);
+
+ /* Do we still want to read or write? */
+ pfd = &pop->event_set[i];
+ if (ev->ev_events & EV_READ) {
+ pfd->events &= ~POLLIN;
+ pop->event_r_back[i] = NULL;
+ }
+ if (ev->ev_events & EV_WRITE) {
+ pfd->events &= ~POLLOUT;
+ pop->event_w_back[i] = NULL;
+ }
+ poll_check_ok(pop);
+ if (pfd->events)
+ /* Another event cares about that fd. */
+ return (0);
+
+ /* Okay, so we aren't interested in that fd anymore. */
+ pop->idxplus1_by_fd[ev->ev_fd] = 0;
+
+ --pop->nfds;
+ if (i != pop->nfds) {
+ /*
+ * Shift the last pollfd down into the now-unoccupied
+ * position.
+ */
+ memcpy(&pop->event_set[i], &pop->event_set[pop->nfds],
+ sizeof(struct pollfd));
+ pop->event_r_back[i] = pop->event_r_back[pop->nfds];
+ pop->event_w_back[i] = pop->event_w_back[pop->nfds];
+ pop->idxplus1_by_fd[pop->event_set[i].fd] = i + 1;
+ }
+
+ poll_check_ok(pop);
+ return (0);
+}
+
+static void
+poll_dealloc(struct event_base *base, void *arg)
+{
+ struct pollop *pop = arg;
+
+ evsignal_dealloc(base);
+ if (pop->event_set)
+ free(pop->event_set);
+ if (pop->event_r_back)
+ free(pop->event_r_back);
+ if (pop->event_w_back)
+ free(pop->event_w_back);
+ if (pop->idxplus1_by_fd)
+ free(pop->idxplus1_by_fd);
+
+ memset(pop, 0, sizeof(struct pollop));
+ free(pop);
+}
diff --git a/chromium/base/third_party/libevent/sample/Makefile.am b/chromium/base/third_party/libevent/sample/Makefile.am
new file mode 100644
index 00000000000..2f4e26e2f3f
--- /dev/null
+++ b/chromium/base/third_party/libevent/sample/Makefile.am
@@ -0,0 +1,14 @@
+AUTOMAKE_OPTIONS = foreign no-dependencies
+
+LDADD = ../libevent.la
+AM_CFLAGS = -I$(top_srcdir) -I$(top_srcdir)/compat
+
+noinst_PROGRAMS = event-test time-test signal-test
+
+event_test_sources = event-test.c
+time_test_sources = time-test.c
+signal_test_sources = signal-test.c
+
+verify:
+
+DISTCLEANFILES = *~
diff --git a/chromium/base/third_party/libevent/sample/event-test.c b/chromium/base/third_party/libevent/sample/event-test.c
new file mode 100644
index 00000000000..0a439cee413
--- /dev/null
+++ b/chromium/base/third_party/libevent/sample/event-test.c
@@ -0,0 +1,139 @@
+/*
+ * Compile with:
+ * cc -I/usr/local/include -o event-test event-test.c -L/usr/local/lib -levent
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifndef WIN32
+#include <sys/queue.h>
+#include <unistd.h>
+#include <sys/time.h>
+#else
+#include <windows.h>
+#endif
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <event.h>
+
+static void
+fifo_read(int fd, short event, void *arg)
+{
+ char buf[255];
+ int len;
+ struct event *ev = arg;
+#ifdef WIN32
+ DWORD dwBytesRead;
+#endif
+
+ /* Reschedule this event */
+ event_add(ev, NULL);
+
+ fprintf(stderr, "fifo_read called with fd: %d, event: %d, arg: %p\n",
+ fd, event, arg);
+#ifdef WIN32
+ len = ReadFile((HANDLE)fd, buf, sizeof(buf) - 1, &dwBytesRead, NULL);
+
+ // Check for end of file.
+ if(len && dwBytesRead == 0) {
+ fprintf(stderr, "End Of File");
+ event_del(ev);
+ return;
+ }
+
+ buf[dwBytesRead] = '\0';
+#else
+ len = read(fd, buf, sizeof(buf) - 1);
+
+ if (len == -1) {
+ perror("read");
+ return;
+ } else if (len == 0) {
+ fprintf(stderr, "Connection closed\n");
+ return;
+ }
+
+ buf[len] = '\0';
+#endif
+ fprintf(stdout, "Read: %s\n", buf);
+}
+
+int
+main (int argc, char **argv)
+{
+ struct event evfifo;
+#ifdef WIN32
+ HANDLE socket;
+ // Open a file.
+ socket = CreateFileA("test.txt", // open File
+ GENERIC_READ, // open for reading
+ 0, // do not share
+ NULL, // no security
+ OPEN_EXISTING, // existing file only
+ FILE_ATTRIBUTE_NORMAL, // normal file
+ NULL); // no attr. template
+
+ if(socket == INVALID_HANDLE_VALUE)
+ return 1;
+
+#else
+ struct stat st;
+ const char *fifo = "event.fifo";
+ int socket;
+
+ if (lstat (fifo, &st) == 0) {
+ if ((st.st_mode & S_IFMT) == S_IFREG) {
+ errno = EEXIST;
+ perror("lstat");
+ exit (1);
+ }
+ }
+
+ unlink (fifo);
+ if (mkfifo (fifo, 0600) == -1) {
+ perror("mkfifo");
+ exit (1);
+ }
+
+ /* Linux pipes are broken, we need O_RDWR instead of O_RDONLY */
+#ifdef __linux
+ socket = open (fifo, O_RDWR | O_NONBLOCK, 0);
+#else
+ socket = open (fifo, O_RDONLY | O_NONBLOCK, 0);
+#endif
+
+ if (socket == -1) {
+ perror("open");
+ exit (1);
+ }
+
+ fprintf(stderr, "Write data to %s\n", fifo);
+#endif
+ /* Initalize the event library */
+ event_init();
+
+ /* Initalize one event */
+#ifdef WIN32
+ event_set(&evfifo, (int)socket, EV_READ, fifo_read, &evfifo);
+#else
+ event_set(&evfifo, socket, EV_READ, fifo_read, &evfifo);
+#endif
+
+ /* Add it to the active events, without a timeout */
+ event_add(&evfifo, NULL);
+
+ event_dispatch();
+#ifdef WIN32
+ CloseHandle(socket);
+#endif
+ return (0);
+}
+
diff --git a/chromium/base/third_party/libevent/sample/signal-test.c b/chromium/base/third_party/libevent/sample/signal-test.c
new file mode 100644
index 00000000000..5a5a303f3d8
--- /dev/null
+++ b/chromium/base/third_party/libevent/sample/signal-test.c
@@ -0,0 +1,65 @@
+/*
+ * Compile with:
+ * cc -I/usr/local/include -o signal-test \
+ * signal-test.c -L/usr/local/lib -levent
+ */
+
+#include <sys/types.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/stat.h>
+#ifndef WIN32
+#include <sys/queue.h>
+#include <unistd.h>
+#include <sys/time.h>
+#else
+#include <windows.h>
+#endif
+#include <signal.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <event.h>
+
+int called = 0;
+
+static void
+signal_cb(int fd, short event, void *arg)
+{
+ struct event *signal = arg;
+
+ printf("%s: got signal %d\n", __func__, EVENT_SIGNAL(signal));
+
+ if (called >= 2)
+ event_del(signal);
+
+ called++;
+}
+
+int
+main (int argc, char **argv)
+{
+ struct event signal_int;
+
+ /* Initalize the event library */
+ struct event_base* base = event_base_new();
+
+ /* Initalize one event */
+ event_set(&signal_int, SIGINT, EV_SIGNAL|EV_PERSIST, signal_cb,
+ &signal_int);
+ event_base_set(base, &signal_int);
+
+ event_add(&signal_int, NULL);
+
+ event_base_dispatch(base);
+ event_base_free(base);
+
+ return (0);
+}
+
diff --git a/chromium/base/third_party/libevent/sample/time-test.c b/chromium/base/third_party/libevent/sample/time-test.c
new file mode 100644
index 00000000000..069d4f8f783
--- /dev/null
+++ b/chromium/base/third_party/libevent/sample/time-test.c
@@ -0,0 +1,70 @@
+/*
+ * Compile with:
+ * cc -I/usr/local/include -o time-test time-test.c -L/usr/local/lib -levent
+ */
+
+#include <sys/types.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/stat.h>
+#ifndef WIN32
+#include <sys/queue.h>
+#include <unistd.h>
+#endif
+#include <time.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <event.h>
+#include <evutil.h>
+
+int lasttime;
+
+static void
+timeout_cb(int fd, short event, void *arg)
+{
+ struct timeval tv;
+ struct event *timeout = arg;
+ int newtime = time(NULL);
+
+ printf("%s: called at %d: %d\n", __func__, newtime,
+ newtime - lasttime);
+ lasttime = newtime;
+
+ evutil_timerclear(&tv);
+ tv.tv_sec = 2;
+ event_add(timeout, &tv);
+}
+
+int
+main (int argc, char **argv)
+{
+ struct event timeout;
+ struct timeval tv;
+
+ /* Initalize the event library */
+ event_init();
+
+ /* Initalize one event */
+ evtimer_set(&timeout, timeout_cb, &timeout);
+
+ evutil_timerclear(&tv);
+ tv.tv_sec = 2;
+ event_add(&timeout, &tv);
+
+ lasttime = time(NULL);
+
+ event_dispatch();
+
+ return (0);
+}
+
diff --git a/chromium/base/third_party/libevent/select.c b/chromium/base/third_party/libevent/select.c
new file mode 100644
index 00000000000..3f733313177
--- /dev/null
+++ b/chromium/base/third_party/libevent/select.c
@@ -0,0 +1,364 @@
+/* $OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */
+
+/*
+ * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#else
+#include <sys/_libevent_time.h>
+#endif
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#include <sys/queue.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#ifdef CHECK_INVARIANTS
+#include <assert.h>
+#endif
+
+#include "event.h"
+#include "evutil.h"
+#include "event-internal.h"
+#include "evsignal.h"
+#include "log.h"
+
+#ifndef howmany
+#define howmany(x, y) (((x)+((y)-1))/(y))
+#endif
+
+#ifndef _EVENT_HAVE_FD_MASK
+/* This type is mandatory, but Android doesn't define it. */
+#undef NFDBITS
+#define NFDBITS (sizeof(long)*8)
+typedef unsigned long fd_mask;
+#endif
+
+struct selectop {
+ int event_fds; /* Highest fd in fd set */
+ int event_fdsz;
+ fd_set *event_readset_in;
+ fd_set *event_writeset_in;
+ fd_set *event_readset_out;
+ fd_set *event_writeset_out;
+ struct event **event_r_by_fd;
+ struct event **event_w_by_fd;
+};
+
+static void *select_init (struct event_base *);
+static int select_add (void *, struct event *);
+static int select_del (void *, struct event *);
+static int select_dispatch (struct event_base *, void *, struct timeval *);
+static void select_dealloc (struct event_base *, void *);
+
+const struct eventop selectops = {
+ "select",
+ select_init,
+ select_add,
+ select_del,
+ select_dispatch,
+ select_dealloc,
+ 0
+};
+
+static int select_resize(struct selectop *sop, int fdsz);
+
+static void *
+select_init(struct event_base *base)
+{
+ struct selectop *sop;
+
+ /* Disable select when this environment variable is set */
+ if (evutil_getenv("EVENT_NOSELECT"))
+ return (NULL);
+
+ if (!(sop = calloc(1, sizeof(struct selectop))))
+ return (NULL);
+
+ select_resize(sop, howmany(32 + 1, NFDBITS)*sizeof(fd_mask));
+
+ evsignal_init(base);
+
+ return (sop);
+}
+
+#ifdef CHECK_INVARIANTS
+static void
+check_selectop(struct selectop *sop)
+{
+ int i;
+ for (i = 0; i <= sop->event_fds; ++i) {
+ if (FD_ISSET(i, sop->event_readset_in)) {
+ assert(sop->event_r_by_fd[i]);
+ assert(sop->event_r_by_fd[i]->ev_events & EV_READ);
+ assert(sop->event_r_by_fd[i]->ev_fd == i);
+ } else {
+ assert(! sop->event_r_by_fd[i]);
+ }
+ if (FD_ISSET(i, sop->event_writeset_in)) {
+ assert(sop->event_w_by_fd[i]);
+ assert(sop->event_w_by_fd[i]->ev_events & EV_WRITE);
+ assert(sop->event_w_by_fd[i]->ev_fd == i);
+ } else {
+ assert(! sop->event_w_by_fd[i]);
+ }
+ }
+
+}
+#else
+#define check_selectop(sop) do { (void) sop; } while (0)
+#endif
+
+static int
+select_dispatch(struct event_base *base, void *arg, struct timeval *tv)
+{
+ int res, i, j;
+ struct selectop *sop = arg;
+
+ check_selectop(sop);
+
+ memcpy(sop->event_readset_out, sop->event_readset_in,
+ sop->event_fdsz);
+ memcpy(sop->event_writeset_out, sop->event_writeset_in,
+ sop->event_fdsz);
+
+ res = select(sop->event_fds + 1, sop->event_readset_out,
+ sop->event_writeset_out, NULL, tv);
+
+ check_selectop(sop);
+
+ if (res == -1) {
+ if (errno != EINTR) {
+ event_warn("select");
+ return (-1);
+ }
+
+ evsignal_process(base);
+ return (0);
+ } else if (base->sig.evsignal_caught) {
+ evsignal_process(base);
+ }
+
+ event_debug(("%s: select reports %d", __func__, res));
+
+ check_selectop(sop);
+ i = random() % (sop->event_fds+1);
+ for (j = 0; j <= sop->event_fds; ++j) {
+ struct event *r_ev = NULL, *w_ev = NULL;
+ if (++i >= sop->event_fds+1)
+ i = 0;
+
+ res = 0;
+ if (FD_ISSET(i, sop->event_readset_out)) {
+ r_ev = sop->event_r_by_fd[i];
+ res |= EV_READ;
+ }
+ if (FD_ISSET(i, sop->event_writeset_out)) {
+ w_ev = sop->event_w_by_fd[i];
+ res |= EV_WRITE;
+ }
+ if (r_ev && (res & r_ev->ev_events)) {
+ event_active(r_ev, res & r_ev->ev_events, 1);
+ }
+ if (w_ev && w_ev != r_ev && (res & w_ev->ev_events)) {
+ event_active(w_ev, res & w_ev->ev_events, 1);
+ }
+ }
+ check_selectop(sop);
+
+ return (0);
+}
+
+
+static int
+select_resize(struct selectop *sop, int fdsz)
+{
+ int n_events, n_events_old;
+
+ fd_set *readset_in = NULL;
+ fd_set *writeset_in = NULL;
+ fd_set *readset_out = NULL;
+ fd_set *writeset_out = NULL;
+ struct event **r_by_fd = NULL;
+ struct event **w_by_fd = NULL;
+
+ n_events = (fdsz/sizeof(fd_mask)) * NFDBITS;
+ n_events_old = (sop->event_fdsz/sizeof(fd_mask)) * NFDBITS;
+
+ if (sop->event_readset_in)
+ check_selectop(sop);
+
+ if ((readset_in = realloc(sop->event_readset_in, fdsz)) == NULL)
+ goto error;
+ sop->event_readset_in = readset_in;
+ if ((readset_out = realloc(sop->event_readset_out, fdsz)) == NULL)
+ goto error;
+ sop->event_readset_out = readset_out;
+ if ((writeset_in = realloc(sop->event_writeset_in, fdsz)) == NULL)
+ goto error;
+ sop->event_writeset_in = writeset_in;
+ if ((writeset_out = realloc(sop->event_writeset_out, fdsz)) == NULL)
+ goto error;
+ sop->event_writeset_out = writeset_out;
+ if ((r_by_fd = realloc(sop->event_r_by_fd,
+ n_events*sizeof(struct event*))) == NULL)
+ goto error;
+ sop->event_r_by_fd = r_by_fd;
+ if ((w_by_fd = realloc(sop->event_w_by_fd,
+ n_events * sizeof(struct event*))) == NULL)
+ goto error;
+ sop->event_w_by_fd = w_by_fd;
+
+ memset((char *)sop->event_readset_in + sop->event_fdsz, 0,
+ fdsz - sop->event_fdsz);
+ memset((char *)sop->event_writeset_in + sop->event_fdsz, 0,
+ fdsz - sop->event_fdsz);
+ memset(sop->event_r_by_fd + n_events_old, 0,
+ (n_events-n_events_old) * sizeof(struct event*));
+ memset(sop->event_w_by_fd + n_events_old, 0,
+ (n_events-n_events_old) * sizeof(struct event*));
+
+ sop->event_fdsz = fdsz;
+ check_selectop(sop);
+
+ return (0);
+
+ error:
+ event_warn("malloc");
+ return (-1);
+}
+
+
+static int
+select_add(void *arg, struct event *ev)
+{
+ struct selectop *sop = arg;
+
+ if (ev->ev_events & EV_SIGNAL)
+ return (evsignal_add(ev));
+
+ check_selectop(sop);
+ /*
+ * Keep track of the highest fd, so that we can calculate the size
+ * of the fd_sets for select(2)
+ */
+ if (sop->event_fds < ev->ev_fd) {
+ int fdsz = sop->event_fdsz;
+
+ if (fdsz < sizeof(fd_mask))
+ fdsz = sizeof(fd_mask);
+
+ while (fdsz <
+ (howmany(ev->ev_fd + 1, NFDBITS) * sizeof(fd_mask)))
+ fdsz *= 2;
+
+ if (fdsz != sop->event_fdsz) {
+ if (select_resize(sop, fdsz)) {
+ check_selectop(sop);
+ return (-1);
+ }
+ }
+
+ sop->event_fds = ev->ev_fd;
+ }
+
+ if (ev->ev_events & EV_READ) {
+ FD_SET(ev->ev_fd, sop->event_readset_in);
+ sop->event_r_by_fd[ev->ev_fd] = ev;
+ }
+ if (ev->ev_events & EV_WRITE) {
+ FD_SET(ev->ev_fd, sop->event_writeset_in);
+ sop->event_w_by_fd[ev->ev_fd] = ev;
+ }
+ check_selectop(sop);
+
+ return (0);
+}
+
+/*
+ * Nothing to be done here.
+ */
+
+static int
+select_del(void *arg, struct event *ev)
+{
+ struct selectop *sop = arg;
+
+ check_selectop(sop);
+ if (ev->ev_events & EV_SIGNAL)
+ return (evsignal_del(ev));
+
+ if (sop->event_fds < ev->ev_fd) {
+ check_selectop(sop);
+ return (0);
+ }
+
+ if (ev->ev_events & EV_READ) {
+ FD_CLR(ev->ev_fd, sop->event_readset_in);
+ sop->event_r_by_fd[ev->ev_fd] = NULL;
+ }
+
+ if (ev->ev_events & EV_WRITE) {
+ FD_CLR(ev->ev_fd, sop->event_writeset_in);
+ sop->event_w_by_fd[ev->ev_fd] = NULL;
+ }
+
+ check_selectop(sop);
+ return (0);
+}
+
+static void
+select_dealloc(struct event_base *base, void *arg)
+{
+ struct selectop *sop = arg;
+
+ evsignal_dealloc(base);
+ if (sop->event_readset_in)
+ free(sop->event_readset_in);
+ if (sop->event_writeset_in)
+ free(sop->event_writeset_in);
+ if (sop->event_readset_out)
+ free(sop->event_readset_out);
+ if (sop->event_writeset_out)
+ free(sop->event_writeset_out);
+ if (sop->event_r_by_fd)
+ free(sop->event_r_by_fd);
+ if (sop->event_w_by_fd)
+ free(sop->event_w_by_fd);
+
+ memset(sop, 0, sizeof(struct selectop));
+ free(sop);
+}
diff --git a/chromium/base/third_party/libevent/signal.c b/chromium/base/third_party/libevent/signal.c
new file mode 100644
index 00000000000..b8d51ab5198
--- /dev/null
+++ b/chromium/base/third_party/libevent/signal.c
@@ -0,0 +1,377 @@
+/* $OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */
+
+/*
+ * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <winsock2.h>
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#endif
+#include <sys/types.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/queue.h>
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <errno.h>
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#include <assert.h>
+
+#include "event.h"
+#include "event-internal.h"
+#include "evsignal.h"
+#include "evutil.h"
+#include "log.h"
+
+struct event_base *evsignal_base = NULL;
+
+static void evsignal_handler(int sig);
+
+#ifdef WIN32
+#define error_is_eagain(err) \
+ ((err) == EAGAIN || (err) == WSAEWOULDBLOCK)
+#else
+#define error_is_eagain(err) ((err) == EAGAIN)
+#endif
+
+/* Callback for when the signal handler write a byte to our signaling socket */
+static void
+evsignal_cb(int fd, short what, void *arg)
+{
+ static char signals[1];
+#ifdef WIN32
+ SSIZE_T n;
+#else
+ ssize_t n;
+#endif
+
+ n = recv(fd, signals, sizeof(signals), 0);
+ if (n == -1) {
+ int err = EVUTIL_SOCKET_ERROR();
+ if (! error_is_eagain(err))
+ event_err(1, "%s: read", __func__);
+ }
+}
+
+#ifdef HAVE_SETFD
+#define FD_CLOSEONEXEC(x) do { \
+ if (fcntl(x, F_SETFD, 1) == -1) \
+ event_warn("fcntl(%d, F_SETFD)", x); \
+} while (0)
+#else
+#define FD_CLOSEONEXEC(x)
+#endif
+
+int
+evsignal_init(struct event_base *base)
+{
+ int i;
+
+ /*
+ * Our signal handler is going to write to one end of the socket
+ * pair to wake up our event loop. The event loop then scans for
+ * signals that got delivered.
+ */
+ if (evutil_socketpair(
+ AF_UNIX, SOCK_STREAM, 0, base->sig.ev_signal_pair) == -1) {
+#ifdef WIN32
+ /* Make this nonfatal on win32, where sometimes people
+ have localhost firewalled. */
+ event_warn("%s: socketpair", __func__);
+#else
+ event_err(1, "%s: socketpair", __func__);
+#endif
+ return -1;
+ }
+
+ FD_CLOSEONEXEC(base->sig.ev_signal_pair[0]);
+ FD_CLOSEONEXEC(base->sig.ev_signal_pair[1]);
+ base->sig.sh_old = NULL;
+ base->sig.sh_old_max = 0;
+ base->sig.evsignal_caught = 0;
+ memset(&base->sig.evsigcaught, 0, sizeof(sig_atomic_t)*NSIG);
+ /* initialize the queues for all events */
+ for (i = 0; i < NSIG; ++i)
+ TAILQ_INIT(&base->sig.evsigevents[i]);
+
+ evutil_make_socket_nonblocking(base->sig.ev_signal_pair[0]);
+ evutil_make_socket_nonblocking(base->sig.ev_signal_pair[1]);
+
+ event_set(&base->sig.ev_signal, base->sig.ev_signal_pair[1],
+ EV_READ | EV_PERSIST, evsignal_cb, &base->sig.ev_signal);
+ base->sig.ev_signal.ev_base = base;
+ base->sig.ev_signal.ev_flags |= EVLIST_INTERNAL;
+
+ return 0;
+}
+
+/* Helper: set the signal handler for evsignal to handler in base, so that
+ * we can restore the original handler when we clear the current one. */
+int
+_evsignal_set_handler(struct event_base *base,
+ int evsignal, void (*handler)(int))
+{
+#ifdef HAVE_SIGACTION
+ struct sigaction sa;
+#else
+ ev_sighandler_t sh;
+#endif
+ struct evsignal_info *sig = &base->sig;
+ void *p;
+
+ /*
+ * resize saved signal handler array up to the highest signal number.
+ * a dynamic array is used to keep footprint on the low side.
+ */
+ if (evsignal >= sig->sh_old_max) {
+ int new_max = evsignal + 1;
+ event_debug(("%s: evsignal (%d) >= sh_old_max (%d), resizing",
+ __func__, evsignal, sig->sh_old_max));
+ p = realloc(sig->sh_old, new_max * sizeof(*sig->sh_old));
+ if (p == NULL) {
+ event_warn("realloc");
+ return (-1);
+ }
+
+ memset((char *)p + sig->sh_old_max * sizeof(*sig->sh_old),
+ 0, (new_max - sig->sh_old_max) * sizeof(*sig->sh_old));
+
+ sig->sh_old_max = new_max;
+ sig->sh_old = p;
+ }
+
+ /* allocate space for previous handler out of dynamic array */
+ sig->sh_old[evsignal] = malloc(sizeof *sig->sh_old[evsignal]);
+ if (sig->sh_old[evsignal] == NULL) {
+ event_warn("malloc");
+ return (-1);
+ }
+
+ /* save previous handler and setup new handler */
+#ifdef HAVE_SIGACTION
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = handler;
+ sa.sa_flags |= SA_RESTART;
+ sigfillset(&sa.sa_mask);
+
+ if (sigaction(evsignal, &sa, sig->sh_old[evsignal]) == -1) {
+ event_warn("sigaction");
+ free(sig->sh_old[evsignal]);
+ sig->sh_old[evsignal] = NULL;
+ return (-1);
+ }
+#else
+ if ((sh = signal(evsignal, handler)) == SIG_ERR) {
+ event_warn("signal");
+ free(sig->sh_old[evsignal]);
+ sig->sh_old[evsignal] = NULL;
+ return (-1);
+ }
+ *sig->sh_old[evsignal] = sh;
+#endif
+
+ return (0);
+}
+
+int
+evsignal_add(struct event *ev)
+{
+ int evsignal;
+ struct event_base *base = ev->ev_base;
+ struct evsignal_info *sig = &ev->ev_base->sig;
+
+ if (ev->ev_events & (EV_READ|EV_WRITE))
+ event_errx(1, "%s: EV_SIGNAL incompatible use", __func__);
+ evsignal = EVENT_SIGNAL(ev);
+ assert(evsignal >= 0 && evsignal < NSIG);
+ if (TAILQ_EMPTY(&sig->evsigevents[evsignal])) {
+ event_debug(("%s: %p: changing signal handler", __func__, ev));
+ if (_evsignal_set_handler(
+ base, evsignal, evsignal_handler) == -1)
+ return (-1);
+
+ /* catch signals if they happen quickly */
+ evsignal_base = base;
+
+ if (!sig->ev_signal_added) {
+ if (event_add(&sig->ev_signal, NULL))
+ return (-1);
+ sig->ev_signal_added = 1;
+ }
+ }
+
+ /* multiple events may listen to the same signal */
+ TAILQ_INSERT_TAIL(&sig->evsigevents[evsignal], ev, ev_signal_next);
+
+ return (0);
+}
+
+int
+_evsignal_restore_handler(struct event_base *base, int evsignal)
+{
+ int ret = 0;
+ struct evsignal_info *sig = &base->sig;
+#ifdef HAVE_SIGACTION
+ struct sigaction *sh;
+#else
+ ev_sighandler_t *sh;
+#endif
+
+ /* restore previous handler */
+ sh = sig->sh_old[evsignal];
+ sig->sh_old[evsignal] = NULL;
+#ifdef HAVE_SIGACTION
+ if (sigaction(evsignal, sh, NULL) == -1) {
+ event_warn("sigaction");
+ ret = -1;
+ }
+#else
+ if (signal(evsignal, *sh) == SIG_ERR) {
+ event_warn("signal");
+ ret = -1;
+ }
+#endif
+ free(sh);
+
+ return ret;
+}
+
+int
+evsignal_del(struct event *ev)
+{
+ struct event_base *base = ev->ev_base;
+ struct evsignal_info *sig = &base->sig;
+ int evsignal = EVENT_SIGNAL(ev);
+
+ assert(evsignal >= 0 && evsignal < NSIG);
+
+ /* multiple events may listen to the same signal */
+ TAILQ_REMOVE(&sig->evsigevents[evsignal], ev, ev_signal_next);
+
+ if (!TAILQ_EMPTY(&sig->evsigevents[evsignal]))
+ return (0);
+
+ event_debug(("%s: %p: restoring signal handler", __func__, ev));
+
+ return (_evsignal_restore_handler(ev->ev_base, EVENT_SIGNAL(ev)));
+}
+
+static void
+evsignal_handler(int sig)
+{
+ int save_errno = errno;
+
+ if (evsignal_base == NULL) {
+ event_warn(
+ "%s: received signal %d, but have no base configured",
+ __func__, sig);
+ return;
+ }
+
+ evsignal_base->sig.evsigcaught[sig]++;
+ evsignal_base->sig.evsignal_caught = 1;
+
+#ifndef HAVE_SIGACTION
+ signal(sig, evsignal_handler);
+#endif
+
+ /* Wake up our notification mechanism */
+ send(evsignal_base->sig.ev_signal_pair[0], "a", 1, 0);
+ errno = save_errno;
+}
+
+void
+evsignal_process(struct event_base *base)
+{
+ struct evsignal_info *sig = &base->sig;
+ struct event *ev, *next_ev;
+ sig_atomic_t ncalls;
+ int i;
+
+ base->sig.evsignal_caught = 0;
+ for (i = 1; i < NSIG; ++i) {
+ ncalls = sig->evsigcaught[i];
+ if (ncalls == 0)
+ continue;
+ sig->evsigcaught[i] -= ncalls;
+
+ for (ev = TAILQ_FIRST(&sig->evsigevents[i]);
+ ev != NULL; ev = next_ev) {
+ next_ev = TAILQ_NEXT(ev, ev_signal_next);
+ if (!(ev->ev_events & EV_PERSIST))
+ event_del(ev);
+ event_active(ev, EV_SIGNAL, ncalls);
+ }
+
+ }
+}
+
+void
+evsignal_dealloc(struct event_base *base)
+{
+ int i = 0;
+ if (base->sig.ev_signal_added) {
+ event_del(&base->sig.ev_signal);
+ base->sig.ev_signal_added = 0;
+ }
+ for (i = 0; i < NSIG; ++i) {
+ if (i < base->sig.sh_old_max && base->sig.sh_old[i] != NULL)
+ _evsignal_restore_handler(base, i);
+ }
+
+ if (base->sig.ev_signal_pair[0] != -1) {
+ EVUTIL_CLOSESOCKET(base->sig.ev_signal_pair[0]);
+ base->sig.ev_signal_pair[0] = -1;
+ }
+ if (base->sig.ev_signal_pair[1] != -1) {
+ EVUTIL_CLOSESOCKET(base->sig.ev_signal_pair[1]);
+ base->sig.ev_signal_pair[1] = -1;
+ }
+ base->sig.sh_old_max = 0;
+
+ /* per index frees are handled in evsig_del() */
+ if (base->sig.sh_old) {
+ free(base->sig.sh_old);
+ base->sig.sh_old = NULL;
+ }
+}
diff --git a/chromium/base/third_party/libevent/solaris/config.h b/chromium/base/third_party/libevent/solaris/config.h
new file mode 100644
index 00000000000..4dd40eb36eb
--- /dev/null
+++ b/chromium/base/third_party/libevent/solaris/config.h
@@ -0,0 +1,266 @@
+/* config.h. Generated from config.h.in by configure. */
+/* config.h.in. Generated from configure.in by autoheader. */
+
+/* Define if clock_gettime is available in libc */
+#define DNS_USE_CPU_CLOCK_FOR_ID 1
+
+/* Define is no secure id variant is available */
+/* #undef DNS_USE_GETTIMEOFDAY_FOR_ID */
+
+/* Define to 1 if you have the `clock_gettime' function. */
+#define HAVE_CLOCK_GETTIME 1
+
+/* Define if /dev/poll is available */
+#define HAVE_DEVPOLL 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define if your system supports the epoll system calls */
+/* #undef HAVE_EPOLL */
+
+/* Define to 1 if you have the `epoll_ctl' function. */
+/* #undef HAVE_EPOLL_CTL */
+
+/* Define if your system supports event ports */
+#define HAVE_EVENT_PORTS 1
+
+/* Define to 1 if you have the `fcntl' function. */
+#define HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if the system has the type `fd_mask'. */
+#define HAVE_FD_MASK 1
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#define HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `getegid' function. */
+#define HAVE_GETEGID 1
+
+/* Define to 1 if you have the `geteuid' function. */
+#define HAVE_GETEUID 1
+
+/* Define to 1 if you have the `getnameinfo' function. */
+#define HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the `inet_ntop' function. */
+#define HAVE_INET_NTOP 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `issetugid' function. */
+#define HAVE_ISSETUGID 1
+
+/* Define to 1 if you have the `kqueue' function. */
+/* #undef HAVE_KQUEUE */
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+#define HAVE_LIBNSL 1
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+#define HAVE_LIBRESOLV 1
+
+/* Define to 1 if you have the `rt' library (-lrt). */
+#define HAVE_LIBRT 1
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+#define HAVE_LIBSOCKET 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <netinet/in6.h> header file. */
+/* #undef HAVE_NETINET_IN6_H */
+
+/* Define to 1 if you have the `poll' function. */
+#define HAVE_POLL 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define HAVE_POLL_H 1
+
+/* Define to 1 if you have the `port_create' function. */
+#define HAVE_PORT_CREATE 1
+
+/* Define to 1 if you have the <port.h> header file. */
+#define HAVE_PORT_H 1
+
+/* Define to 1 if you have the `select' function. */
+#define HAVE_SELECT 1
+
+/* Define if F_SETFD is defined in <fcntl.h> */
+#define HAVE_SETFD 1
+
+/* Define to 1 if you have the `sigaction' function. */
+#define HAVE_SIGACTION 1
+
+/* Define to 1 if you have the `signal' function. */
+#define HAVE_SIGNAL 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#define HAVE_STDARG_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+#define HAVE_STRLCPY 1
+
+/* Define to 1 if you have the `strsep' function. */
+#define HAVE_STRSEP 1
+
+/* Define to 1 if you have the `strtok_r' function. */
+#define HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the `strtoll' function. */
+#define HAVE_STRTOLL 1
+
+/* Define to 1 if the system has the type `struct in6_addr'. */
+#define HAVE_STRUCT_IN6_ADDR 1
+
+/* Define to 1 if you have the <sys/devpoll.h> header file. */
+#define HAVE_SYS_DEVPOLL_H 1
+
+/* Define to 1 if you have the <sys/epoll.h> header file. */
+/* #undef HAVE_SYS_EPOLL_H */
+
+/* Define to 1 if you have the <sys/event.h> header file. */
+/* #undef HAVE_SYS_EVENT_H */
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/queue.h> header file. */
+#define HAVE_SYS_QUEUE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
+#define HAVE_TAILQFOREACH 1
+
+/* Define if timeradd is defined in <sys/time.h> */
+#define HAVE_TIMERADD 1
+
+/* Define if timerclear is defined in <sys/time.h> */
+#define HAVE_TIMERCLEAR 1
+
+/* Define if timercmp is defined in <sys/time.h> */
+#define HAVE_TIMERCMP 1
+
+/* Define if timerisset is defined in <sys/time.h> */
+#define HAVE_TIMERISSET 1
+
+/* Define to 1 if the system has the type `uint16_t'. */
+#define HAVE_UINT16_T 1
+
+/* Define to 1 if the system has the type `uint32_t'. */
+#define HAVE_UINT32_T 1
+
+/* Define to 1 if the system has the type `uint64_t'. */
+#define HAVE_UINT64_T 1
+
+/* Define to 1 if the system has the type `uint8_t'. */
+#define HAVE_UINT8_T 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `vasprintf' function. */
+#define HAVE_VASPRINTF 1
+
+/* Define if kqueue works correctly with pipes */
+/* #undef HAVE_WORKING_KQUEUE */
+
+/* Name of package */
+#define PACKAGE "libevent"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION ""
+
+/* The size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 4
+
+/* The size of `long long', as computed by sizeof. */
+#define SIZEOF_LONG_LONG 8
+
+/* The size of `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Version number of package */
+#define VERSION "1.4.13-stable"
+
+/* Define to appropriate substitue if compiler doesnt have __func__ */
+/* #undef __func__ */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef pid_t */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* Define to unsigned int if you dont have it */
+/* #undef socklen_t */
diff --git a/chromium/base/third_party/libevent/solaris/event-config.h b/chromium/base/third_party/libevent/solaris/event-config.h
new file mode 100644
index 00000000000..afabe2f467e
--- /dev/null
+++ b/chromium/base/third_party/libevent/solaris/event-config.h
@@ -0,0 +1,284 @@
+/* event-config.h
+ * Generated by autoconf; post-processed by libevent.
+ * Do not edit this file.
+ * Do not rely on macros in this file existing in later versions.
+ */
+#ifndef _EVENT_CONFIG_H_
+#define _EVENT_CONFIG_H_
+/* config.h. Generated from config.h.in by configure. */
+/* config.h.in. Generated from configure.in by autoheader. */
+
+/* Define if clock_gettime is available in libc */
+#define _EVENT_DNS_USE_CPU_CLOCK_FOR_ID 1
+
+/* Define is no secure id variant is available */
+/* #undef _EVENT_DNS_USE_GETTIMEOFDAY_FOR_ID */
+
+/* Define to 1 if you have the `clock_gettime' function. */
+#define _EVENT_HAVE_CLOCK_GETTIME 1
+
+/* Define if /dev/poll is available */
+#define _EVENT_HAVE_DEVPOLL 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define _EVENT_HAVE_DLFCN_H 1
+
+/* Define if your system supports the epoll system calls */
+/* #undef _EVENT_HAVE_EPOLL */
+
+/* Define to 1 if you have the `epoll_ctl' function. */
+/* #undef _EVENT_HAVE_EPOLL_CTL */
+
+/* Define if your system supports event ports */
+#define _EVENT_HAVE_EVENT_PORTS 1
+
+/* Define to 1 if you have the `fcntl' function. */
+#define _EVENT_HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define _EVENT_HAVE_FCNTL_H 1
+
+/* Define to 1 if the system has the type `fd_mask'. */
+#define _EVENT_HAVE_FD_MASK 1
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#define _EVENT_HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `getegid' function. */
+#define _EVENT_HAVE_GETEGID 1
+
+/* Define to 1 if you have the `geteuid' function. */
+#define _EVENT_HAVE_GETEUID 1
+
+/* Define to 1 if you have the `getnameinfo' function. */
+#define _EVENT_HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define _EVENT_HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the `inet_ntop' function. */
+#define _EVENT_HAVE_INET_NTOP 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define _EVENT_HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `issetugid' function. */
+#define _EVENT_HAVE_ISSETUGID 1
+
+/* Define to 1 if you have the `kqueue' function. */
+/* #undef _EVENT_HAVE_KQUEUE */
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+#define _EVENT_HAVE_LIBNSL 1
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+#define _EVENT_HAVE_LIBRESOLV 1
+
+/* Define to 1 if you have the `rt' library (-lrt). */
+#define _EVENT_HAVE_LIBRT 1
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+#define _EVENT_HAVE_LIBSOCKET 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define _EVENT_HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <netinet/in6.h> header file. */
+/* #undef _EVENT_HAVE_NETINET_IN6_H */
+
+/* Define to 1 if you have the `poll' function. */
+#define _EVENT_HAVE_POLL 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define _EVENT_HAVE_POLL_H 1
+
+/* Define to 1 if you have the `port_create' function. */
+#define _EVENT_HAVE_PORT_CREATE 1
+
+/* Define to 1 if you have the <port.h> header file. */
+#define _EVENT_HAVE_PORT_H 1
+
+/* Define to 1 if you have the `select' function. */
+#define _EVENT_HAVE_SELECT 1
+
+/* Define if F_SETFD is defined in <fcntl.h> */
+#define _EVENT_HAVE_SETFD 1
+
+/* Define to 1 if you have the `sigaction' function. */
+#define _EVENT_HAVE_SIGACTION 1
+
+/* Define to 1 if you have the `signal' function. */
+#define _EVENT_HAVE_SIGNAL 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define _EVENT_HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#define _EVENT_HAVE_STDARG_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define _EVENT_HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define _EVENT_HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define _EVENT_HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define _EVENT_HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+#define _EVENT_HAVE_STRLCPY 1
+
+/* Define to 1 if you have the `strsep' function. */
+#define _EVENT_HAVE_STRSEP 1
+
+/* Define to 1 if you have the `strtok_r' function. */
+#define _EVENT_HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the `strtoll' function. */
+#define _EVENT_HAVE_STRTOLL 1
+
+/* Define to 1 if the system has the type `struct in6_addr'. */
+#define _EVENT_HAVE_STRUCT_IN6_ADDR 1
+
+/* Define to 1 if you have the <sys/devpoll.h> header file. */
+#define _EVENT_HAVE_SYS_DEVPOLL_H 1
+
+/* Define to 1 if you have the <sys/epoll.h> header file. */
+/* #undef _EVENT_HAVE_SYS_EPOLL_H */
+
+/* Define to 1 if you have the <sys/event.h> header file. */
+/* #undef _EVENT_HAVE_SYS_EVENT_H */
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define _EVENT_HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define _EVENT_HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/queue.h> header file. */
+#define _EVENT_HAVE_SYS_QUEUE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define _EVENT_HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define _EVENT_HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define _EVENT_HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define _EVENT_HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define _EVENT_HAVE_SYS_TYPES_H 1
+
+/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
+#define _EVENT_HAVE_TAILQFOREACH 1
+
+/* Define if timeradd is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERADD 1
+
+/* Define if timerclear is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERCLEAR 1
+
+/* Define if timercmp is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERCMP 1
+
+/* Define if timerisset is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERISSET 1
+
+/* Define to 1 if the system has the type `uint16_t'. */
+#define _EVENT_HAVE_UINT16_T 1
+
+/* Define to 1 if the system has the type `uint32_t'. */
+#define _EVENT_HAVE_UINT32_T 1
+
+/* Define to 1 if the system has the type `uint64_t'. */
+#define _EVENT_HAVE_UINT64_T 1
+
+/* Define to 1 if the system has the type `uint8_t'. */
+#define _EVENT_HAVE_UINT8_T 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define _EVENT_HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `vasprintf' function. */
+#define _EVENT_HAVE_VASPRINTF 1
+
+/* Define if kqueue works correctly with pipes */
+/* #undef _EVENT_HAVE_WORKING_KQUEUE */
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+#define _EVENT_LT_OBJDIR ".libs/"
+
+/* Numeric representation of the version */
+#define _EVENT_NUMERIC_VERSION 0x01040f00
+
+/* Name of package */
+#define _EVENT_PACKAGE "libevent"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define _EVENT_PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define _EVENT_PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define _EVENT_PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define _EVENT_PACKAGE_TARNAME ""
+
+/* Define to the home page for this package. */
+#define _EVENT_PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define _EVENT_PACKAGE_VERSION ""
+
+/* The size of `int', as computed by sizeof. */
+#define _EVENT_SIZEOF_INT 4
+
+/* The size of `long', as computed by sizeof. */
+#define _EVENT_SIZEOF_LONG 4
+
+/* The size of `long long', as computed by sizeof. */
+#define _EVENT_SIZEOF_LONG_LONG 8
+
+/* The size of `short', as computed by sizeof. */
+#define _EVENT_SIZEOF_SHORT 2
+
+/* Define to 1 if you have the ANSI C header files. */
+#define _EVENT_STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define _EVENT_TIME_WITH_SYS_TIME 1
+
+/* Version number of package */
+#define _EVENT_VERSION "1.4.15"
+
+/* Define to appropriate substitue if compiler doesnt have __func__ */
+/* #undef _EVENT___func__ */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef _EVENT_const */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef _EVENT___cplusplus
+/* #undef _EVENT_inline */
+#endif
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef _EVENT_pid_t */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef _EVENT_size_t */
+
+/* Define to unsigned int if you dont have it */
+/* #undef _EVENT_socklen_t */
+#endif
diff --git a/chromium/base/third_party/libevent/stamp-h.in b/chromium/base/third_party/libevent/stamp-h.in
new file mode 100644
index 00000000000..9788f70238c
--- /dev/null
+++ b/chromium/base/third_party/libevent/stamp-h.in
@@ -0,0 +1 @@
+timestamp
diff --git a/chromium/base/third_party/libevent/strlcpy-internal.h b/chromium/base/third_party/libevent/strlcpy-internal.h
new file mode 100644
index 00000000000..22b5f61d45e
--- /dev/null
+++ b/chromium/base/third_party/libevent/strlcpy-internal.h
@@ -0,0 +1,23 @@
+#ifndef _STRLCPY_INTERNAL_H_
+#define _STRLCPY_INTERNAL_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifndef HAVE_STRLCPY
+#include <string.h>
+size_t _event_strlcpy(char *dst, const char *src, size_t siz);
+#define strlcpy _event_strlcpy
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/chromium/base/third_party/libevent/strlcpy.c b/chromium/base/third_party/libevent/strlcpy.c
new file mode 100644
index 00000000000..5d194527c8c
--- /dev/null
+++ b/chromium/base/third_party/libevent/strlcpy.c
@@ -0,0 +1,76 @@
+/* $OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $ */
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *rcsid = "$OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifndef HAVE_STRLCPY
+#include "strlcpy-internal.h"
+
+/*
+ * Copy src to string dst of size siz. At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+size_t
+_event_strlcpy(dst, src, siz)
+ char *dst;
+ const char *src;
+ size_t siz;
+{
+ register char *d = dst;
+ register const char *s = src;
+ register size_t n = siz;
+
+ /* Copy as many bytes as will fit */
+ if (n != 0 && --n != 0) {
+ do {
+ if ((*d++ = *s++) == 0)
+ break;
+ } while (--n != 0);
+ }
+
+ /* Not enough room in dst, add NUL and traverse rest of src */
+ if (n == 0) {
+ if (siz != 0)
+ *d = '\0'; /* NUL-terminate dst */
+ while (*s++)
+ ;
+ }
+
+ return(s - src - 1); /* count does not include NUL */
+}
+#endif
diff --git a/chromium/base/third_party/libevent/whatsnew-14.txt b/chromium/base/third_party/libevent/whatsnew-14.txt
new file mode 100644
index 00000000000..769dda78194
--- /dev/null
+++ b/chromium/base/third_party/libevent/whatsnew-14.txt
@@ -0,0 +1,167 @@
+What's New In Libevent 1.4:
+
+0. About this document
+
+ This document describes the key differences between Libevent 1.3 and
+ Libevent 1.4, from a user's point of view. It was most recently
+ updated based on features from libevent 1.4.2-rc.
+
+1. Packaging Issues.
+
+1.1. The great library division.
+
+ The libevent source now builds two libraries: libevent_core and
+ libevent_extra. The libevent_core library includes event loops,
+ timers, buffer code, and various small compatibility functions. The
+ libevent_extra library includes code for HTTP, DNS, RPC, and so on.
+ Thus, if you're writing software that only uses libevent's event
+ loop, you should link against only the libevent_core library,
+ whereas if you're writing software that uses libevent's protocol
+ support as well, you need to link libevent_extra as well.
+
+ For backward compatibility, libevent also builds a library called
+ "libevent" that includes everything.
+
+1.2. The event-config.h header
+
+ Libevent configure script now builds two headers from its configure
+ script: config.h (which it uses internally) and event-config.h
+ (which it installs as a header file). All of the macros in
+ event-config.h are modified so that they're safe to include in other
+ projects. This allows libevent's header files (like event.h and
+ evutil.h) information about platform configuration.
+
+ What does this mean for you? As of 1.4.x, it should never be
+ necessary to include extra files or define extra types before you
+ include event.h (or any other libevent header); event.h can now look
+ at the information in event-config.h and figure out what it needs to
+ include.
+
+1.3. Documentation
+
+ Libevent now includes better doxygen documentation. It's not
+ perfect or complete, though; if you find a mistake, please let us
+ know.
+
+1.4. Libtool usage
+
+ We now use libtool's library versioning support correctly. If we
+ don't mess this up, it means that binaries linked against old
+ version of libevent should continue working when we make changes to
+ libevent that don't break backward compatibility.
+
+1.5. Portability
+
+ Libevent now builds with MSVC again. We've only tested it with MSVC
+ 2005, and the project files might not be right. Please let us know
+ if you run into any issues.
+
+ Libevent now builds on platforms where /bin/sh is not bash.
+
+ Libevent's regression test no longer requires Python to be
+ installed.
+
+2. New and Improved APIs:
+
+ (This list includes functions that are new, functions whose behavior
+ has changed, and functions that were included in previous releases
+ but which never actually worked before.)
+
+2.1. Utility functions are defined in evutil.h
+
+ Libevent now exposes a small set of functions for cross-platform
+ network programming in evutil.h, on the theory that they've been
+ useful enough to us that other people may likely want to use them
+ too. These are mainly workarounds for Windows issues for now: they
+ include evutil_socketpair (to fake socketpair on platforms that
+ don't have it) and evutil_make_socket_nonblocking (to make a socket
+ nonblocking in a cross-platform way. See the header for more
+ information.
+
+2.2. In the libevent core.
+
+ The event_base_free() function now works. Previously, it would
+ crash with an assertion failure if there were events pending on a
+ base. Now, it simply deletes all the pending events and frees the
+ base. Be careful -- this might leak fds and memory associated with
+ the old events. To avoid leaks, you should still remove all the
+ events and free their resources before you delete the base.
+
+ Libevent should now work properly with fork(). Just call
+ event_reinit() on your event base after the fork call, and it should
+ work okay. Please let us know about any bugs you find.
+
+ There's a new event_base_new() function that acts just like
+ event_init(), but does not replace the default base. If you are
+ using multiple event bases in your code, you should just use
+ event_base_new() instead of event_init(), to avoid accidental bugs.
+
+ There's new event_loopbreak() function to make a current event loop
+ stop exiting and return. Unlike event_loopexit, it stops subsequent
+ pending events from getting executed. This behavior is useful for
+ scripting languages to implement exceptions from inside callbacks.
+
+ There's a new event_base_get_method() function, for use in place of
+ event_get_method() in multi-base applications.
+
+2.3. New in HTTP.
+
+ There's an evhttp_connection_set_local_address() function you can
+ use to set the local address of an HTTP connection.
+
+ HTTP/1.1 chunking now correctly ends chunks with '\r\n'.
+
+2.4. New in DNS
+
+ Instead of picking your method for generating DNS transaction IDs at
+ startup, you can use evdns_set_transaction_id() to provide a
+ transaction ID function at runtime.
+
+ The "class" field in evdns_server_request is now renamed to
+ dns_question_class, so that it won't break compilation under C++.
+ This uses some preprocessor hacks so that C code using the old name
+ won't break. Eventually, the old name will be deprecated entirely;
+ please don't use it.
+
+2.5. New in RPC
+
+ There are now hooks on RPC input and output; can be used to
+ implement RPC independent processing such as compression or
+ authentication.
+
+ RPC tags can now be up to 32 bits. This is wire-compatible, but
+ changes some of the types in the APIs. Please let us know if this
+ is problematic for you.
+
+3. Big bugfixes
+
+ We've done a lot, with help from users on different platforms, to
+ make the different backends behave more similarly with respect to
+ signals and timeouts. The kqueue and solaris backends were the big
+ offenders previously, but they should be better now. Windows should
+ be better too, though it's likely that problems remain there.
+
+ The libevent headers (though not the source files!) should now build
+ cleanly on C++.
+
+ (For more bugfixes, see the ChangeLog file. These are only the
+ biggies.)
+
+4. Big performance improvements
+
+ Libevent now uses a min-heap rather than a red-black tree to track
+ timeouts. This means that finding the next timeout to fire is now
+ O(1) instead of (lg n).
+
+ The win32 select-based backend now uses a red-black tree to map
+ SOCKET handles to event structures. This changes the performance
+ characteristics of the event loop on win32 from O(n^2) to O(n lg n).
+ Not perfect, but better.
+
+5. Removed code and features
+
+ The rtsig backend is now removed. It hasn't even compiled for a
+ while, and nobody seemed to miss it very much. All the platforms
+ that have rtsig seem to have a better option instead these days.
+ Please let us know if rtsig was crucial for you.
+
diff --git a/chromium/base/third_party/nspr/prtime.cc b/chromium/base/third_party/nspr/prtime.cc
index a7c5a3a9496..177cc90243f 100644
--- a/chromium/base/third_party/nspr/prtime.cc
+++ b/chromium/base/third_party/nspr/prtime.cc
@@ -65,6 +65,8 @@
* Unit tests are in base/time/pr_time_unittest.cc.
*/
+#include <limits.h>
+
#include "base/logging.h"
#include "base/third_party/nspr/prtime.h"
#include "build/build_config.h"
diff --git a/chromium/base/third_party/symbolize/README.chromium b/chromium/base/third_party/symbolize/README.chromium
index de92794c812..64a62472245 100644
--- a/chromium/base/third_party/symbolize/README.chromium
+++ b/chromium/base/third_party/symbolize/README.chromium
@@ -1,9 +1,10 @@
Name: google-glog's symbolization library
-URL: http://code.google.com/p/google-glog/
+URL: https://github.com/google/glog
License: BSD
The following files are copied AS-IS from:
http://code.google.com/p/google-glog/source/browse/#svn/trunk/src (r141)
+https://github.com/google/glog/tree/a5ffa884137f7687d0393ccba22557d583654a25
- demangle.cc
- demangle.h
diff --git a/chromium/base/third_party/symbolize/symbolize.cc b/chromium/base/third_party/symbolize/symbolize.cc
index f4861dfe523..db82b04d4df 100644
--- a/chromium/base/third_party/symbolize/symbolize.cc
+++ b/chromium/base/third_party/symbolize/symbolize.cc
@@ -773,7 +773,7 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
// Run the call back if it's installed.
// Note: relocation (and much of the rest of this code) will be
// wrong for prelinked shared libraries and PIE executables.
- uint64 relocation = (elf_type == ET_DYN) ? start_address : 0;
+ uint64_t relocation = (elf_type == ET_DYN) ? start_address : 0;
int num_bytes_written = g_symbolize_callback(wrapped_object_fd.get(),
pc, out, out_size,
relocation);
diff --git a/chromium/base/third_party/symbolize/symbolize.h b/chromium/base/third_party/symbolize/symbolize.h
index f617184249c..aeb2fe3c665 100644
--- a/chromium/base/third_party/symbolize/symbolize.h
+++ b/chromium/base/third_party/symbolize/symbolize.h
@@ -117,7 +117,7 @@ _START_GOOGLE_NAMESPACE_
// and return the size of the output written. On error, the callback
// function should return -1.
typedef int (*SymbolizeCallback)(int fd, void *pc, char *out, size_t out_size,
- uint64 relocation);
+ uint64_t relocation);
void InstallSymbolizeCallback(SymbolizeCallback callback);
// Installs a callback function, which will be called instead of
diff --git a/chromium/base/third_party/symbolize/utilities.h b/chromium/base/third_party/symbolize/utilities.h
index 0bed526634d..3971145a6a4 100644
--- a/chromium/base/third_party/symbolize/utilities.h
+++ b/chromium/base/third_party/symbolize/utilities.h
@@ -6,6 +6,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-typedef uint64_t uint64;
+typedef uint64_t uint64_t;
#define HAVE_SYMBOLIZE 1
#define ATTRIBUTE_NOINLINE __attribute__ ((noinline))
diff --git a/chromium/base/thread_task_runner_handle.h b/chromium/base/thread_task_runner_handle.h
index 238435f978e..197669ed88b 100644
--- a/chromium/base/thread_task_runner_handle.h
+++ b/chromium/base/thread_task_runner_handle.h
@@ -16,6 +16,7 @@ class SingleThreadTaskRunner;
// in thread-local storage. Callers can then retrieve the TaskRunner
// for the current thread by calling ThreadTaskRunnerHandle::Get().
// At most one TaskRunner may be bound to each thread at a time.
+// Prefer SequenceTaskRunnerHandle to this unless thread affinity is required.
class BASE_EXPORT ThreadTaskRunnerHandle {
public:
// Gets the SingleThreadTaskRunner for the current thread.
diff --git a/chromium/base/threading/non_thread_safe_unittest.cc b/chromium/base/threading/non_thread_safe_unittest.cc
index 955c939d92d..2a27c3fb88e 100644
--- a/chromium/base/threading/non_thread_safe_unittest.cc
+++ b/chromium/base/threading/non_thread_safe_unittest.cc
@@ -2,8 +2,8 @@
// 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/logging.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/threading/non_thread_safe.h"
#include "base/threading/simple_thread.h"
diff --git a/chromium/base/threading/platform_thread.h b/chromium/base/threading/platform_thread.h
index 6b52cc4eb63..e2b09bcb5bf 100644
--- a/chromium/base/threading/platform_thread.h
+++ b/chromium/base/threading/platform_thread.h
@@ -9,8 +9,10 @@
#ifndef BASE_THREADING_PLATFORM_THREAD_H_
#define BASE_THREADING_PLATFORM_THREAD_H_
+#include <stddef.h>
+
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/time/time.h"
#include "build/build_config.h"
diff --git a/chromium/base/threading/platform_thread_android.cc b/chromium/base/threading/platform_thread_android.cc
index b6bea49b36c..11a6ba8dd4f 100644
--- a/chromium/base/threading/platform_thread_android.cc
+++ b/chromium/base/threading/platform_thread_android.cc
@@ -5,6 +5,7 @@
#include "base/threading/platform_thread.h"
#include <errno.h>
+#include <stddef.h>
#include <sys/prctl.h>
#include <sys/resource.h>
#include <sys/types.h>
diff --git a/chromium/base/threading/platform_thread_freebsd.cc b/chromium/base/threading/platform_thread_freebsd.cc
index e29e865e63b..bce1ccf45df 100644
--- a/chromium/base/threading/platform_thread_freebsd.cc
+++ b/chromium/base/threading/platform_thread_freebsd.cc
@@ -6,15 +6,17 @@
#include <errno.h>
#include <sched.h>
+#include <stddef.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 "build/build_config.h"
#if !defined(OS_NACL)
#include <pthread.h>
-#include <sys/prctl.h>
#include <sys/types.h>
#include <unistd.h>
#endif
@@ -34,7 +36,7 @@ const ThreadPriorityToNiceValuePair kThreadPriorityToNiceValueMap[4] = {
{ThreadPriority::NORMAL, 0},
{ThreadPriority::DISPLAY, -6},
{ThreadPriority::REALTIME_AUDIO, -10},
-}
+};
bool SetCurrentThreadPriorityForPlatform(ThreadPriority priority) {
#if !defined(OS_NACL)
diff --git a/chromium/base/threading/platform_thread_linux.cc b/chromium/base/threading/platform_thread_linux.cc
index 48cf7443f7d..4057ede947e 100644
--- a/chromium/base/threading/platform_thread_linux.cc
+++ b/chromium/base/threading/platform_thread_linux.cc
@@ -6,12 +6,14 @@
#include <errno.h>
#include <sched.h>
+#include <stddef.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 "build/build_config.h"
#if !defined(OS_NACL)
#include <pthread.h>
diff --git a/chromium/base/threading/platform_thread_mac.mm b/chromium/base/threading/platform_thread_mac.mm
index 1ecbcd6ad91..df11f852e56 100644
--- a/chromium/base/threading/platform_thread_mac.mm
+++ b/chromium/base/threading/platform_thread_mac.mm
@@ -8,6 +8,7 @@
#include <mach/mach.h>
#include <mach/mach_time.h>
#include <mach/thread_policy.h>
+#include <stddef.h>
#include <sys/resource.h>
#include <algorithm>
@@ -17,6 +18,7 @@
#include "base/mac/mach_logging.h"
#include "base/threading/thread_id_name_manager.h"
#include "base/tracked_objects.h"
+#include "build/build_config.h"
namespace base {
diff --git a/chromium/base/threading/platform_thread_posix.cc b/chromium/base/threading/platform_thread_posix.cc
index 0adb92dbce5..39a007316f7 100644
--- a/chromium/base/threading/platform_thread_posix.cc
+++ b/chromium/base/threading/platform_thread_posix.cc
@@ -7,6 +7,8 @@
#include <errno.h>
#include <pthread.h>
#include <sched.h>
+#include <stddef.h>
+#include <stdint.h>
#include <sys/resource.h>
#include <sys/time.h>
@@ -16,6 +18,7 @@
#include "base/threading/platform_thread_internal_posix.h"
#include "base/threading/thread_id_name_manager.h"
#include "base/threading/thread_restrictions.h"
+#include "build/build_config.h"
#if defined(OS_LINUX)
#include <sys/syscall.h>
@@ -136,9 +139,9 @@ PlatformThreadId PlatformThread::CurrentId() {
return pthread_self();
#elif defined(OS_NACL) && !defined(__GLIBC__)
// Pointers are 32-bits in NaCl.
- return reinterpret_cast<int32>(pthread_self());
+ return reinterpret_cast<int32_t>(pthread_self());
#elif defined(OS_POSIX)
- return reinterpret_cast<int64>(pthread_self());
+ return reinterpret_cast<int64_t>(pthread_self());
#endif
}
diff --git a/chromium/base/threading/platform_thread_unittest.cc b/chromium/base/threading/platform_thread_unittest.cc
index 1ac08a77ae2..52f8d1ba6f3 100644
--- a/chromium/base/threading/platform_thread_unittest.cc
+++ b/chromium/base/threading/platform_thread_unittest.cc
@@ -2,10 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
+
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/platform_thread.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#if defined(OS_POSIX)
diff --git a/chromium/base/threading/platform_thread_win.cc b/chromium/base/threading/platform_thread_win.cc
index 25973bcada9..d5bd9bed08e 100644
--- a/chromium/base/threading/platform_thread_win.cc
+++ b/chromium/base/threading/platform_thread_win.cc
@@ -4,6 +4,8 @@
#include "base/threading/platform_thread.h"
+#include <stddef.h>
+
#include "base/debug/alias.h"
#include "base/debug/profiler.h"
#include "base/logging.h"
diff --git a/chromium/base/threading/post_task_and_reply_impl.cc b/chromium/base/threading/post_task_and_reply_impl.cc
index f3e88abf608..80ca52009f2 100644
--- a/chromium/base/threading/post_task_and_reply_impl.cc
+++ b/chromium/base/threading/post_task_and_reply_impl.cc
@@ -75,6 +75,9 @@ bool PostTaskAndReplyImpl::PostTaskAndReply(
const tracked_objects::Location& from_here,
const Closure& task,
const Closure& reply) {
+ // TODO(tzik): Use DCHECK here once the crash is gone. http://crbug.com/541319
+ CHECK(!task.is_null()) << from_here.ToString();
+ CHECK(!reply.is_null()) << from_here.ToString();
PostTaskAndReplyRelay* relay =
new PostTaskAndReplyRelay(from_here, task, reply);
if (!PostTask(from_here, Bind(&PostTaskAndReplyRelay::Run,
diff --git a/chromium/base/threading/sequenced_task_runner_handle.cc b/chromium/base/threading/sequenced_task_runner_handle.cc
new file mode 100644
index 00000000000..081f11f78b3
--- /dev/null
+++ b/chromium/base/threading/sequenced_task_runner_handle.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/threading/sequenced_task_runner_handle.h"
+
+#include "base/sequenced_task_runner.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/sequenced_worker_pool.h"
+
+namespace base {
+
+// static
+scoped_refptr<SequencedTaskRunner> SequencedTaskRunnerHandle::Get() {
+ // Return the SequencedTaskRunner if found or the SingleThreadedTaskRunner for
+ // the current thread otherwise.
+ scoped_refptr<base::SequencedTaskRunner> task_runner =
+ SequencedWorkerPool::GetSequencedTaskRunnerForCurrentThread();
+ if (task_runner)
+ return task_runner;
+
+ return base::ThreadTaskRunnerHandle::Get();
+}
+
+// static
+bool SequencedTaskRunnerHandle::IsSet() {
+ return SequencedWorkerPool::GetWorkerPoolForCurrentThread() ||
+ base::ThreadTaskRunnerHandle::IsSet();
+}
+
+} // namespace base
diff --git a/chromium/base/threading/sequenced_task_runner_handle.h b/chromium/base/threading/sequenced_task_runner_handle.h
new file mode 100644
index 00000000000..7084ec4bb9b
--- /dev/null
+++ b/chromium/base/threading/sequenced_task_runner_handle.h
@@ -0,0 +1,37 @@
+// 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_SEQUENCED_TASK_RUNNER_HANDLE_H_
+#define BASE_THREADING_SEQUENCED_TASK_RUNNER_HANDLE_H_
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+
+namespace base {
+
+class SequencedTaskRunner;
+
+class BASE_EXPORT SequencedTaskRunnerHandle {
+ public:
+ // Returns a SequencedTaskRunner which guarantees that posted tasks will only
+ // run after the current task is finished and will satisfy a SequenceChecker.
+ // It should only be called if IsSet() returns true (see the comment there for
+ // the requirements).
+ static scoped_refptr<SequencedTaskRunner> Get();
+
+ // Returns true if one of the following conditions is fulfilled:
+ // a) The current thread has a ThreadTaskRunnerHandle (which includes any
+ // thread that has a MessageLoop associated with it), or
+ // b) The current thread is a worker thread belonging to a
+ // SequencedWorkerPool.
+ static bool IsSet();
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(SequencedTaskRunnerHandle);
+};
+
+} // namespace base
+
+#endif // BASE_THREADING_SEQUENCED_TASK_RUNNER_HANDLE_H_
diff --git a/chromium/base/threading/sequenced_task_runner_handle_unittest.cc b/chromium/base/threading/sequenced_task_runner_handle_unittest.cc
new file mode 100644
index 00000000000..1e624f4dce9
--- /dev/null
+++ b/chromium/base/threading/sequenced_task_runner_handle_unittest.cc
@@ -0,0 +1,102 @@
+// 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/callback.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/run_loop.h"
+#include "base/sequence_checker_impl.h"
+#include "base/sequenced_task_runner.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/test/sequenced_worker_pool_owner.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "base/threading/simple_thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace {
+
+class SequencedTaskRunnerHandleTest : public ::testing::Test {
+ protected:
+ static void VerifyCurrentSequencedTaskRunner(const Closure& callback) {
+ ASSERT_TRUE(SequencedTaskRunnerHandle::IsSet());
+ scoped_refptr<SequencedTaskRunner> task_runner =
+ SequencedTaskRunnerHandle::Get();
+ ASSERT_TRUE(task_runner);
+
+ // Use SequenceCheckerImpl to make sure it's not a no-op in Release builds.
+ scoped_ptr<SequenceCheckerImpl> sequence_checker(new SequenceCheckerImpl);
+ task_runner->PostTask(
+ FROM_HERE,
+ base::Bind(&SequencedTaskRunnerHandleTest::CheckValidSequence,
+ base::Passed(&sequence_checker), callback));
+ }
+
+ private:
+ static void CheckValidSequence(
+ scoped_ptr<SequenceCheckerImpl> sequence_checker,
+ const Closure& callback) {
+ EXPECT_TRUE(sequence_checker->CalledOnValidSequencedThread());
+ callback.Run();
+ }
+
+ MessageLoop message_loop_;
+};
+
+TEST_F(SequencedTaskRunnerHandleTest, FromMessageLoop) {
+ RunLoop run_loop;
+ VerifyCurrentSequencedTaskRunner(run_loop.QuitClosure());
+ run_loop.Run();
+}
+
+TEST_F(SequencedTaskRunnerHandleTest, FromSequencedWorkerPoolTask) {
+ // Wrap the SequencedWorkerPool to avoid leaks due to its asynchronous
+ // destruction.
+ SequencedWorkerPoolOwner owner(3, "Test");
+ WaitableEvent event(false, false);
+ owner.pool()->PostSequencedWorkerTask(
+ owner.pool()->GetSequenceToken(), FROM_HERE,
+ base::Bind(
+ &SequencedTaskRunnerHandleTest::VerifyCurrentSequencedTaskRunner,
+ base::Bind(&WaitableEvent::Signal, base::Unretained(&event))));
+ event.Wait();
+ owner.pool()->Shutdown();
+}
+
+TEST_F(SequencedTaskRunnerHandleTest, FromUnsequencedTask) {
+ // Wrap the SequencedWorkerPool to avoid leaks due to its asynchronous
+ // destruction.
+ SequencedWorkerPoolOwner owner(3, "Test");
+ WaitableEvent event(false, false);
+ owner.pool()->PostWorkerTask(
+ FROM_HERE,
+ base::Bind(
+ &SequencedTaskRunnerHandleTest::VerifyCurrentSequencedTaskRunner,
+ base::Bind(&WaitableEvent::Signal, base::Unretained(&event))));
+ event.Wait();
+}
+
+class ThreadRunner : public DelegateSimpleThread::Delegate {
+ public:
+ void Run() override {
+ ASSERT_FALSE(SequencedTaskRunnerHandle::IsSet());
+ }
+
+ private:
+ Closure callback_;
+};
+
+TEST_F(SequencedTaskRunnerHandleTest, FromSimpleThread) {
+ ThreadRunner thread_runner;
+ DelegateSimpleThread thread(&thread_runner, "Background thread");
+ thread.Start();
+ thread.Join();
+}
+
+} // namespace
+} // namespace base
diff --git a/chromium/base/threading/sequenced_worker_pool.cc b/chromium/base/threading/sequenced_worker_pool.cc
index 54a6bc8245d..3cc50f404c2 100644
--- a/chromium/base/threading/sequenced_worker_pool.cc
+++ b/chromium/base/threading/sequenced_worker_pool.cc
@@ -4,6 +4,8 @@
#include "base/threading/sequenced_worker_pool.h"
+#include <stdint.h>
+
#include <list>
#include <map>
#include <set>
@@ -16,6 +18,7 @@
#include "base/critical_closure.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/linked_ptr.h"
#include "base/stl_util.h"
#include "base/strings/stringprintf.h"
@@ -29,6 +32,7 @@
#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
#include "base/tracked_objects.h"
+#include "build/build_config.h"
#if defined(OS_MACOSX)
#include "base/mac/scoped_nsautorelease_pool.h"
@@ -62,7 +66,7 @@ struct SequencedTask : public TrackingInfo {
int sequence_token_id;
int trace_id;
- int64 sequence_task_number;
+ int64_t sequence_task_number;
SequencedWorkerPool::WorkerShutdown shutdown_behavior;
tracked_objects::Location posted_from;
Closure task;
@@ -213,16 +217,11 @@ bool SequencedWorkerPoolSequencedTaskRunner::PostNonNestableDelayedTask(
// Create a process-wide unique ID to represent this task in trace events. This
// will be mangled with a Process ID hash to reduce the likelyhood of colliding
// with MessageLoop pointers on other processes.
-uint64 GetTaskTraceID(const SequencedTask& task,
- void* pool) {
- return (static_cast<uint64>(task.trace_id) << 32) |
- static_cast<uint64>(reinterpret_cast<intptr_t>(pool));
+uint64_t GetTaskTraceID(const SequencedTask& task, void* pool) {
+ return (static_cast<uint64_t>(task.trace_id) << 32) |
+ static_cast<uint64_t>(reinterpret_cast<intptr_t>(pool));
}
-base::LazyInstance<base::ThreadLocalPointer<
- SequencedWorkerPool::SequenceToken> >::Leaky g_lazy_tls_ptr =
- LAZY_INSTANCE_INITIALIZER;
-
} // namespace
// Worker ---------------------------------------------------------------------
@@ -239,6 +238,9 @@ class SequencedWorkerPool::Worker : public SimpleThread {
// SimpleThread implementation. This actually runs the background thread.
void Run() override;
+ // Gets the worker for the current thread out of thread-local storage.
+ static Worker* GetForCurrentThread();
+
// 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,
@@ -264,7 +266,14 @@ class SequencedWorkerPool::Worker : public SimpleThread {
return task_shutdown_behavior_;
}
+ scoped_refptr<SequencedWorkerPool> worker_pool() const {
+ return worker_pool_;
+ }
+
private:
+ static LazyInstance<ThreadLocalPointer<SequencedWorkerPool::Worker>>::Leaky
+ lazy_tls_ptr_;
+
scoped_refptr<SequencedWorkerPool> worker_pool_;
// The sequence token of the task being processed. Only valid when
// is_processing_task_ is true.
@@ -290,7 +299,7 @@ class SequencedWorkerPool::Inner {
~Inner();
- SequenceToken GetSequenceToken();
+ static SequenceToken GetSequenceToken();
SequenceToken GetNamedSequenceToken(const std::string& name);
@@ -308,6 +317,11 @@ class SequencedWorkerPool::Inner {
bool IsRunningSequenceOnCurrentThread(SequenceToken sequence_token) const;
+ bool IsRunningSequence(SequenceToken sequence_token) const;
+
+ void SetRunningTaskInfoForCurrentThread(SequenceToken sequence_token,
+ WorkerShutdown shutdown_behavior);
+
void CleanupForTesting();
void SignalHasWorkForTesting();
@@ -341,7 +355,7 @@ class SequencedWorkerPool::Inner {
int LockedGetNamedTokenID(const std::string& name);
// Called from within the lock, this returns the next sequence task number.
- int64 LockedGetNextSequenceTaskNumber();
+ int64_t LockedGetNextSequenceTaskNumber();
// Gets new task. There are 3 cases depending on the return value:
//
@@ -457,7 +471,7 @@ class SequencedWorkerPool::Inner {
PendingTaskSet pending_tasks_;
// The next sequence number for a new sequenced task.
- int64 next_sequence_task_number_;
+ int64_t next_sequence_task_number_;
// Number of tasks in the pending_tasks_ list that are marked as blocking
// shutdown.
@@ -508,9 +522,10 @@ void SequencedWorkerPool::Worker::Run() {
win::ScopedCOMInitializer com_initializer;
#endif
- // Store a pointer to the running sequence in thread local storage for
- // static function access.
- g_lazy_tls_ptr.Get().Set(&task_sequence_token_);
+ // Store a pointer to this worker in thread local storage for static function
+ // access.
+ DCHECK(!lazy_tls_ptr_.Get().Get());
+ lazy_tls_ptr_.Get().Set(this);
// 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
@@ -519,9 +534,23 @@ void SequencedWorkerPool::Worker::Run() {
// send thread-specific information easily to the thread loop.
worker_pool_->inner_->ThreadLoop(this);
// Release our cyclic reference once we're done.
- worker_pool_ = NULL;
+ worker_pool_ = nullptr;
}
+// static
+SequencedWorkerPool::Worker*
+SequencedWorkerPool::Worker::GetForCurrentThread() {
+ // Don't construct lazy instance on check.
+ if (lazy_tls_ptr_ == nullptr)
+ return nullptr;
+
+ return lazy_tls_ptr_.Get().Get();
+}
+
+// static
+LazyInstance<ThreadLocalPointer<SequencedWorkerPool::Worker>>::Leaky
+ SequencedWorkerPool::Worker::lazy_tls_ptr_ = LAZY_INSTANCE_INITIALIZER;
+
// Inner definitions ---------------------------------------------------------
SequencedWorkerPool::Inner::Inner(
@@ -562,6 +591,7 @@ SequencedWorkerPool::Inner::~Inner() {
testing_observer_->OnDestruct();
}
+// static
SequencedWorkerPool::SequenceToken
SequencedWorkerPool::Inner::GetSequenceToken() {
// Need to add one because StaticAtomicSequenceNumber starts at zero, which
@@ -662,6 +692,28 @@ bool SequencedWorkerPool::Inner::IsRunningSequenceOnCurrentThread(
sequence_token.Equals(found->second->task_sequence_token());
}
+bool SequencedWorkerPool::Inner::IsRunningSequence(
+ SequenceToken sequence_token) const {
+ DCHECK(sequence_token.IsValid());
+ AutoLock lock(lock_);
+ return !IsSequenceTokenRunnable(sequence_token.id_);
+}
+
+void SequencedWorkerPool::Inner::SetRunningTaskInfoForCurrentThread(
+ SequenceToken sequence_token,
+ WorkerShutdown shutdown_behavior) {
+ AutoLock lock(lock_);
+ ThreadMap::const_iterator found = threads_.find(PlatformThread::CurrentId());
+ DCHECK(found != threads_.end());
+ DCHECK(found->second->is_processing_task());
+ DCHECK(!found->second->task_sequence_token().IsValid());
+ found->second->set_running_task_info(sequence_token, shutdown_behavior);
+
+ // Mark the sequence token as in use.
+ bool success = current_sequences_.insert(sequence_token.id_).second;
+ DCHECK(success);
+}
+
// See https://code.google.com/p/chromium/issues/detail?id=168415
void SequencedWorkerPool::Inner::CleanupForTesting() {
DCHECK(!RunsTasksOnCurrentThread());
@@ -786,6 +838,11 @@ void SequencedWorkerPool::Inner::ThreadLoop(Worker* this_worker) {
tracked_objects::ThreadData::TallyRunOnNamedThreadIfTracking(
task, stopwatch);
+ // Update the sequence token in case it has been set from within the
+ // task, so it can be removed from the set of currently running
+ // sequences in DidRunWorkerTask() below.
+ task.sequence_token_id = this_worker->task_sequence_token().id_;
+
// 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 reset_running_task_info() so
@@ -920,7 +977,7 @@ int SequencedWorkerPool::Inner::LockedGetNamedTokenID(
return result.id_;
}
-int64 SequencedWorkerPool::Inner::LockedGetNextSequenceTaskNumber() {
+int64_t SequencedWorkerPool::Inner::LockedGetNextSequenceTaskNumber() {
lock_.AssertAcquired();
// We assume that we never create enough tasks to wrap around.
return next_sequence_task_number_++;
@@ -1145,17 +1202,55 @@ SequencedWorkerPool::Inner::g_last_sequence_number_;
// SequencedWorkerPool --------------------------------------------------------
+std::string SequencedWorkerPool::SequenceToken::ToString() const {
+ return base::StringPrintf("[%d]", id_);
+}
+
// static
SequencedWorkerPool::SequenceToken
SequencedWorkerPool::GetSequenceTokenForCurrentThread() {
- // Don't construct lazy instance on check.
- if (g_lazy_tls_ptr == NULL)
+ Worker* worker = Worker::GetForCurrentThread();
+ if (!worker)
return SequenceToken();
- SequencedWorkerPool::SequenceToken* token = g_lazy_tls_ptr.Get().Get();
- if (!token)
- return SequenceToken();
- return *token;
+ return worker->task_sequence_token();
+}
+
+// static
+scoped_refptr<SequencedWorkerPool>
+SequencedWorkerPool::GetWorkerPoolForCurrentThread() {
+ Worker* worker = Worker::GetForCurrentThread();
+ if (!worker)
+ return nullptr;
+
+ return worker->worker_pool();
+}
+
+// static
+scoped_refptr<SequencedTaskRunner>
+SequencedWorkerPool::GetSequencedTaskRunnerForCurrentThread() {
+ Worker* worker = Worker::GetForCurrentThread();
+
+ // If there is no worker, this thread is not a worker thread. Otherwise, it is
+ // currently running a task (sequenced or unsequenced).
+ if (!worker)
+ return nullptr;
+
+ scoped_refptr<SequencedWorkerPool> pool = worker->worker_pool();
+ SequenceToken sequence_token = worker->task_sequence_token();
+ WorkerShutdown shutdown_behavior = worker->task_shutdown_behavior();
+ if (!sequence_token.IsValid()) {
+ // Create a new sequence token and bind this thread to it, to make sure that
+ // a task posted to the SequencedTaskRunner we are going to return is not
+ // immediately going to run on a different thread.
+ sequence_token = Inner::GetSequenceToken();
+ pool->inner_->SetRunningTaskInfoForCurrentThread(sequence_token,
+ shutdown_behavior);
+ }
+
+ DCHECK(pool->IsRunningSequenceOnCurrentThread(sequence_token));
+ return new SequencedWorkerPoolSequencedTaskRunner(
+ std::move(pool), sequence_token, shutdown_behavior);
}
SequencedWorkerPool::SequencedWorkerPool(size_t max_threads,
@@ -1174,8 +1269,7 @@ SequencedWorkerPool::SequencedWorkerPool(size_t max_threads,
SequencedWorkerPool::~SequencedWorkerPool() {}
void SequencedWorkerPool::OnDestruct() const {
- // Avoid deleting ourselves on a worker thread (which would
- // deadlock).
+ // Avoid deleting ourselves on a worker thread (which would deadlock).
if (RunsTasksOnCurrentThread()) {
constructor_task_runner_->DeleteSoon(FROM_HERE, this);
} else {
@@ -1183,8 +1277,9 @@ void SequencedWorkerPool::OnDestruct() const {
}
}
+// static
SequencedWorkerPool::SequenceToken SequencedWorkerPool::GetSequenceToken() {
- return inner_->GetSequenceToken();
+ return Inner::GetSequenceToken();
}
SequencedWorkerPool::SequenceToken SequencedWorkerPool::GetNamedSequenceToken(
@@ -1288,6 +1383,11 @@ bool SequencedWorkerPool::IsRunningSequenceOnCurrentThread(
return inner_->IsRunningSequenceOnCurrentThread(sequence_token);
}
+bool SequencedWorkerPool::IsRunningSequence(
+ SequenceToken sequence_token) const {
+ return inner_->IsRunningSequence(sequence_token);
+}
+
void SequencedWorkerPool::FlushForTesting() {
inner_->CleanupForTesting();
}
diff --git a/chromium/base/threading/sequenced_worker_pool.h b/chromium/base/threading/sequenced_worker_pool.h
index ee282bc2312..ba0e444210f 100644
--- a/chromium/base/threading/sequenced_worker_pool.h
+++ b/chromium/base/threading/sequenced_worker_pool.h
@@ -5,12 +5,14 @@
#ifndef BASE_THREADING_SEQUENCED_WORKER_POOL_H_
#define BASE_THREADING_SEQUENCED_WORKER_POOL_H_
+#include <stddef.h>
+
#include <cstddef>
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/callback_forward.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/single_thread_task_runner.h"
@@ -45,7 +47,8 @@ class SequencedTaskRunner;
// destruction will be visible to T2.
//
// Example:
-// SequencedWorkerPool::SequenceToken token = pool.GetSequenceToken();
+// SequencedWorkerPool::SequenceToken token =
+// SequencedWorkerPool::GetSequenceToken();
// pool.PostSequencedWorkerTask(token, SequencedWorkerPool::SKIP_ON_SHUTDOWN,
// FROM_HERE, base::Bind(...));
// pool.PostSequencedWorkerTask(token, SequencedWorkerPool::SKIP_ON_SHUTDOWN,
@@ -121,7 +124,7 @@ class BASE_EXPORT SequencedWorkerPool : public TaskRunner {
// Opaque identifier that defines sequencing of tasks posted to the worker
// pool.
- class SequenceToken {
+ class BASE_EXPORT SequenceToken {
public:
SequenceToken() : id_(0) {}
~SequenceToken() {}
@@ -135,6 +138,10 @@ class BASE_EXPORT SequencedWorkerPool : public TaskRunner {
return id_ != 0;
}
+ // Returns a string representation of this token. This method should only be
+ // used for debugging.
+ std::string ToString() const;
+
private:
friend class SequencedWorkerPool;
@@ -157,25 +164,38 @@ class BASE_EXPORT SequencedWorkerPool : public TaskRunner {
// an unsequenced task, returns an invalid SequenceToken.
static SequenceToken GetSequenceTokenForCurrentThread();
+ // Gets a SequencedTaskRunner for the current thread. If the current thread is
+ // running an unsequenced task, a new SequenceToken will be generated and set,
+ // so that the returned SequencedTaskRunner is guaranteed to run tasks after
+ // the current task has finished running.
+ static scoped_refptr<SequencedTaskRunner>
+ GetSequencedTaskRunnerForCurrentThread();
+
+ // Returns a unique token that can be used to sequence tasks posted to
+ // PostSequencedWorkerTask(). Valid tokens are always nonzero.
+ // TODO(bauerb): Rename this to better differentiate from
+ // GetSequenceTokenForCurrentThread().
+ static SequenceToken GetSequenceToken();
+
+ // Returns the SequencedWorkerPool that owns this thread, or null if the
+ // current thread is not a SequencedWorkerPool worker thread.
+ static scoped_refptr<SequencedWorkerPool> GetWorkerPoolForCurrentThread();
+
// When constructing a SequencedWorkerPool, there must be a
- // MessageLoop on the current thread unless you plan to deliberately
- // leak it.
+ // ThreadTaskRunnerHandle on the current thread unless you plan to
+ // deliberately leak it.
// Pass the maximum number of threads (they will be lazily created as needed)
// and a prefix for the thread name to aid in debugging.
SequencedWorkerPool(size_t max_threads,
const std::string& thread_name_prefix);
- // Like above, but with |observer| for testing. Does not take
- // ownership of |observer|.
+ // Like above, but with |observer| for testing. Does not take ownership of
+ // |observer|.
SequencedWorkerPool(size_t max_threads,
const std::string& thread_name_prefix,
TestingObserver* observer);
- // Returns a unique token that can be used to sequence tasks posted to
- // PostSequencedWorkerTask(). Valid tokens are always nonzero.
- SequenceToken GetSequenceToken();
-
// Returns the sequence token associated with the given name. Calling this
// function multiple times with the same string will always produce the
// same sequence token. If the name has not been used before, a new token
@@ -300,6 +320,10 @@ class BASE_EXPORT SequencedWorkerPool : public TaskRunner {
// sequence_token.
bool IsRunningSequenceOnCurrentThread(SequenceToken sequence_token) const;
+ // Returns true if any thread is currently processing a task with the given
+ // sequence token. Should only be called with a valid sequence token.
+ bool IsRunningSequence(SequenceToken sequence_token) const;
+
// Blocks until all pending tasks are complete. This should only be called in
// unit tests when you want to validate something that should have happened.
// This will not flush delayed tasks; delayed tasks get deleted.
diff --git a/chromium/base/threading/sequenced_worker_pool_unittest.cc b/chromium/base/threading/sequenced_worker_pool_unittest.cc
index bf82b110357..fba18084391 100644
--- a/chromium/base/threading/sequenced_worker_pool_unittest.cc
+++ b/chromium/base/threading/sequenced_worker_pool_unittest.cc
@@ -4,15 +4,21 @@
#include "base/threading/sequenced_worker_pool.h"
+#include <stddef.h>
+
#include <algorithm>
#include "base/bind.h"
#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
+#include "base/sequence_checker_impl.h"
+#include "base/stl_util.h"
#include "base/synchronization/condition_variable.h"
#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
#include "base/test/sequenced_task_runner_test_template.h"
#include "base/test/sequenced_worker_pool_owner.h"
#include "base/test/task_runner_test_template.h"
@@ -69,7 +75,8 @@ class ThreadBlocker {
class DestructionDeadlockChecker
: public base::RefCountedThreadSafe<DestructionDeadlockChecker> {
public:
- DestructionDeadlockChecker(const scoped_refptr<SequencedWorkerPool>& pool)
+ explicit DestructionDeadlockChecker(
+ const scoped_refptr<SequencedWorkerPool>& pool)
: pool_(pool) {}
protected:
@@ -234,8 +241,6 @@ class SequencedWorkerPoolTest : public testing::Test {
ResetPool();
}
- void TearDown() override { pool()->Shutdown(); }
-
const scoped_refptr<SequencedWorkerPool>& pool() {
return pool_owner_->pool();
}
@@ -351,7 +356,6 @@ TEST_F(SequencedWorkerPoolTest, DelayedTaskDuringShutdown) {
ASSERT_EQ(1u, completion_sequence.size());
ASSERT_EQ(1, completion_sequence[0]);
- pool()->Shutdown();
// Shutdown is asynchronous, so use ResetPool() to block until the pool is
// fully destroyed (and thus shut down).
ResetPool();
@@ -430,9 +434,6 @@ TEST_F(SequencedWorkerPoolTest, LotsOfTasksTwoPools) {
std::vector<int> result =
tracker()->WaitUntilTasksComplete(2*kNumTasks);
EXPECT_EQ(2 * kNumTasks, result.size());
-
- pool2.pool()->Shutdown();
- pool1.pool()->Shutdown();
}
// Test that tasks with the same sequence token are executed in order but don't
@@ -525,10 +526,8 @@ TEST_F(SequencedWorkerPoolTest, DISABLED_IgnoresAfterShutdown) {
// The kNumWorkerThread items should have completed, in no particular order.
ASSERT_EQ(kNumWorkerThreads, result.size());
- for (size_t i = 0; i < kNumWorkerThreads; i++) {
- EXPECT_TRUE(std::find(result.begin(), result.end(), static_cast<int>(i)) !=
- result.end());
- }
+ for (size_t i = 0; i < kNumWorkerThreads; i++)
+ EXPECT_TRUE(ContainsValue(result, static_cast<int>(i)));
// No further tasks, regardless of shutdown mode, should be allowed.
EXPECT_FALSE(pool()->PostWorkerTaskWithShutdownBehavior(
@@ -660,11 +659,9 @@ TEST_F(SequencedWorkerPoolTest, DiscardOnShutdown) {
// The kNumWorkerThread items should have completed, plus the BLOCK_SHUTDOWN
// one, in no particular order.
ASSERT_EQ(kNumWorkerThreads + 1, result.size());
- for (size_t i = 0; i < kNumWorkerThreads; i++) {
- EXPECT_TRUE(std::find(result.begin(), result.end(), static_cast<int>(i)) !=
- result.end());
- }
- EXPECT_TRUE(std::find(result.begin(), result.end(), 102) != result.end());
+ for (size_t i = 0; i < kNumWorkerThreads; i++)
+ EXPECT_TRUE(ContainsValue(result, static_cast<int>(i)));
+ EXPECT_TRUE(ContainsValue(result, 102));
}
// Tests that CONTINUE_ON_SHUTDOWN tasks don't block shutdown.
@@ -760,10 +757,8 @@ TEST_F(SequencedWorkerPoolTest, SkipOnShutdown) {
// allowed to complete. No additional non-blocking tasks should have been
// started.
ASSERT_EQ(kNumWorkerThreads, result.size());
- for (size_t i = 0; i < kNumWorkerThreads; i++) {
- EXPECT_TRUE(std::find(result.begin(), result.end(), static_cast<int>(i)) !=
- result.end());
- }
+ for (size_t i = 0; i < kNumWorkerThreads; i++)
+ EXPECT_TRUE(ContainsValue(result, static_cast<int>(i)));
}
// Ensure all worker threads are created, and then trigger a spurious
@@ -799,33 +794,30 @@ TEST_F(SequencedWorkerPoolTest, IsRunningOnCurrentThread) {
SequencedWorkerPool::SequenceToken token2 = pool()->GetSequenceToken();
SequencedWorkerPool::SequenceToken unsequenced_token;
- scoped_refptr<SequencedWorkerPool> unused_pool =
- new SequencedWorkerPool(2, "unused_pool");
+ SequencedWorkerPoolOwner unused_pool_owner(2, "unused_pool");
EXPECT_FALSE(pool()->RunsTasksOnCurrentThread());
EXPECT_FALSE(pool()->IsRunningSequenceOnCurrentThread(token1));
EXPECT_FALSE(pool()->IsRunningSequenceOnCurrentThread(token2));
EXPECT_FALSE(pool()->IsRunningSequenceOnCurrentThread(unsequenced_token));
- EXPECT_FALSE(unused_pool->RunsTasksOnCurrentThread());
- EXPECT_FALSE(unused_pool->IsRunningSequenceOnCurrentThread(token1));
- EXPECT_FALSE(unused_pool->IsRunningSequenceOnCurrentThread(token2));
+ EXPECT_FALSE(unused_pool_owner.pool()->RunsTasksOnCurrentThread());
+ EXPECT_FALSE(
+ unused_pool_owner.pool()->IsRunningSequenceOnCurrentThread(token1));
EXPECT_FALSE(
- unused_pool->IsRunningSequenceOnCurrentThread(unsequenced_token));
+ unused_pool_owner.pool()->IsRunningSequenceOnCurrentThread(token2));
+ EXPECT_FALSE(unused_pool_owner.pool()->IsRunningSequenceOnCurrentThread(
+ unsequenced_token));
pool()->PostSequencedWorkerTask(
- token1, FROM_HERE,
- base::Bind(&IsRunningOnCurrentThreadTask,
- token1, token2, pool(), unused_pool));
+ token1, FROM_HERE, base::Bind(&IsRunningOnCurrentThreadTask, token1,
+ token2, pool(), unused_pool_owner.pool()));
pool()->PostSequencedWorkerTask(
token2, FROM_HERE,
- base::Bind(&IsRunningOnCurrentThreadTask,
- token2, unsequenced_token, pool(), unused_pool));
+ base::Bind(&IsRunningOnCurrentThreadTask, token2, unsequenced_token,
+ pool(), unused_pool_owner.pool()));
pool()->PostWorkerTask(
- FROM_HERE,
- base::Bind(&IsRunningOnCurrentThreadTask,
- unsequenced_token, token1, pool(), unused_pool));
- pool()->Shutdown();
- unused_pool->Shutdown();
+ FROM_HERE, base::Bind(&IsRunningOnCurrentThreadTask, unsequenced_token,
+ token1, pool(), unused_pool_owner.pool()));
}
// Checks that tasks are destroyed in the right context during shutdown. If a
@@ -904,16 +896,148 @@ TEST_F(SequencedWorkerPoolTest, FlushForTesting) {
pool()->FlushForTesting();
}
-TEST(SequencedWorkerPoolRefPtrTest, ShutsDownCleanWithContinueOnShutdown) {
- MessageLoop loop;
- scoped_refptr<SequencedWorkerPool> pool(new SequencedWorkerPool(3, "Pool"));
+// Helper method for VerifyCurrentSequencedTaskRunner() and
+// VerifyCurrentSequencedTaskRunnerForUnsequencedTask().
+void VerifySequencedTaskRunnerRunsOnCurrentThread(
+ SequencedTaskRunner* task_runner,
+ bool should_run_on_current_thread,
+ const Closure& callback) {
+ EXPECT_EQ(should_run_on_current_thread,
+ task_runner->RunsTasksOnCurrentThread());
+ callback.Run();
+}
+
+void VerifyCurrentSequencedTaskRunner(
+ SequencedTaskRunner* expected_task_runner,
+ bool expected_equal,
+ const Closure& callback) {
+ scoped_refptr<SequencedTaskRunner> task_runner =
+ SequencedWorkerPool::GetSequencedTaskRunnerForCurrentThread();
+
+ EXPECT_TRUE(task_runner->RunsTasksOnCurrentThread());
+
+ // SequencedTaskRunner does not allow directly checking for equality, but we
+ // can post a task to one task runner and verify that the other task runner
+ // is on the same sequence.
+ task_runner->PostTask(
+ FROM_HERE,
+ Bind(&VerifySequencedTaskRunnerRunsOnCurrentThread,
+ base::Unretained(expected_task_runner), expected_equal, callback));
+}
+
+void VerifyCurrentSequencedTaskRunnerForUnsequencedTask(
+ SequencedWorkerPool* pool,
+ const Closure& callback) {
+ EXPECT_FALSE(
+ SequencedWorkerPool::GetSequenceTokenForCurrentThread().IsValid());
+
+ scoped_refptr<SequencedTaskRunner> task_runner =
+ SequencedWorkerPool::GetSequencedTaskRunnerForCurrentThread();
+
+ EXPECT_TRUE(task_runner->RunsTasksOnCurrentThread());
+
+ scoped_refptr<SequencedTaskRunner> expected_task_runner =
+ SequencedWorkerPool::GetSequencedTaskRunnerForCurrentThread();
+
+ // The pool should now be running a sequence. This also verifies that no other
+ // thread will start running tasks with this sequence token.
+ const SequencedWorkerPool::SequenceToken sequence_token =
+ SequencedWorkerPool::GetSequenceTokenForCurrentThread();
+ ASSERT_TRUE(sequence_token.IsValid());
+ EXPECT_TRUE(pool->IsRunningSequence(sequence_token));
+
+ // The two sequenced task runners should be the same. See
+ // VerifyCurrentSequencedTaskRunner() above for why the check is implemented
+ // this way.
+ const bool expected_equal = true;
+ task_runner->PostTask(
+ FROM_HERE,
+ Bind(&VerifySequencedTaskRunnerRunsOnCurrentThread,
+ std::move(expected_task_runner), expected_equal, callback));
+}
+
+TEST_F(SequencedWorkerPoolTest, GetSequencedTaskRunnerForCurrentThread) {
+ EnsureAllWorkersCreated();
+
+ // The current thread should not have a sequenced task runner from a
+ // worker pool.
+ scoped_refptr<SequencedTaskRunner> local_task_runner =
+ SequencedWorkerPool::GetSequencedTaskRunnerForCurrentThread();
+ EXPECT_FALSE(local_task_runner);
+
+ WaitableEvent event(false, false);
+ Closure signal = Bind(&WaitableEvent::Signal, Unretained(&event));
+ scoped_refptr<SequencedTaskRunner> task_runner_1 =
+ pool()->GetSequencedTaskRunner(SequencedWorkerPool::GetSequenceToken());
+ scoped_refptr<SequencedTaskRunner> task_runner_2 =
+ pool()->GetSequencedTaskRunner(SequencedWorkerPool::GetSequenceToken());
+ task_runner_1->PostTask(
+ FROM_HERE, Bind(&VerifyCurrentSequencedTaskRunner,
+ base::Unretained(task_runner_1.get()), true, signal));
+ event.Wait();
+ task_runner_2->PostTask(
+ FROM_HERE, Bind(&VerifyCurrentSequencedTaskRunner,
+ base::Unretained(task_runner_2.get()), true, signal));
+ event.Wait();
+
+ task_runner_1->PostTask(
+ FROM_HERE, Bind(&VerifyCurrentSequencedTaskRunner,
+ base::Unretained(task_runner_2.get()), false, signal));
+ event.Wait();
+
+ pool()->PostWorkerTask(
+ FROM_HERE, Bind(&VerifyCurrentSequencedTaskRunnerForUnsequencedTask,
+ pool(), signal));
+ event.Wait();
+}
+
+class ChecksSequenceOnDestruction
+ : public RefCountedThreadSafe<ChecksSequenceOnDestruction> {
+ public:
+ void DoNothing() {}
+
+ private:
+ friend class RefCountedThreadSafe<ChecksSequenceOnDestruction>;
+
+ ~ChecksSequenceOnDestruction() {
+ EXPECT_TRUE(sequence_checker_.CalledOnValidSequencedThread());
+ }
+
+ SequenceCheckerImpl sequence_checker_;
+};
+
+void VerifySequenceOnDestruction(const Closure& callback) {
+ scoped_refptr<SequencedTaskRunner> task_runner =
+ SequencedWorkerPool::GetSequencedTaskRunnerForCurrentThread();
+ scoped_refptr<ChecksSequenceOnDestruction> check_sequence(
+ new ChecksSequenceOnDestruction);
+
+ // Post a task to an empty method. This will keep the only reference to the
+ // object, so it will be destroyed right after running the task.
+ task_runner->PostTask(FROM_HERE, Bind(&ChecksSequenceOnDestruction::DoNothing,
+ std::move(check_sequence)));
+
+ // Post the callback afterwards, so we can be sure the first task completed.
+ task_runner->PostTask(FROM_HERE, callback);
+}
+
+TEST_F(SequencedWorkerPoolTest, CheckSequenceOnDestruction) {
+ EnsureAllWorkersCreated();
+
+ WaitableEvent event(false, false);
+ Closure signal = Bind(&WaitableEvent::Signal, Unretained(&event));
+ pool()->PostWorkerTask(FROM_HERE, Bind(&VerifySequenceOnDestruction, signal));
+ event.Wait();
+}
+
+TEST_F(SequencedWorkerPoolTest, ShutsDownCleanWithContinueOnShutdown) {
scoped_refptr<SequencedTaskRunner> task_runner =
- pool->GetSequencedTaskRunnerWithShutdownBehavior(
- pool->GetSequenceToken(),
+ pool()->GetSequencedTaskRunnerWithShutdownBehavior(
+ pool()->GetSequenceToken(),
base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
// Upon test exit, should shut down without hanging.
- pool->Shutdown();
+ pool()->Shutdown();
}
class SequencedWorkerPoolTaskRunnerTestDelegate {
diff --git a/chromium/base/threading/simple_thread.h b/chromium/base/threading/simple_thread.h
index 2f0eb4d778f..3deeb1018cb 100644
--- a/chromium/base/threading/simple_thread.h
+++ b/chromium/base/threading/simple_thread.h
@@ -40,16 +40,17 @@
#ifndef BASE_THREADING_SIMPLE_THREAD_H_
#define BASE_THREADING_SIMPLE_THREAD_H_
-#include <string>
+#include <stddef.h>
+
#include <queue>
+#include <string>
#include <vector>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/compiler_specific.h"
-#include "base/threading/platform_thread.h"
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
+#include "base/threading/platform_thread.h"
namespace base {
diff --git a/chromium/base/threading/thread.cc b/chromium/base/threading/thread.cc
index 4b517a1ef26..19bf49e46d0 100644
--- a/chromium/base/threading/thread.cc
+++ b/chromium/base/threading/thread.cc
@@ -12,6 +12,7 @@
#include "base/threading/thread_id_name_manager.h"
#include "base/threading/thread_local.h"
#include "base/threading/thread_restrictions.h"
+#include "build/build_config.h"
#if defined(OS_WIN)
#include "base/win/scoped_com_initializer.h"
@@ -262,8 +263,12 @@ void Thread::ThreadMain() {
com_initializer.reset();
#endif
- // Assert that MessageLoop::Quit was called by ThreadQuitHelper.
- DCHECK(GetThreadWasQuitProperly());
+ if (message_loop->type() != MessageLoop::TYPE_CUSTOM) {
+ // Assert that MessageLoop::QuitWhenIdle was called by ThreadQuitHelper.
+ // Don't check for custom message pumps, because their shutdown might not
+ // allow this.
+ DCHECK(GetThreadWasQuitProperly());
+ }
// We can't receive messages anymore.
// (The message loop is destructed at the end of this block)
diff --git a/chromium/base/threading/thread.h b/chromium/base/threading/thread.h
index c8a1c803156..da985da07ae 100644
--- a/chromium/base/threading/thread.h
+++ b/chromium/base/threading/thread.h
@@ -5,10 +5,13 @@
#ifndef BASE_THREADING_THREAD_H_
#define BASE_THREADING_THREAD_H_
+#include <stddef.h>
+
#include <string>
#include "base/base_export.h"
#include "base/callback.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/message_loop/timer_slack.h"
@@ -16,6 +19,7 @@
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/platform_thread.h"
+#include "build/build_config.h"
namespace base {
diff --git a/chromium/base/threading/thread_checker_unittest.cc b/chromium/base/threading/thread_checker_unittest.cc
index d42cbc26278..fd98f764ed1 100644
--- a/chromium/base/threading/thread_checker_unittest.cc
+++ b/chromium/base/threading/thread_checker_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/basictypes.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
-#include "base/threading/thread_checker.h"
#include "base/threading/simple_thread.h"
+#include "base/threading/thread_checker.h"
#include "testing/gtest/include/gtest/gtest.h"
// Duplicated from base/threading/thread_checker.h so that we can be
diff --git a/chromium/base/threading/thread_collision_warner.h b/chromium/base/threading/thread_collision_warner.h
index de4e9c3eb58..4699a910dd2 100644
--- a/chromium/base/threading/thread_collision_warner.h
+++ b/chromium/base/threading/thread_collision_warner.h
@@ -9,8 +9,8 @@
#include "base/atomicops.h"
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/compiler_specific.h"
+#include "base/macros.h"
// A helper class alongside macros to be used to verify assumptions about thread
// safety of a class.
diff --git a/chromium/base/threading/thread_collision_warner_unittest.cc b/chromium/base/threading/thread_collision_warner_unittest.cc
index d7ce79ec378..79ca7e2a4ce 100644
--- a/chromium/base/threading/thread_collision_warner_unittest.cc
+++ b/chromium/base/threading/thread_collision_warner_unittest.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/synchronization/lock.h"
#include "base/threading/platform_thread.h"
diff --git a/chromium/base/threading/thread_id_name_manager.h b/chromium/base/threading/thread_id_name_manager.h
index 1ba7e13e57b..f469b605e40 100644
--- a/chromium/base/threading/thread_id_name_manager.h
+++ b/chromium/base/threading/thread_id_name_manager.h
@@ -9,7 +9,7 @@
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/synchronization/lock.h"
#include "base/threading/platform_thread.h"
diff --git a/chromium/base/threading/thread_local.h b/chromium/base/threading/thread_local.h
index df9c4b72573..f40420cd2f8 100644
--- a/chromium/base/threading/thread_local.h
+++ b/chromium/base/threading/thread_local.h
@@ -52,8 +52,9 @@
#define BASE_THREADING_THREAD_LOCAL_H_
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/threading/thread_local_storage.h"
+#include "build/build_config.h"
#if defined(OS_POSIX)
#include <pthread.h>
diff --git a/chromium/base/threading/thread_local_posix.cc b/chromium/base/threading/thread_local_posix.cc
index 75ea4795d45..8bc46ad1902 100644
--- a/chromium/base/threading/thread_local_posix.cc
+++ b/chromium/base/threading/thread_local_posix.cc
@@ -7,6 +7,7 @@
#include <pthread.h>
#include "base/logging.h"
+#include "build/build_config.h"
#if !defined(OS_ANDROID)
diff --git a/chromium/base/threading/thread_local_storage.cc b/chromium/base/threading/thread_local_storage.cc
index 701f6a2af9b..a7eb5278884 100644
--- a/chromium/base/threading/thread_local_storage.cc
+++ b/chromium/base/threading/thread_local_storage.cc
@@ -6,6 +6,7 @@
#include "base/atomicops.h"
#include "base/logging.h"
+#include "build/build_config.h"
using base::internal::PlatformThreadLocalStorage;
@@ -76,8 +77,10 @@ void** ConstructTlsVector() {
// TLS_KEY_OUT_OF_INDEXES, go ahead and set it. Otherwise, do nothing, as
// another thread already did our dirty work.
if (PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES !=
- base::subtle::NoBarrier_CompareAndSwap(&g_native_tls_key,
- PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES, key)) {
+ static_cast<PlatformThreadLocalStorage::TLSKey>(
+ base::subtle::NoBarrier_CompareAndSwap(
+ &g_native_tls_key,
+ PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES, key))) {
// We've been shortcut. Another thread replaced g_native_tls_key first so
// we need to destroy our index and use the one the other thread got
// first.
diff --git a/chromium/base/threading/thread_local_storage.h b/chromium/base/threading/thread_local_storage.h
index 195bff683c3..013b0aeffbb 100644
--- a/chromium/base/threading/thread_local_storage.h
+++ b/chromium/base/threading/thread_local_storage.h
@@ -7,7 +7,8 @@
#include "base/atomicops.h"
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
+#include "build/build_config.h"
#if defined(OS_WIN)
#include <windows.h>
@@ -27,7 +28,7 @@ class BASE_EXPORT PlatformThreadLocalStorage {
#if defined(OS_WIN)
typedef unsigned long TLSKey;
- enum { TLS_KEY_OUT_OF_INDEXES = TLS_OUT_OF_INDEXES };
+ enum : unsigned { TLS_KEY_OUT_OF_INDEXES = TLS_OUT_OF_INDEXES };
#elif defined(OS_POSIX)
typedef pthread_key_t TLSKey;
// The following is a "reserved key" which is used in our generic Chromium
diff --git a/chromium/base/threading/thread_local_storage_unittest.cc b/chromium/base/threading/thread_local_storage_unittest.cc
index bcc1d1b9db5..322524b10e1 100644
--- a/chromium/base/threading/thread_local_storage_unittest.cc
+++ b/chromium/base/threading/thread_local_storage_unittest.cc
@@ -7,8 +7,10 @@
#include <process.h>
#endif
+#include "base/macros.h"
#include "base/threading/simple_thread.h"
#include "base/threading/thread_local_storage.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#if defined(OS_WIN)
diff --git a/chromium/base/threading/thread_perftest.cc b/chromium/base/threading/thread_perftest.cc
index e865ffa9085..5958f1aa6de 100644
--- a/chromium/base/threading/thread_perftest.cc
+++ b/chromium/base/threading/thread_perftest.cc
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
+
#include "base/base_switches.h"
#include "base/bind.h"
#include "base/command_line.h"
@@ -44,7 +46,10 @@ class ThreadPerfTest : public testing::Test {
// To be implemented by each test. Subclass must uses threads_ such that
// their cpu-time can be measured. Test must return from PingPong() _and_
// call FinishMeasurement from any thread to complete the test.
- virtual void Init() {}
+ virtual void Init() {
+ if (ThreadTicks::IsSupported())
+ ThreadTicks::WaitUntilInitialized();
+ }
virtual void PingPong(int hops) = 0;
virtual void Reset() {}
diff --git a/chromium/base/threading/thread_restrictions.h b/chromium/base/threading/thread_restrictions.h
index a71cad2795b..eec00fbb796 100644
--- a/chromium/base/threading/thread_restrictions.h
+++ b/chromium/base/threading/thread_restrictions.h
@@ -6,7 +6,7 @@
#define BASE_THREADING_THREAD_RESTRICTIONS_H_
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
// See comment at top of thread_checker.h
#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON))
@@ -22,7 +22,7 @@ class ScopedAllowWaitForLegacyWebViewApi;
namespace cc {
class CompletionEvent;
-class TaskGraphRunner;
+class SingleThreadTaskGraphRunner;
}
namespace chromeos {
class BlockingMethodCaller;
@@ -42,7 +42,9 @@ class GpuChannelHost;
class NestedMessagePumpAndroid;
class ScopedAllowWaitForAndroidLayoutTests;
class ScopedAllowWaitForDebugURL;
+class SoftwareOutputDeviceMus;
class TextInputClientMac;
+class RasterWorkerPool;
} // namespace content
namespace dbus {
class Bus;
@@ -51,10 +53,17 @@ namespace disk_cache {
class BackendImpl;
class InFlightIO;
}
+namespace gles2 {
+class CommandBufferClientImpl;
+}
namespace mojo {
namespace common {
-class WatcherThreadManager;
+class MessagePumpMojo;
+}
}
+namespace mus {
+class CommandBufferLocal;
+class GpuState;
}
namespace net {
class NetworkChangeNotifierMac;
@@ -71,6 +80,10 @@ namespace ui {
class WindowResizeHelperMac;
}
+namespace views {
+class WindowManagerConnection;
+}
+
namespace base {
namespace android {
@@ -183,8 +196,8 @@ class BASE_EXPORT ThreadRestrictions {
friend class ::HistogramSynchronizer;
friend class ::ScopedAllowWaitForLegacyWebViewApi;
friend class cc::CompletionEvent;
- friend class cc::TaskGraphRunner;
- friend class mojo::common::WatcherThreadManager;
+ friend class cc::SingleThreadTaskGraphRunner;
+ friend class content::RasterWorkerPool;
friend class remoting::AutoThread;
friend class ui::WindowResizeHelperMac;
friend class MessagePumpDefault;
@@ -194,6 +207,10 @@ class BASE_EXPORT ThreadRestrictions {
friend class ThreadTestHelper;
friend class PlatformThread;
friend class android::JavaHandlerThread;
+ friend class gles2::CommandBufferClientImpl;
+ friend class mojo::common::MessagePumpMojo;
+ friend class mus::CommandBufferLocal;
+ friend class mus::GpuState;
// END ALLOWED USAGE.
// BEGIN USAGE THAT NEEDS TO BE FIXED.
@@ -213,7 +230,11 @@ class BASE_EXPORT ThreadRestrictions {
friend class net::NetworkChangeNotifierMac; // http://crbug.com/125097
friend class ::BrowserProcessImpl; // http://crbug.com/125207
friend class ::NativeBackendKWallet; // http://crbug.com/125331
- // END USAGE THAT NEEDS TO BE FIXED.
+#if !defined(OFFICIAL_BUILD)
+ friend class content::SoftwareOutputDeviceMus; // Interim non-production code
+#endif
+ friend class views::WindowManagerConnection;
+// END USAGE THAT NEEDS TO BE FIXED.
#if ENABLE_THREAD_RESTRICTIONS
static bool SetWaitAllowed(bool allowed);
diff --git a/chromium/base/threading/thread_unittest.cc b/chromium/base/threading/thread_unittest.cc
index 94220810c16..c9c6b907cd2 100644
--- a/chromium/base/threading/thread_unittest.cc
+++ b/chromium/base/threading/thread_unittest.cc
@@ -4,6 +4,8 @@
#include "base/threading/thread.h"
+#include <stddef.h>
+
#include <vector>
#include "base/bind.h"
@@ -11,6 +13,7 @@
#include "base/single_thread_task_runner.h"
#include "base/synchronization/waitable_event.h"
#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
diff --git a/chromium/base/threading/watchdog.h b/chromium/base/threading/watchdog.h
index ea3be36d1a8..f8069846e4f 100644
--- a/chromium/base/threading/watchdog.h
+++ b/chromium/base/threading/watchdog.h
@@ -22,6 +22,7 @@
#include "base/base_export.h"
#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "base/synchronization/condition_variable.h"
#include "base/synchronization/lock.h"
#include "base/threading/platform_thread.h"
diff --git a/chromium/base/threading/watchdog_unittest.cc b/chromium/base/threading/watchdog_unittest.cc
index 627f46d8a9b..473f3ecfe21 100644
--- a/chromium/base/threading/watchdog_unittest.cc
+++ b/chromium/base/threading/watchdog_unittest.cc
@@ -5,6 +5,7 @@
#include "base/threading/watchdog.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/synchronization/spin_wait.h"
#include "base/threading/platform_thread.h"
#include "base/time/time.h"
diff --git a/chromium/base/threading/worker_pool.cc b/chromium/base/threading/worker_pool.cc
index 71b1a2bda35..6e07b6ef37e 100644
--- a/chromium/base/threading/worker_pool.cc
+++ b/chromium/base/threading/worker_pool.cc
@@ -8,6 +8,7 @@
#include "base/compiler_specific.h"
#include "base/debug/leak_annotations.h"
#include "base/lazy_instance.h"
+#include "base/macros.h"
#include "base/task_runner.h"
#include "base/threading/post_task_and_reply_impl.h"
#include "base/tracked_objects.h"
diff --git a/chromium/base/threading/worker_pool.h b/chromium/base/threading/worker_pool.h
index f8c62357d93..a52a41428b3 100644
--- a/chromium/base/threading/worker_pool.h
+++ b/chromium/base/threading/worker_pool.h
@@ -22,11 +22,11 @@ class TaskRunner;
// This is a facility that runs tasks that don't require a specific thread or
// a message loop.
//
-// WARNING: This shouldn't be used unless absolutely necessary. Typically
-// (without calling ShutDownCleanly()), we don't wait for the worker pool
-// threads to finish on shutdown, so the tasks running inside the pool must be
-// extremely careful about other objects they access (MessageLoops, Singletons,
-// etc). During shutdown these object may no longer exist.
+// WARNING: This shouldn't be used unless absolutely necessary. We don't wait
+// for the worker pool threads to finish on shutdown, so the tasks running
+// inside the pool must be extremely careful about other objects they access
+// (MessageLoops, Singletons, etc). During shutdown these object may no longer
+// exist.
class BASE_EXPORT WorkerPool {
public:
// This function posts |task| to run on a worker thread. |task_is_slow|
@@ -53,13 +53,6 @@ class BASE_EXPORT WorkerPool {
// Get a TaskRunner wrapper which posts to the WorkerPool using the given
// |task_is_slow| behavior.
static const scoped_refptr<TaskRunner>& GetTaskRunner(bool task_is_slow);
-
- // Blocks until all worker threads quit cleanly. Please note that it ensures
- // that no worker threads are running after the method returns, but it doesn't
- // guarantee to process all queued pending tasks. This method may take a long
- // time. Please don't use it unless absolutely necessary, e.g., when we want
- // to unload the library containing the worker pool before process shutdown.
- static void ShutDownCleanly();
};
} // namespace base
diff --git a/chromium/base/threading/worker_pool_posix.cc b/chromium/base/threading/worker_pool_posix.cc
index 231aa68deaf..53ae4e69627 100644
--- a/chromium/base/threading/worker_pool_posix.cc
+++ b/chromium/base/threading/worker_pool_posix.cc
@@ -4,10 +4,13 @@
#include "base/threading/worker_pool_posix.h"
+#include <stddef.h>
+
#include "base/bind.h"
#include "base/callback.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/strings/stringprintf.h"
#include "base/threading/platform_thread.h"
@@ -22,10 +25,10 @@ namespace base {
namespace {
-LazyInstance<ThreadLocalBoolean>::Leaky g_worker_pool_running_on_this_thread =
- LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<ThreadLocalBoolean>::Leaky
+ g_worker_pool_running_on_this_thread = LAZY_INSTANCE_INITIALIZER;
-const int64 kIdleSecondsBeforeExit = 10 * 60;
+const int kIdleSecondsBeforeExit = 10 * 60;
class WorkerPoolImpl {
public:
@@ -33,55 +36,49 @@ class WorkerPoolImpl {
~WorkerPoolImpl();
void PostTask(const tracked_objects::Location& from_here,
- const Closure& task,
+ const base::Closure& task,
bool task_is_slow);
- void ShutDownCleanly();
-
private:
- scoped_refptr<PosixDynamicThreadPool> pool_;
+ scoped_refptr<base::PosixDynamicThreadPool> pool_;
};
WorkerPoolImpl::WorkerPoolImpl()
- : pool_(new PosixDynamicThreadPool(
- "WorkerPool",
- TimeDelta::FromSeconds(kIdleSecondsBeforeExit))) {
-}
+ : pool_(new base::PosixDynamicThreadPool("WorkerPool",
+ kIdleSecondsBeforeExit)) {}
WorkerPoolImpl::~WorkerPoolImpl() {
- pool_->Terminate(false);
+ pool_->Terminate();
}
void WorkerPoolImpl::PostTask(const tracked_objects::Location& from_here,
- const Closure& task,
+ const base::Closure& task,
bool task_is_slow) {
pool_->PostTask(from_here, task);
}
-void WorkerPoolImpl::ShutDownCleanly() {
- pool_->Terminate(true);
-}
-
-LazyInstance<WorkerPoolImpl> g_lazy_worker_pool = LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<WorkerPoolImpl> g_lazy_worker_pool =
+ LAZY_INSTANCE_INITIALIZER;
class WorkerThread : public PlatformThread::Delegate {
public:
- WorkerThread(const std::string& name_prefix, PosixDynamicThreadPool* pool)
+ WorkerThread(const std::string& name_prefix,
+ base::PosixDynamicThreadPool* pool)
: name_prefix_(name_prefix), pool_(pool) {}
void ThreadMain() override;
private:
const std::string name_prefix_;
- scoped_refptr<PosixDynamicThreadPool> pool_;
+ scoped_refptr<base::PosixDynamicThreadPool> pool_;
DISALLOW_COPY_AND_ASSIGN(WorkerThread);
};
void WorkerThread::ThreadMain() {
g_worker_pool_running_on_this_thread.Get().Set(true);
- const std::string name =
- StringPrintf("%s/%d", name_prefix_.c_str(), PlatformThread::CurrentId());
+ 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);
@@ -102,7 +99,7 @@ void WorkerThread::ThreadMain() {
pending_task.birth_tally, pending_task.time_posted, stopwatch);
}
- pool_->NotifyWorkerIsGoingAway(PlatformThread::CurrentHandle());
+ // The WorkerThread is non-joinable, so it deletes itself.
delete this;
}
@@ -110,7 +107,7 @@ void WorkerThread::ThreadMain() {
// static
bool WorkerPool::PostTask(const tracked_objects::Location& from_here,
- const Closure& task,
+ const base::Closure& task,
bool task_is_slow) {
g_lazy_worker_pool.Pointer()->PostTask(from_here, task, task_is_slow);
return true;
@@ -121,82 +118,73 @@ bool WorkerPool::RunsTasksOnCurrentThread() {
return g_worker_pool_running_on_this_thread.Get().Get();
}
-// static
-void WorkerPool::ShutDownCleanly() {
- g_lazy_worker_pool.Pointer()->ShutDownCleanly();
-}
-
PosixDynamicThreadPool::PosixDynamicThreadPool(const std::string& name_prefix,
- TimeDelta idle_time_before_exit)
+ int idle_seconds_before_exit)
: name_prefix_(name_prefix),
- idle_time_before_exit_(idle_time_before_exit),
+ idle_seconds_before_exit_(idle_seconds_before_exit),
pending_tasks_available_cv_(&lock_),
num_idle_threads_(0),
- has_pending_cleanup_task_(false),
- terminated_(false) {
-}
+ terminated_(false) {}
PosixDynamicThreadPool::~PosixDynamicThreadPool() {
while (!pending_tasks_.empty())
pending_tasks_.pop();
}
-void PosixDynamicThreadPool::Terminate(bool blocking) {
- std::vector<PlatformThreadHandle> threads_to_cleanup;
- std::vector<PlatformThreadHandle> worker_threads;
+void PosixDynamicThreadPool::Terminate() {
{
AutoLock locked(lock_);
- if (terminated_)
- return;
+ DCHECK(!terminated_) << "Thread pool is already terminated.";
terminated_ = true;
-
- threads_to_cleanup.swap(threads_to_cleanup_);
- worker_threads.swap(worker_threads_);
}
pending_tasks_available_cv_.Broadcast();
-
- if (blocking) {
- for (const auto& item : threads_to_cleanup)
- PlatformThread::Join(item);
-
- for (const auto& item : worker_threads)
- PlatformThread::Join(item);
-
- // No need to take the lock. No one else should be accessing these members.
- DCHECK_EQ(0u, num_idle_threads_);
- // The following members should not have new elements added after
- // |terminated_| is set to true.
- DCHECK(threads_to_cleanup_.empty());
- DCHECK(worker_threads_.empty());
- }
}
void PosixDynamicThreadPool::PostTask(
const tracked_objects::Location& from_here,
- const Closure& task) {
+ const base::Closure& task) {
PendingTask pending_task(from_here, task);
+ AddTask(&pending_task);
+}
+
+void PosixDynamicThreadPool::AddTask(PendingTask* pending_task) {
AutoLock locked(lock_);
- AddTaskNoLock(&pending_task);
+ DCHECK(!terminated_)
+ << "This thread pool is already terminated. Do not post new tasks.";
+
+ pending_tasks_.push(*pending_task);
+ pending_task->task.Reset();
+
+ // We have enough worker threads.
+ if (static_cast<size_t>(num_idle_threads_) >= pending_tasks_.size()) {
+ pending_tasks_available_cv_.Signal();
+ } else {
+ // The new PlatformThread will take ownership of the WorkerThread object,
+ // which will delete itself on exit.
+ WorkerThread* worker = new WorkerThread(name_prefix_, this);
+ PlatformThread::CreateNonJoinable(0, worker);
+ }
}
PendingTask PosixDynamicThreadPool::WaitForTask() {
AutoLock locked(lock_);
if (terminated_)
- return PendingTask(FROM_HERE, Closure());
+ return PendingTask(FROM_HERE, base::Closure());
if (pending_tasks_.empty()) { // No work available, wait for work.
num_idle_threads_++;
- if (num_threads_cv_)
- num_threads_cv_->Broadcast();
- pending_tasks_available_cv_.TimedWait(idle_time_before_exit_);
+ if (num_idle_threads_cv_.get())
+ num_idle_threads_cv_->Signal();
+ pending_tasks_available_cv_.TimedWait(
+ TimeDelta::FromSeconds(idle_seconds_before_exit_));
num_idle_threads_--;
- if (num_threads_cv_)
- num_threads_cv_->Broadcast();
+ if (num_idle_threads_cv_.get())
+ num_idle_threads_cv_->Signal();
if (pending_tasks_.empty()) {
- // We waited for work, but there's still no work. Return an empty task to
- // signal the thread to terminate.
- return PendingTask(FROM_HERE, Closure());
+ // We waited for work, but there's still no work. Return NULL to signal
+ // the thread to terminate.
+ return PendingTask(FROM_HERE, base::Closure());
}
}
@@ -205,72 +193,4 @@ PendingTask PosixDynamicThreadPool::WaitForTask() {
return pending_task;
}
-void PosixDynamicThreadPool::NotifyWorkerIsGoingAway(
- PlatformThreadHandle worker) {
- AutoLock locked(lock_);
- if (terminated_)
- return;
-
- auto new_end = std::remove_if(worker_threads_.begin(), worker_threads_.end(),
- [worker](PlatformThreadHandle handle) {
- return handle.is_equal(worker);
- });
- DCHECK_EQ(1, worker_threads_.end() - new_end);
- worker_threads_.erase(new_end, worker_threads_.end());
-
- threads_to_cleanup_.push_back(worker);
-
- if (num_threads_cv_)
- num_threads_cv_->Broadcast();
-
- if (!has_pending_cleanup_task_) {
- has_pending_cleanup_task_ = true;
- PendingTask pending_task(
- FROM_HERE,
- base::Bind(&PosixDynamicThreadPool::CleanUpThreads, Unretained(this)));
- AddTaskNoLock(&pending_task);
- }
-}
-
-void PosixDynamicThreadPool::AddTaskNoLock(PendingTask* pending_task) {
- lock_.AssertAcquired();
-
- if (terminated_) {
- LOG(WARNING)
- << "This thread pool is already terminated. Do not post new tasks.";
- return;
- }
-
- pending_tasks_.push(*pending_task);
- pending_task->task.Reset();
-
- // We have enough worker threads.
- if (num_idle_threads_ >=
- pending_tasks_.size() - (has_pending_cleanup_task_ ? 1 : 0)) {
- pending_tasks_available_cv_.Signal();
- } else {
- // The new PlatformThread will take ownership of the WorkerThread object,
- // which will delete itself on exit.
- WorkerThread* worker = new WorkerThread(name_prefix_, this);
- PlatformThreadHandle handle;
- PlatformThread::Create(0, worker, &handle);
- worker_threads_.push_back(handle);
-
- if (num_threads_cv_)
- num_threads_cv_->Broadcast();
- }
-}
-
-void PosixDynamicThreadPool::CleanUpThreads() {
- std::vector<PlatformThreadHandle> threads_to_cleanup;
- {
- AutoLock locked(lock_);
- DCHECK(has_pending_cleanup_task_);
- has_pending_cleanup_task_ = false;
- threads_to_cleanup.swap(threads_to_cleanup_);
- }
- for (const auto& item : threads_to_cleanup)
- PlatformThread::Join(item);
-}
-
} // namespace base
diff --git a/chromium/base/threading/worker_pool_posix.h b/chromium/base/threading/worker_pool_posix.h
index d3c4a8ff29a..f8971aca7d4 100644
--- a/chromium/base/threading/worker_pool_posix.h
+++ b/chromium/base/threading/worker_pool_posix.h
@@ -5,12 +5,12 @@
// The thread pool used in the POSIX implementation of WorkerPool dynamically
// adds threads as necessary to handle all tasks. It keeps old threads around
// for a period of time to allow them to be reused. After this waiting period,
-// the threads exit. Unless blocking termination is requested, worker threads
-// are not joined during process shutdown. This means that potentially long
-// running tasks (such as DNS lookup) do not block process shutdown, but also
-// means that process shutdown may "leak" objects. Note that although
-// PosixDynamicThreadPool spawns the worker threads and manages the task queue,
-// it does not own the worker threads. The worker threads ask the
+// the threads exit. This thread pool uses non-joinable threads, therefore
+// worker threads are not joined during process shutdown. This means that
+// potentially long running tasks (such as DNS lookup) do not block process
+// shutdown, but also means that process shutdown may "leak" objects. Note that
+// although PosixDynamicThreadPool spawns the worker threads and manages the
+// task queue, it does not own the worker threads. The worker threads ask the
// PosixDynamicThreadPool for work and eventually clean themselves up. The
// worker threads all maintain scoped_refptrs to the PosixDynamicThreadPool
// instance, which prevents PosixDynamicThreadPool from disappearing before all
@@ -26,18 +26,16 @@
#include <queue>
#include <string>
-#include <vector>
-#include "base/basictypes.h"
#include "base/callback_forward.h"
#include "base/location.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/pending_task.h"
#include "base/synchronization/condition_variable.h"
#include "base/synchronization/lock.h"
#include "base/threading/platform_thread.h"
-#include "base/time/time.h"
#include "base/tracked_objects.h"
class Task;
@@ -50,44 +48,34 @@ class BASE_EXPORT PosixDynamicThreadPool
class PosixDynamicThreadPoolPeer;
// All worker threads will share the same |name_prefix|. They will exit after
- // |idle_time_before_exit|.
+ // |idle_seconds_before_exit|.
PosixDynamicThreadPool(const std::string& name_prefix,
- TimeDelta idle_time_before_exit);
+ int idle_seconds_before_exit);
// Indicates that the thread pool is going away. Stops handing out tasks to
- // worker threads. Wakes up all the idle threads to let them exit. If
- // |blocking| is set to true, the call returns after all worker threads have
- // quit.
- // The second and subsequent calls to this method are ignored, regardless of
- // the value of |blocking|.
- void Terminate(bool blocking);
+ // worker threads. Wakes up all the idle threads to let them exit.
+ void Terminate();
// Adds |task| to the thread pool.
void PostTask(const tracked_objects::Location& from_here,
const Closure& task);
- // Worker thread method to wait for up to |idle_time_before_exit| for more
- // work from the thread pool. Returns an empty task if no work is available.
+ // Worker thread method to wait for up to |idle_seconds_before_exit| for more
+ // work from the thread pool. Returns NULL if no work is available.
PendingTask WaitForTask();
- // Marks |worker| as dead and enqueues a cleanup task to join dead worker
- // threads. Unlike tasks enqueued by PostTask(), cleanup tasks never cause new
- // worker threads to be created.
- void NotifyWorkerIsGoingAway(PlatformThreadHandle worker);
-
private:
friend class RefCountedThreadSafe<PosixDynamicThreadPool>;
+ friend class PosixDynamicThreadPoolPeer;
~PosixDynamicThreadPool();
// Adds pending_task to the thread pool. This function will clear
// |pending_task->task|.
- void AddTaskNoLock(PendingTask* pending_task);
-
- void CleanUpThreads();
+ void AddTask(PendingTask* pending_task);
const std::string name_prefix_;
- const TimeDelta idle_time_before_exit_;
+ const int idle_seconds_before_exit_;
Lock lock_; // Protects all the variables below.
@@ -95,20 +83,12 @@ class BASE_EXPORT PosixDynamicThreadPool
// Also used for Broadcast()'ing to worker threads to let them know the pool
// is being deleted and they can exit.
ConditionVariable pending_tasks_available_cv_;
- size_t num_idle_threads_;
- bool has_pending_cleanup_task_;
- std::queue<PendingTask> pending_tasks_;
+ int num_idle_threads_;
+ TaskQueue pending_tasks_;
bool terminated_;
-
- std::vector<PlatformThreadHandle> threads_to_cleanup_;
- std::vector<PlatformThreadHandle> worker_threads_;
-
- // Signaled when idle thread count or living thread count is changed. Please
- // note that it won't be signaled when Terminate() is called.
- //
- // Only used for tests to ensure correct thread ordering. It will always be
+ // Only used for tests to ensure correct thread ordering. It will always be
// NULL in non-test code.
- scoped_ptr<ConditionVariable> num_threads_cv_;
+ scoped_ptr<ConditionVariable> num_idle_threads_cv_;
DISALLOW_COPY_AND_ASSIGN(PosixDynamicThreadPool);
};
diff --git a/chromium/base/threading/worker_pool_posix_unittest.cc b/chromium/base/threading/worker_pool_posix_unittest.cc
index 8d2368f37f9..99a93696070 100644
--- a/chromium/base/threading/worker_pool_posix_unittest.cc
+++ b/chromium/base/threading/worker_pool_posix_unittest.cc
@@ -8,11 +8,11 @@
#include "base/bind.h"
#include "base/callback.h"
+#include "base/macros.h"
#include "base/synchronization/condition_variable.h"
#include "base/synchronization/lock.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 {
@@ -27,17 +27,15 @@ class PosixDynamicThreadPool::PosixDynamicThreadPoolPeer {
ConditionVariable* pending_tasks_available_cv() {
return &pool_->pending_tasks_available_cv_;
}
- size_t num_pending_tasks() const { return pool_->pending_tasks_.size(); }
- size_t num_idle_threads() const { return pool_->num_idle_threads_; }
- ConditionVariable* num_threads_cv() { return pool_->num_threads_cv_.get(); }
- void set_num_threads_cv(ConditionVariable* cv) {
- pool_->num_threads_cv_.reset(cv);
+ const std::queue<PendingTask>& pending_tasks() const {
+ return pool_->pending_tasks_;
}
- const std::vector<PlatformThreadHandle>& threads_to_cleanup() const {
- return pool_->threads_to_cleanup_;
+ int num_idle_threads() const { return pool_->num_idle_threads_; }
+ ConditionVariable* num_idle_threads_cv() {
+ return pool_->num_idle_threads_cv_.get();
}
- const std::vector<PlatformThreadHandle>& worker_threads() const {
- return pool_->worker_threads_;
+ void set_num_idle_threads_cv(ConditionVariable* cv) {
+ pool_->num_idle_threads_cv_.reset(cv);
}
private:
@@ -48,8 +46,6 @@ class PosixDynamicThreadPool::PosixDynamicThreadPoolPeer {
namespace {
-const int64 kDefaultIdleSecondsBeforeExit = 60 * 60;
-
// IncrementingTask's main purpose is to increment a counter. It also updates a
// set of unique thread ids, and signals a ConditionVariable on completion.
// Note that since it does not block, there is no way to control the number of
@@ -61,10 +57,10 @@ void IncrementingTask(Lock* counter_lock,
Lock* unique_threads_lock,
std::set<PlatformThreadId>* unique_threads) {
{
- AutoLock locked(*unique_threads_lock);
+ base::AutoLock locked(*unique_threads_lock);
unique_threads->insert(PlatformThread::CurrentId());
}
- AutoLock locked(*counter_lock);
+ base::AutoLock locked(*counter_lock);
(*counter)++;
}
@@ -78,12 +74,12 @@ struct BlockingIncrementingTaskArgs {
Lock* num_waiting_to_start_lock;
int* num_waiting_to_start;
ConditionVariable* num_waiting_to_start_cv;
- WaitableEvent* start;
+ base::WaitableEvent* start;
};
void BlockingIncrementingTask(const BlockingIncrementingTaskArgs& args) {
{
- AutoLock num_waiting_to_start_locked(*args.num_waiting_to_start_lock);
+ base::AutoLock num_waiting_to_start_locked(*args.num_waiting_to_start_lock);
(*args.num_waiting_to_start)++;
}
args.num_waiting_to_start_cv->Signal();
@@ -95,62 +91,53 @@ void BlockingIncrementingTask(const BlockingIncrementingTaskArgs& args) {
class PosixDynamicThreadPoolTest : public testing::Test {
protected:
PosixDynamicThreadPoolTest()
- : counter_(0),
+ : pool_(new base::PosixDynamicThreadPool("dynamic_pool", 60 * 60)),
+ peer_(pool_.get()),
+ counter_(0),
num_waiting_to_start_(0),
num_waiting_to_start_cv_(&num_waiting_to_start_lock_),
start_(true, false) {}
+ void SetUp() override {
+ peer_.set_num_idle_threads_cv(new ConditionVariable(peer_.lock()));
+ }
+
void TearDown() override {
// Wake up the idle threads so they can terminate.
if (pool_.get())
- pool_->Terminate(false);
- }
-
- void Initialize(TimeDelta idle_time_before_exit) {
- pool_ = new PosixDynamicThreadPool("dynamic_pool", idle_time_before_exit);
- peer_.reset(
- new PosixDynamicThreadPool::PosixDynamicThreadPoolPeer(pool_.get()));
- peer_->set_num_threads_cv(new ConditionVariable(peer_->lock()));
+ pool_->Terminate();
}
void WaitForTasksToStart(int num_tasks) {
- AutoLock num_waiting_to_start_locked(num_waiting_to_start_lock_);
+ base::AutoLock num_waiting_to_start_locked(num_waiting_to_start_lock_);
while (num_waiting_to_start_ < num_tasks) {
num_waiting_to_start_cv_.Wait();
}
}
- void WaitForIdleThreads(size_t num_idle_threads) {
- AutoLock pool_locked(*peer_->lock());
- while (peer_->num_idle_threads() != num_idle_threads) {
- peer_->num_threads_cv()->Wait();
+ void WaitForIdleThreads(int num_idle_threads) {
+ base::AutoLock pool_locked(*peer_.lock());
+ while (peer_.num_idle_threads() < num_idle_threads) {
+ peer_.num_idle_threads_cv()->Wait();
}
}
- void WaitForLivingThreads(int num_living_threads) {
- AutoLock pool_locked(*peer_->lock());
- while (static_cast<int>(peer_->worker_threads().size()) !=
- num_living_threads) {
- peer_->num_threads_cv()->Wait();
- }
- }
-
- Closure CreateNewIncrementingTaskCallback() {
- return Bind(&IncrementingTask, &counter_lock_, &counter_,
- &unique_threads_lock_, &unique_threads_);
+ base::Closure CreateNewIncrementingTaskCallback() {
+ return base::Bind(&IncrementingTask, &counter_lock_, &counter_,
+ &unique_threads_lock_, &unique_threads_);
}
- Closure CreateNewBlockingIncrementingTaskCallback() {
+ base::Closure CreateNewBlockingIncrementingTaskCallback() {
BlockingIncrementingTaskArgs args = {
&counter_lock_, &counter_, &unique_threads_lock_, &unique_threads_,
&num_waiting_to_start_lock_, &num_waiting_to_start_,
&num_waiting_to_start_cv_, &start_
};
- return Bind(&BlockingIncrementingTask, args);
+ return base::Bind(&BlockingIncrementingTask, args);
}
- scoped_refptr<PosixDynamicThreadPool> pool_;
- scoped_ptr<PosixDynamicThreadPool::PosixDynamicThreadPoolPeer> peer_;
+ scoped_refptr<base::PosixDynamicThreadPool> pool_;
+ base::PosixDynamicThreadPool::PosixDynamicThreadPoolPeer peer_;
Lock counter_lock_;
int counter_;
Lock unique_threads_lock_;
@@ -158,17 +145,15 @@ class PosixDynamicThreadPoolTest : public testing::Test {
Lock num_waiting_to_start_lock_;
int num_waiting_to_start_;
ConditionVariable num_waiting_to_start_cv_;
- WaitableEvent start_;
+ base::WaitableEvent start_;
};
} // namespace
TEST_F(PosixDynamicThreadPoolTest, Basic) {
- Initialize(TimeDelta::FromSeconds(kDefaultIdleSecondsBeforeExit));
-
- EXPECT_EQ(0U, peer_->num_idle_threads());
+ EXPECT_EQ(0, peer_.num_idle_threads());
EXPECT_EQ(0U, unique_threads_.size());
- EXPECT_EQ(0U, peer_->num_pending_tasks());
+ EXPECT_EQ(0U, peer_.pending_tasks().size());
// Add one task and wait for it to be completed.
pool_->PostTask(FROM_HERE, CreateNewIncrementingTaskCallback());
@@ -181,8 +166,6 @@ TEST_F(PosixDynamicThreadPoolTest, Basic) {
}
TEST_F(PosixDynamicThreadPoolTest, ReuseIdle) {
- Initialize(TimeDelta::FromSeconds(kDefaultIdleSecondsBeforeExit));
-
// Add one task and wait for it to be completed.
pool_->PostTask(FROM_HERE, CreateNewIncrementingTaskCallback());
@@ -197,13 +180,11 @@ TEST_F(PosixDynamicThreadPoolTest, ReuseIdle) {
WaitForIdleThreads(2);
EXPECT_EQ(2U, unique_threads_.size());
- EXPECT_EQ(2U, peer_->num_idle_threads());
+ EXPECT_EQ(2, peer_.num_idle_threads());
EXPECT_EQ(3, counter_);
}
TEST_F(PosixDynamicThreadPoolTest, TwoActiveTasks) {
- Initialize(TimeDelta::FromSeconds(kDefaultIdleSecondsBeforeExit));
-
// Add two blocking tasks.
pool_->PostTask(FROM_HERE, CreateNewBlockingIncrementingTaskCallback());
pool_->PostTask(FROM_HERE, CreateNewBlockingIncrementingTaskCallback());
@@ -215,14 +196,12 @@ TEST_F(PosixDynamicThreadPoolTest, TwoActiveTasks) {
WaitForIdleThreads(2);
EXPECT_EQ(2U, unique_threads_.size());
- EXPECT_EQ(2U, peer_->num_idle_threads()) << "Existing threads are now idle.";
+ EXPECT_EQ(2, peer_.num_idle_threads()) << "Existing threads are now idle.";
EXPECT_EQ(2, counter_);
}
TEST_F(PosixDynamicThreadPoolTest, Complex) {
- Initialize(TimeDelta::FromSeconds(kDefaultIdleSecondsBeforeExit));
-
- // Add one non blocking tasks and wait for it to finish.
+ // Add two non blocking tasks and wait for them to finish.
pool_->PostTask(FROM_HERE, CreateNewIncrementingTaskCallback());
WaitForIdleThreads(1);
@@ -237,15 +216,15 @@ TEST_F(PosixDynamicThreadPoolTest, Complex) {
WaitForIdleThreads(2);
EXPECT_EQ(3, counter_);
- EXPECT_EQ(2U, peer_->num_idle_threads());
+ EXPECT_EQ(2, peer_.num_idle_threads());
EXPECT_EQ(2U, unique_threads_.size());
// Wake up all idle threads so they can exit.
{
- AutoLock locked(*peer_->lock());
- while (peer_->worker_threads().size() > 0) {
- peer_->pending_tasks_available_cv()->Signal();
- peer_->num_threads_cv()->Wait();
+ base::AutoLock locked(*peer_.lock());
+ while (peer_.num_idle_threads() > 0) {
+ peer_.pending_tasks_available_cv()->Signal();
+ peer_.num_idle_threads_cv()->Wait();
}
}
@@ -269,77 +248,8 @@ TEST_F(PosixDynamicThreadPoolTest, Complex) {
// be either 2 or 3 unique thread IDs in the set at this stage in the test.
EXPECT_TRUE(unique_threads_.size() >= 2 && unique_threads_.size() <= 3)
<< "unique_threads_.size() = " << unique_threads_.size();
- EXPECT_EQ(1U, peer_->num_idle_threads());
+ EXPECT_EQ(1, peer_.num_idle_threads());
EXPECT_EQ(4, counter_);
}
-TEST_F(PosixDynamicThreadPoolTest, NoNewThreadForCleanup) {
- // Let worker threads quit quickly after they are idle.
- Initialize(TimeDelta::FromMilliseconds(1));
-
- for (size_t i = 0; i < 2; ++i) {
- // This will create a worker thread.
- pool_->PostTask(FROM_HERE, CreateNewBlockingIncrementingTaskCallback());
-
- WaitForTasksToStart(1);
-
- PlatformThreadHandle worker;
- {
- AutoLock locked(*peer_->lock());
- ASSERT_EQ(1u, peer_->worker_threads().size());
- worker = peer_->worker_threads()[0];
- }
-
- start_.Signal();
-
- // Wait for the worker thread to quit.
- WaitForLivingThreads(0);
-
- {
- AutoLock locked(*peer_->lock());
- // The thread that just quit is recorded for cleanup. But we don't create
- // a worker thread just for doing that.
- ASSERT_EQ(1u, peer_->threads_to_cleanup().size());
- EXPECT_TRUE(worker.is_equal(peer_->threads_to_cleanup()[0]));
- EXPECT_TRUE(peer_->worker_threads().empty());
- }
- }
-
- pool_->Terminate(true);
-
- {
- AutoLock locked(*peer_->lock());
- EXPECT_TRUE(peer_->threads_to_cleanup().empty());
- EXPECT_TRUE(peer_->worker_threads().empty());
- }
-}
-
-TEST_F(PosixDynamicThreadPoolTest, BlockingTerminate) {
- // Let worker threads quit quickly after they are idle.
- Initialize(TimeDelta::FromMilliseconds(3));
-
- for (size_t i = 0; i < 5; ++i) {
- PlatformThread::Sleep(TimeDelta::FromMilliseconds(i));
- for (size_t j = 0; j < 50; ++j)
- pool_->PostTask(FROM_HERE, CreateNewIncrementingTaskCallback());
- }
-
- pool_->Terminate(true);
-
- {
- AutoLock locked(*peer_->lock());
- EXPECT_TRUE(peer_->threads_to_cleanup().empty());
- EXPECT_TRUE(peer_->worker_threads().empty());
- }
-
- int counter = counter_;
- EXPECT_GE(5 * 50, counter);
- EXPECT_GE(5 * 50u, unique_threads_.size());
-
- // Make sure that no threads are still running and trying to modify
- // |counter_|.
- PlatformThread::Sleep(TimeDelta::FromMilliseconds(10));
- EXPECT_EQ(counter, counter_);
-}
-
} // namespace base
diff --git a/chromium/base/threading/worker_pool_unittest.cc b/chromium/base/threading/worker_pool_unittest.cc
index 9a9ab951b9e..27af50be678 100644
--- a/chromium/base/threading/worker_pool_unittest.cc
+++ b/chromium/base/threading/worker_pool_unittest.cc
@@ -13,6 +13,7 @@
#include "base/test/test_timeouts.h"
#include "base/threading/thread_checker_impl.h"
#include "base/time/time.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
diff --git a/chromium/base/threading/worker_pool_win.cc b/chromium/base/threading/worker_pool_win.cc
index 563702be15b..1b0ade5e244 100644
--- a/chromium/base/threading/worker_pool_win.cc
+++ b/chromium/base/threading/worker_pool_win.cc
@@ -70,10 +70,4 @@ bool WorkerPool::RunsTasksOnCurrentThread() {
return g_worker_pool_running_on_this_thread.Get().Get();
}
-// static
-void WorkerPool::ShutDownCleanly() {
- // TODO(yzshen): implement it.
- NOTIMPLEMENTED();
-}
-
} // namespace base
diff --git a/chromium/base/time/pr_time_unittest.cc b/chromium/base/time/pr_time_unittest.cc
index 06043a5b8eb..3f1a348ae80 100644
--- a/chromium/base/time/pr_time_unittest.cc
+++ b/chromium/base/time/pr_time_unittest.cc
@@ -6,8 +6,10 @@
#include <time.h>
#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "base/third_party/nspr/prtime.h"
#include "base/time/time.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::Time;
diff --git a/chromium/base/time/time.cc b/chromium/base/time/time.cc
index 10ffcc60665..76ffeb74411 100644
--- a/chromium/base/time/time.cc
+++ b/chromium/base/time/time.cc
@@ -12,8 +12,10 @@
#include "base/lazy_instance.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/strings/stringprintf.h"
#include "base/third_party/nspr/prtime.h"
+#include "build/build_config.h"
namespace base {
@@ -21,7 +23,7 @@ namespace base {
// static
TimeDelta TimeDelta::Max() {
- return TimeDelta(std::numeric_limits<int64>::max());
+ return TimeDelta(std::numeric_limits<int64_t>::max());
}
int TimeDelta::InDays() const {
@@ -56,10 +58,10 @@ double TimeDelta::InSecondsF() const {
return static_cast<double>(delta_) / Time::kMicrosecondsPerSecond;
}
-int64 TimeDelta::InSeconds() const {
+int64_t TimeDelta::InSeconds() const {
if (is_max()) {
// Preserve max to prevent overflow.
- return std::numeric_limits<int64>::max();
+ return std::numeric_limits<int64_t>::max();
}
return delta_ / Time::kMicrosecondsPerSecond;
}
@@ -72,46 +74,46 @@ double TimeDelta::InMillisecondsF() const {
return static_cast<double>(delta_) / Time::kMicrosecondsPerMillisecond;
}
-int64 TimeDelta::InMilliseconds() const {
+int64_t TimeDelta::InMilliseconds() const {
if (is_max()) {
// Preserve max to prevent overflow.
- return std::numeric_limits<int64>::max();
+ return std::numeric_limits<int64_t>::max();
}
return delta_ / Time::kMicrosecondsPerMillisecond;
}
-int64 TimeDelta::InMillisecondsRoundedUp() const {
+int64_t TimeDelta::InMillisecondsRoundedUp() const {
if (is_max()) {
// Preserve max to prevent overflow.
- return std::numeric_limits<int64>::max();
+ return std::numeric_limits<int64_t>::max();
}
return (delta_ + Time::kMicrosecondsPerMillisecond - 1) /
Time::kMicrosecondsPerMillisecond;
}
-int64 TimeDelta::InMicroseconds() const {
+int64_t TimeDelta::InMicroseconds() const {
if (is_max()) {
// Preserve max to prevent overflow.
- return std::numeric_limits<int64>::max();
+ return std::numeric_limits<int64_t>::max();
}
return delta_;
}
namespace time_internal {
-int64 SaturatedAdd(TimeDelta delta, int64 value) {
- CheckedNumeric<int64> rv(delta.delta_);
+int64_t SaturatedAdd(TimeDelta delta, int64_t value) {
+ CheckedNumeric<int64_t> rv(delta.delta_);
rv += value;
return FromCheckedNumeric(rv);
}
-int64 SaturatedSub(TimeDelta delta, int64 value) {
- CheckedNumeric<int64> rv(delta.delta_);
+int64_t SaturatedSub(TimeDelta delta, int64_t value) {
+ CheckedNumeric<int64_t> rv(delta.delta_);
rv -= value;
return FromCheckedNumeric(rv);
}
-int64 FromCheckedNumeric(const CheckedNumeric<int64> value) {
+int64_t FromCheckedNumeric(const CheckedNumeric<int64_t> value) {
if (value.IsValid())
return value.ValueUnsafe();
@@ -119,7 +121,7 @@ int64 FromCheckedNumeric(const CheckedNumeric<int64> value) {
// 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();
+ int64_t limit = std::numeric_limits<int64_t>::max();
if (value.validity() == internal::RANGE_UNDERFLOW)
limit = -limit;
return value.ValueOrDefault(limit);
@@ -135,7 +137,7 @@ std::ostream& operator<<(std::ostream& os, TimeDelta time_delta) {
// static
Time Time::Max() {
- return Time(std::numeric_limits<int64>::max());
+ return Time(std::numeric_limits<int64_t>::max());
}
// static
@@ -154,7 +156,7 @@ time_t Time::ToTimeT() const {
// Preserve max without offset to prevent overflow.
return std::numeric_limits<time_t>::max();
}
- if (std::numeric_limits<int64>::max() - kTimeTToMicrosecondsOffset <= us_) {
+ if (std::numeric_limits<int64_t>::max() - kTimeTToMicrosecondsOffset <= us_) {
DLOG(WARNING) << "Overflow when converting base::Time with internal " <<
"value " << us_ << " to time_t.";
return std::numeric_limits<time_t>::max();
@@ -210,14 +212,14 @@ double Time::ToJsTime() const {
kMicrosecondsPerMillisecond);
}
-int64 Time::ToJavaTime() const {
+int64_t Time::ToJavaTime() const {
if (is_null()) {
// Preserve 0 so the invalid result doesn't depend on the platform.
return 0;
}
if (is_max()) {
// Preserve max without offset to prevent overflow.
- return std::numeric_limits<int64>::max();
+ return std::numeric_limits<int64_t>::max();
}
return ((us_ - kTimeTToMicrosecondsOffset) /
kMicrosecondsPerMillisecond);
@@ -326,11 +328,6 @@ std::ostream& operator<<(std::ostream& os, ThreadTicks thread_ticks) {
return os << as_time_delta.InMicroseconds() << " bogo-thread-microseconds";
}
-std::ostream& operator<<(std::ostream& os, TraceTicks trace_ticks) {
- const TimeDelta as_time_delta = trace_ticks - TraceTicks();
- return os << as_time_delta.InMicroseconds() << " bogo-trace-microseconds";
-}
-
// Time::Exploded -------------------------------------------------------------
inline bool is_in_range(int value, int lo, int hi) {
diff --git a/chromium/base/time/time.h b/chromium/base/time/time.h
index e0a6ea37eaa..066d910833d 100644
--- a/chromium/base/time/time.h
+++ b/chromium/base/time/time.h
@@ -13,13 +13,13 @@
// TimeDelta represents a duration of time, internally represented in
// microseconds.
//
-// TimeTicks, ThreadTicks, and TraceTicks represent an abstract time that is
-// most of the time incrementing, for use in measuring time durations.
-// Internally, they are represented in microseconds. They can not be converted
-// to a human-readable time, but are guaranteed not to decrease (unlike the Time
-// class). Note that TimeTicks may "stand still" (e.g., if the computer is
-// suspended), and ThreadTicks will "stand still" whenever the thread has been
-// de-scheduled by the operating system.
+// TimeTicks and ThreadTicks represent an abstract time that is most of the time
+// incrementing, for use in measuring time durations. Internally, they are
+// represented in microseconds. They can not be converted to a human-readable
+// time, but are guaranteed not to decrease (unlike the Time class). Note that
+// TimeTicks may "stand still" (e.g., if the computer is suspended), and
+// ThreadTicks will "stand still" whenever the thread has been de-scheduled by
+// the operating system.
//
// All time classes are copyable, assignable, and occupy 64-bits per
// instance. Thus, they can be efficiently passed by-value (as opposed to
@@ -45,22 +45,17 @@
//
// ThreadTicks: Benchmarking how long the current thread has been doing actual
// work.
-//
-// TraceTicks: This is only meant to be used by the event tracing
-// infrastructure, and by outside code modules in special
-// circumstances. Please be sure to consult a
-// base/trace_event/OWNER before committing any new code that
-// uses this.
#ifndef BASE_TIME_TIME_H_
#define BASE_TIME_TIME_H_
+#include <stdint.h>
#include <time.h>
#include <iosfwd>
+#include <limits>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/numerics/safe_math.h"
#include "build/build_config.h"
@@ -79,9 +74,9 @@
// For FILETIME in FromFileTime, until it moves to a new converter class.
// See TODO(iyengar) below.
#include <windows.h>
-#endif
-#include <limits>
+#include "base/gtest_prod_util.h"
+#endif
namespace base {
@@ -92,14 +87,14 @@ class TimeDelta;
// 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);
+// Add or subtract |value| from a TimeDelta. The int64_t argument and return
+// value are in terms of a microsecond timebase.
+BASE_EXPORT int64_t SaturatedAdd(TimeDelta delta, int64_t value);
+BASE_EXPORT int64_t SaturatedSub(TimeDelta delta, int64_t value);
-// Clamp |value| on overflow and underflow conditions. The int64 argument and
+// Clamp |value| on overflow and underflow conditions. The int64_t argument and
// return value are in terms of a microsecond timebase.
-BASE_EXPORT int64 FromCheckedNumeric(const CheckedNumeric<int64> value);
+BASE_EXPORT int64_t FromCheckedNumeric(const CheckedNumeric<int64_t> value);
} // namespace time_internal
@@ -114,11 +109,11 @@ class BASE_EXPORT TimeDelta {
static TimeDelta FromDays(int days);
static TimeDelta FromHours(int hours);
static TimeDelta FromMinutes(int minutes);
- static TimeDelta FromSeconds(int64 secs);
- static TimeDelta FromMilliseconds(int64 ms);
+ static TimeDelta FromSeconds(int64_t secs);
+ static TimeDelta FromMilliseconds(int64_t ms);
static TimeDelta FromSecondsD(double secs);
static TimeDelta FromMillisecondsD(double ms);
- static TimeDelta FromMicroseconds(int64 us);
+ static TimeDelta FromMicroseconds(int64_t us);
#if defined(OS_WIN)
static TimeDelta FromQPCValue(LONGLONG qpc_value);
#endif
@@ -127,9 +122,7 @@ class BASE_EXPORT TimeDelta {
// when deserializing a |TimeDelta| 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 TimeDelta FromInternalValue(int64 delta) {
- return TimeDelta(delta);
- }
+ static TimeDelta FromInternalValue(int64_t delta) { return TimeDelta(delta); }
// Returns the maximum time delta, which should be greater than any reasonable
// time delta we might compare it to. Adding or subtracting the maximum time
@@ -140,16 +133,14 @@ class BASE_EXPORT TimeDelta {
// use this and do arithmetic on it, as it is more error prone than using the
// provided operators.
// For serializing, use FromInternalValue to reconstitute.
- int64 ToInternalValue() const {
- return delta_;
- }
+ int64_t ToInternalValue() const { 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
+ // int64_t overload for std::abs(). The following is a simple branchless
// implementation:
- const int64 mask = delta_ >> (sizeof(delta_) * 8 - 1);
+ const int64_t mask = delta_ >> (sizeof(delta_) * 8 - 1);
return TimeDelta((delta_ + mask) ^ mask);
}
@@ -159,9 +150,7 @@ class BASE_EXPORT TimeDelta {
}
// Returns true if the time delta is the maximum time delta.
- bool is_max() const {
- return delta_ == std::numeric_limits<int64>::max();
- }
+ bool is_max() const { return delta_ == std::numeric_limits<int64_t>::max(); }
#if defined(OS_POSIX)
struct timespec ToTimeSpec() const;
@@ -176,11 +165,11 @@ class BASE_EXPORT TimeDelta {
int InHours() const;
int InMinutes() const;
double InSecondsF() const;
- int64 InSeconds() const;
+ int64_t InSeconds() const;
double InMillisecondsF() const;
- int64 InMilliseconds() const;
- int64 InMillisecondsRoundedUp() const;
- int64 InMicroseconds() const;
+ int64_t InMilliseconds() const;
+ int64_t InMillisecondsRoundedUp() const;
+ int64_t InMicroseconds() const;
TimeDelta& operator=(TimeDelta other) {
delta_ = other.delta_;
@@ -208,13 +197,13 @@ class BASE_EXPORT TimeDelta {
// Computations with numeric types.
template<typename T>
TimeDelta operator*(T a) const {
- CheckedNumeric<int64> rv(delta_);
+ CheckedNumeric<int64_t> rv(delta_);
rv *= a;
return TimeDelta(time_internal::FromCheckedNumeric(rv));
}
template<typename T>
TimeDelta operator/(T a) const {
- CheckedNumeric<int64> rv(delta_);
+ CheckedNumeric<int64_t> rv(delta_);
rv /= a;
return TimeDelta(time_internal::FromCheckedNumeric(rv));
}
@@ -227,9 +216,7 @@ class BASE_EXPORT TimeDelta {
return *this = (*this / a);
}
- int64 operator/(TimeDelta a) const {
- return delta_ / a.delta_;
- }
+ int64_t operator/(TimeDelta a) const { return delta_ / a.delta_; }
TimeDelta operator%(TimeDelta a) const {
return TimeDelta(delta_ % a.delta_);
}
@@ -255,20 +242,19 @@ class BASE_EXPORT TimeDelta {
}
private:
- friend int64 time_internal::SaturatedAdd(TimeDelta delta, int64 value);
- friend int64 time_internal::SaturatedSub(TimeDelta delta, int64 value);
+ friend int64_t time_internal::SaturatedAdd(TimeDelta delta, int64_t value);
+ friend int64_t time_internal::SaturatedSub(TimeDelta delta, int64_t value);
// Constructs a delta given the duration in microseconds. This is private
// to avoid confusion by callers with an integer constructor. Use
// FromSeconds, FromMilliseconds, etc. instead.
- explicit TimeDelta(int64 delta_us) : delta_(delta_us) {
- }
+ explicit TimeDelta(int64_t delta_us) : delta_(delta_us) {}
// Private method to build a delta from a double.
static TimeDelta FromDouble(double value);
// Delta in microseconds.
- int64 delta_;
+ int64_t delta_;
};
template<typename T>
@@ -293,20 +279,21 @@ namespace time_internal {
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 * kHoursPerDay;
- static const int64 kMicrosecondsPerWeek = kMicrosecondsPerDay * 7;
- static const int64 kNanosecondsPerMicrosecond = 1000;
- static const int64 kNanosecondsPerSecond = kNanosecondsPerMicrosecond *
- kMicrosecondsPerSecond;
+ static const int64_t kHoursPerDay = 24;
+ static const int64_t kMillisecondsPerSecond = 1000;
+ static const int64_t kMillisecondsPerDay =
+ kMillisecondsPerSecond * 60 * 60 * kHoursPerDay;
+ static const int64_t kMicrosecondsPerMillisecond = 1000;
+ static const int64_t kMicrosecondsPerSecond =
+ kMicrosecondsPerMillisecond * kMillisecondsPerSecond;
+ static const int64_t kMicrosecondsPerMinute = kMicrosecondsPerSecond * 60;
+ static const int64_t kMicrosecondsPerHour = kMicrosecondsPerMinute * 60;
+ static const int64_t kMicrosecondsPerDay =
+ kMicrosecondsPerHour * kHoursPerDay;
+ static const int64_t kMicrosecondsPerWeek = kMicrosecondsPerDay * 7;
+ static const int64_t kNanosecondsPerMicrosecond = 1000;
+ static const int64_t kNanosecondsPerSecond =
+ kNanosecondsPerMicrosecond * kMicrosecondsPerSecond;
// Returns true if this object has not been initialized.
//
@@ -318,16 +305,12 @@ class TimeBase {
}
// Returns true if this object represents the maximum time.
- bool is_max() const {
- return us_ == std::numeric_limits<int64>::max();
- }
+ bool is_max() const { return us_ == std::numeric_limits<int64_t>::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_;
- }
+ int64_t ToInternalValue() const { return us_; }
TimeClass& operator=(TimeClass other) {
us_ = other.us_;
@@ -379,16 +362,13 @@ class TimeBase {
// 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);
- }
+ static TimeClass FromInternalValue(int64_t us) { return TimeClass(us); }
protected:
- explicit TimeBase(int64 us) : us_(us) {
- }
+ explicit TimeBase(int64_t us) : us_(us) {}
// Time value in a microsecond timebase.
- int64 us_;
+ int64_t us_;
};
} // namespace time_internal
@@ -406,7 +386,7 @@ 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;
+ static const int64_t kTimeTToMicrosecondsOffset;
#if !defined(OS_WIN)
// On Mac & Linux, this value is the delta from the Windows epoch of 1601 to
@@ -414,12 +394,12 @@ class BASE_EXPORT Time : public time_internal::TimeBase<Time> {
// 1970-based epochs to the new 1601-based ones. It should be removed from
// this global header and put in the platform-specific ones when we remove the
// migration code.
- static const int64 kWindowsEpochDeltaMicroseconds;
+ static const int64_t kWindowsEpochDeltaMicroseconds;
#else
// To avoid overflow in QPC to Microseconds calculations, since we multiply
// by kMicrosecondsPerSecond, then the QPC value should not exceed
// (2^63 - 1) / 1E6. If it exceeds that threshold, we divide then multiply.
- static const int64 kQPCOverflowThreshold = 0x8637BD05AF7;
+ enum : int64_t{kQPCOverflowThreshold = 0x8637BD05AF7};
#endif
// Represents an exploded time that can be formatted nicely. This is kind of
@@ -494,7 +474,7 @@ class BASE_EXPORT Time : public time_internal::TimeBase<Time> {
// Converts to Java convention for times, a number of
// milliseconds since the epoch.
- int64 ToJavaTime() const;
+ int64_t ToJavaTime() const;
#if defined(OS_POSIX)
static Time FromTimeVal(struct timeval t);
@@ -573,8 +553,7 @@ class BASE_EXPORT Time : public time_internal::TimeBase<Time> {
private:
friend class time_internal::TimeBase<Time>;
- explicit Time(int64 us) : TimeBase(us) {
- }
+ explicit Time(int64_t us) : TimeBase(us) {}
// Explodes the given time to either local time |is_local = true| or UTC
// |is_local = false|.
@@ -620,12 +599,12 @@ inline TimeDelta TimeDelta::FromMinutes(int minutes) {
}
// static
-inline TimeDelta TimeDelta::FromSeconds(int64 secs) {
+inline TimeDelta TimeDelta::FromSeconds(int64_t secs) {
return TimeDelta(secs) * Time::kMicrosecondsPerSecond;
}
// static
-inline TimeDelta TimeDelta::FromMilliseconds(int64 ms) {
+inline TimeDelta TimeDelta::FromMilliseconds(int64_t ms) {
return TimeDelta(ms) * Time::kMicrosecondsPerMillisecond;
}
@@ -640,14 +619,14 @@ inline TimeDelta TimeDelta::FromMillisecondsD(double ms) {
}
// static
-inline TimeDelta TimeDelta::FromMicroseconds(int64 us) {
+inline TimeDelta TimeDelta::FromMicroseconds(int64_t us) {
return TimeDelta(us);
}
// static
inline TimeDelta TimeDelta::FromDouble(double value) {
- double max_magnitude = std::numeric_limits<int64>::max();
- TimeDelta delta = TimeDelta(static_cast<int64>(value));
+ double max_magnitude = std::numeric_limits<int64_t>::max();
+ TimeDelta delta = TimeDelta(static_cast<int64_t>(value));
if (value > max_magnitude)
delta = Max();
else if (value < -max_magnitude)
@@ -685,12 +664,14 @@ class BASE_EXPORT TimeTicks : public time_internal::TimeBase<TimeTicks> {
static TimeTicks FromQPCValue(LONGLONG qpc_value);
#endif
- // 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
- // clock to establish a reference point. This function will return the same
- // value for the duration of the application, but will be different in future
- // application runs.
+ // Get an estimate of the TimeTick value at the time of the UnixEpoch. Because
+ // Time and TimeTicks respond differently to user-set time and NTP
+ // adjustments, this number is only an estimate. Nevertheless, this can be
+ // 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 clock to establish a reference point. This function will return
+ // the same value for the duration of the application, but will be different
+ // in future application runs.
static TimeTicks UnixEpoch();
// Returns |this| snapped to the next tick, given a |tick_phase| and
@@ -710,8 +691,7 @@ class BASE_EXPORT TimeTicks : public 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) {
- }
+ explicit TimeTicks(int64_t us) : TimeBase(us) {}
};
// For logging use only.
@@ -731,16 +711,28 @@ class BASE_EXPORT ThreadTicks : public time_internal::TimeBase<ThreadTicks> {
#if (defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME >= 0)) || \
(defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_ANDROID)
return true;
+#elif defined(OS_WIN)
+ return IsSupportedWin();
#else
return false;
#endif
}
+ // Waits until the initialization is completed. Needs to be guarded with a
+ // call to IsSupported().
+ static void WaitUntilInitialized() {
+#if defined(OS_WIN)
+ WaitUntilInitializedWin();
+#endif
+ }
+
// Returns thread-specific CPU-time on systems that support this feature.
// Needs to be guarded with a call to IsSupported(). Use this timer
// 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.
+ // migrates to another CPU between two calls. Returns an empty ThreadTicks
+ // object until the initialization is completed. If a clock reading is
+ // absolutely needed, call WaitUntilInitialized() before this method.
static ThreadTicks Now();
private:
@@ -748,58 +740,24 @@ class BASE_EXPORT ThreadTicks : public time_internal::TimeBase<ThreadTicks> {
// Please use Now() to create a new object. This is for internal use
// and testing.
- explicit ThreadTicks(int64 us) : TimeBase(us) {
- }
-};
+ explicit ThreadTicks(int64_t us) : TimeBase(us) {}
-// For logging use only.
-BASE_EXPORT std::ostream& operator<<(std::ostream& os, ThreadTicks time_ticks);
+#if defined(OS_WIN)
+ FRIEND_TEST_ALL_PREFIXES(TimeTicks, TSCTicksPerSecond);
-// TraceTicks ----------------------------------------------------------------
+ // Returns the frequency of the TSC in ticks per second, or 0 if it hasn't
+ // been measured yet. Needs to be guarded with a call to IsSupported().
+ // This method is declared here rather than in the anonymous namespace to
+ // allow testing.
+ static double TSCTicksPerSecond();
-// Represents high-resolution system trace clock time.
-class BASE_EXPORT TraceTicks : public time_internal::TimeBase<TraceTicks> {
- public:
- // We define this even without OS_CHROMEOS for seccomp sandbox testing.
-#if defined(OS_LINUX)
- // Force definition of the system trace clock; it is a chromeos-only api
- // at the moment and surfacing it in the right place requires mucking
- // with glibc et al.
- static const clockid_t kClockSystemTrace = 11;
+ static bool IsSupportedWin();
+ static void WaitUntilInitializedWin();
#endif
-
- TraceTicks() : TimeBase(0) {
- }
-
- // 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).
- //
- // On some platforms, the clock source used for tracing can vary depending on
- // hardware and/or kernel support. Do not make any assumptions without
- // consulting the documentation for this functionality in the time_win.cc,
- // time_posix.cc, etc. files.
- //
- // NOTE: This is only meant to be used by the event tracing infrastructure,
- // and by outside code modules in special circumstances. Please be sure to
- // consult a base/trace_event/OWNER before committing any new code that uses
- // this.
- static TraceTicks Now();
-
- private:
- friend class time_internal::TimeBase<TraceTicks>;
-
- // Please use Now() to create a new object. This is for internal use
- // and testing.
- explicit TraceTicks(int64 us) : TimeBase(us) {
- }
};
// For logging use only.
-BASE_EXPORT std::ostream& operator<<(std::ostream& os, TraceTicks time_ticks);
+BASE_EXPORT std::ostream& operator<<(std::ostream& os, ThreadTicks time_ticks);
} // namespace base
diff --git a/chromium/base/time/time_mac.cc b/chromium/base/time/time_mac.cc
index 1dbbc3370df..f2bc5ed8c97 100644
--- a/chromium/base/time/time_mac.cc
+++ b/chromium/base/time/time_mac.cc
@@ -8,18 +8,20 @@
#include <CoreFoundation/CFTimeZone.h>
#include <mach/mach.h>
#include <mach/mach_time.h>
+#include <stddef.h>
#include <stdint.h>
#include <sys/sysctl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <time.h>
-#include "base/basictypes.h"
#include "base/logging.h"
#include "base/mac/mach_logging.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/mac/scoped_mach_port.h"
+#include "base/macros.h"
#include "base/numerics/safe_conversions.h"
+#include "build/build_config.h"
namespace {
@@ -83,7 +85,7 @@ int64_t ComputeThreadTicks() {
}
kern_return_t kr = thread_info(
- thread,
+ thread.get(),
THREAD_BASIC_INFO,
reinterpret_cast<thread_info_t>(&thread_info_data),
&thread_info_count);
@@ -117,16 +119,16 @@ namespace base {
// => Thu Jan 01 00:00:00 UTC 1970
// irb(main):011:0> Time.at(-11644473600).getutc()
// => Mon Jan 01 00:00:00 UTC 1601
-static const int64 kWindowsEpochDeltaSeconds = INT64_C(11644473600);
+static const int64_t kWindowsEpochDeltaSeconds = INT64_C(11644473600);
// static
-const int64 Time::kWindowsEpochDeltaMicroseconds =
+const int64_t Time::kWindowsEpochDeltaMicroseconds =
kWindowsEpochDeltaSeconds * Time::kMicrosecondsPerSecond;
// Some functions in time.cc use time_t directly, so we provide an offset
// to convert from time_t (Unix epoch) and internal (Windows epoch).
// static
-const int64 Time::kTimeTToMicrosecondsOffset = kWindowsEpochDeltaMicroseconds;
+const int64_t Time::kTimeTToMicrosecondsOffset = kWindowsEpochDeltaMicroseconds;
// static
Time Time::Now() {
@@ -135,20 +137,20 @@ Time Time::Now() {
// static
Time Time::FromCFAbsoluteTime(CFAbsoluteTime t) {
- COMPILE_ASSERT(std::numeric_limits<CFAbsoluteTime>::has_infinity,
- numeric_limits_infinity_is_undefined_when_not_has_infinity);
+ static_assert(std::numeric_limits<CFAbsoluteTime>::has_infinity,
+ "CFAbsoluteTime must have an infinity value");
if (t == 0)
return Time(); // Consider 0 as a null Time.
if (t == std::numeric_limits<CFAbsoluteTime>::infinity())
return Max();
- return Time(static_cast<int64>(
- (t + kCFAbsoluteTimeIntervalSince1970) * kMicrosecondsPerSecond) +
- kWindowsEpochDeltaMicroseconds);
+ return Time(static_cast<int64_t>((t + kCFAbsoluteTimeIntervalSince1970) *
+ kMicrosecondsPerSecond) +
+ kWindowsEpochDeltaMicroseconds);
}
CFAbsoluteTime Time::ToCFAbsoluteTime() const {
- COMPILE_ASSERT(std::numeric_limits<CFAbsoluteTime>::has_infinity,
- numeric_limits_infinity_is_undefined_when_not_has_infinity);
+ static_assert(std::numeric_limits<CFAbsoluteTime>::has_infinity,
+ "CFAbsoluteTime must have an infinity value");
if (is_null())
return 0; // Consider 0 as a null Time.
if (is_max())
@@ -178,14 +180,14 @@ Time Time::FromExploded(bool is_local, const Exploded& exploded) {
is_local ? CFTimeZoneCopySystem() : NULL);
CFAbsoluteTime seconds = CFGregorianDateGetAbsoluteTime(date, time_zone) +
kCFAbsoluteTimeIntervalSince1970;
- return Time(static_cast<int64>(seconds * kMicrosecondsPerSecond) +
- kWindowsEpochDeltaMicroseconds);
+ return Time(static_cast<int64_t>(seconds * kMicrosecondsPerSecond) +
+ kWindowsEpochDeltaMicroseconds);
}
void Time::Explode(bool is_local, Exploded* exploded) const {
// Avoid rounding issues, by only putting the integral number of seconds
// (rounded towards -infinity) into a |CFAbsoluteTime| (which is a |double|).
- int64 microsecond = us_ % kMicrosecondsPerSecond;
+ int64_t microsecond = us_ % kMicrosecondsPerSecond;
if (microsecond < 0)
microsecond += kMicrosecondsPerSecond;
CFAbsoluteTime seconds = ((us_ - microsecond) / kMicrosecondsPerSecond) -
@@ -231,9 +233,4 @@ ThreadTicks ThreadTicks::Now() {
return ThreadTicks(ComputeThreadTicks());
}
-// static
-TraceTicks TraceTicks::Now() {
- return TraceTicks(ComputeCurrentTicks());
-}
-
} // namespace base
diff --git a/chromium/base/time/time_posix.cc b/chromium/base/time/time_posix.cc
index fc82c620b38..4aadee618a0 100644
--- a/chromium/base/time/time_posix.cc
+++ b/chromium/base/time/time_posix.cc
@@ -15,7 +15,6 @@
#include <limits>
#include <ostream>
-#include "base/basictypes.h"
#include "base/logging.h"
#include "build/build_config.h"
@@ -80,8 +79,8 @@ void SysTimeToTimeStruct(SysTime t, struct tm* timestruct, bool is_local) {
}
#endif // OS_ANDROID
-int64 ConvertTimespecToMicros(const struct timespec& ts) {
- base::CheckedNumeric<int64> result(ts.tv_sec);
+int64_t ConvertTimespecToMicros(const struct timespec& ts) {
+ base::CheckedNumeric<int64_t> result(ts.tv_sec);
result *= base::Time::kMicrosecondsPerSecond;
result += (ts.tv_nsec / base::Time::kNanosecondsPerMicrosecond);
return result.ValueOrDie();
@@ -94,7 +93,7 @@ int64 ConvertTimespecToMicros(const struct timespec& ts) {
#if (defined(OS_POSIX) && \
defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0) || \
defined(OS_BSD) || defined(OS_ANDROID)
-int64 ClockNow(clockid_t clk_id) {
+int64_t ClockNow(clockid_t clk_id) {
struct timespec ts;
if (clock_gettime(clk_id, &ts) != 0) {
NOTREACHED() << "clock_gettime(" << clk_id << ") failed.";
@@ -112,7 +111,7 @@ int64 ClockNow(clockid_t clk_id) {
namespace base {
struct timespec TimeDelta::ToTimeSpec() const {
- int64 microseconds = InMicroseconds();
+ int64_t microseconds = InMicroseconds();
time_t seconds = 0;
if (microseconds >= Time::kMicrosecondsPerSecond) {
seconds = InSeconds();
@@ -137,16 +136,16 @@ struct timespec TimeDelta::ToTimeSpec() const {
// => Thu Jan 01 00:00:00 UTC 1970
// irb(main):011:0> Time.at(-11644473600).getutc()
// => Mon Jan 01 00:00:00 UTC 1601
-static const int64 kWindowsEpochDeltaSeconds = INT64_C(11644473600);
+static const int64_t kWindowsEpochDeltaSeconds = INT64_C(11644473600);
// static
-const int64 Time::kWindowsEpochDeltaMicroseconds =
+const int64_t Time::kWindowsEpochDeltaMicroseconds =
kWindowsEpochDeltaSeconds * Time::kMicrosecondsPerSecond;
// Some functions in time.cc use time_t directly, so we provide an offset
// to convert from time_t (Unix epoch) and internal (Windows epoch).
// static
-const int64 Time::kTimeTToMicrosecondsOffset = kWindowsEpochDeltaMicroseconds;
+const int64_t Time::kTimeTToMicrosecondsOffset = kWindowsEpochDeltaMicroseconds;
// static
Time Time::Now() {
@@ -176,9 +175,9 @@ void Time::Explode(bool is_local, Exploded* exploded) const {
// Time stores times with microsecond resolution, but Exploded only carries
// millisecond resolution, so begin by being lossy. Adjust from Windows
// epoch (1601) to Unix epoch (1970);
- int64 microseconds = us_ - kWindowsEpochDeltaMicroseconds;
+ int64_t microseconds = us_ - kWindowsEpochDeltaMicroseconds;
// The following values are all rounded towards -infinity.
- int64 milliseconds; // Milliseconds since epoch.
+ int64_t milliseconds; // Milliseconds since epoch.
SysTime seconds; // Seconds since epoch.
int millisecond; // Exploded millisecond value (0-999).
if (microseconds >= 0) {
@@ -228,8 +227,7 @@ Time Time::FromExploded(bool is_local, const Exploded& exploded) {
timestruct.tm_zone = NULL; // not a POSIX field, so mktime/timegm ignore
#endif
-
- int64 milliseconds;
+ int64_t milliseconds;
SysTime seconds;
// Certain exploded dates do not really exist due to daylight saving times,
@@ -247,11 +245,11 @@ Time Time::FromExploded(bool is_local, const Exploded& exploded) {
// to UTC 00:00:00 that isn't -1.
timestruct = timestruct0;
timestruct.tm_isdst = 0;
- int64 seconds_isdst0 = SysTimeFromTimeStruct(&timestruct, is_local);
+ int64_t seconds_isdst0 = SysTimeFromTimeStruct(&timestruct, is_local);
timestruct = timestruct0;
timestruct.tm_isdst = 1;
- int64 seconds_isdst1 = SysTimeFromTimeStruct(&timestruct, is_local);
+ int64_t seconds_isdst1 = SysTimeFromTimeStruct(&timestruct, is_local);
// seconds_isdst0 or seconds_isdst1 can be -1 for some timezones.
// E.g. "CLST" (Chile Summer Time) returns -1 for 'tm_isdt == 1'.
@@ -284,14 +282,14 @@ Time Time::FromExploded(bool is_local, const Exploded& exploded) {
// 999ms to avoid the time being less than any other possible value that
// this function can return.
- // On Android, SysTime is int64, special care must be taken to avoid
+ // On Android, SysTime is int64_t, special care must be taken to avoid
// overflows.
- const int64 min_seconds = (sizeof(SysTime) < sizeof(int64))
- ? std::numeric_limits<SysTime>::min()
- : std::numeric_limits<int32_t>::min();
- const int64 max_seconds = (sizeof(SysTime) < sizeof(int64))
- ? std::numeric_limits<SysTime>::max()
- : std::numeric_limits<int32_t>::max();
+ const int64_t min_seconds = (sizeof(SysTime) < sizeof(int64_t))
+ ? std::numeric_limits<SysTime>::min()
+ : std::numeric_limits<int32_t>::min();
+ const int64_t max_seconds = (sizeof(SysTime) < sizeof(int64_t))
+ ? std::numeric_limits<SysTime>::max()
+ : std::numeric_limits<int32_t>::max();
if (exploded.year < 1969) {
milliseconds = min_seconds * kMillisecondsPerSecond;
} else {
@@ -329,27 +327,6 @@ ThreadTicks ThreadTicks::Now() {
#endif
}
-// Use the Chrome OS specific system-wide clock.
-#if defined(OS_CHROMEOS)
-// static
-TraceTicks TraceTicks::Now() {
- struct timespec ts;
- if (clock_gettime(kClockSystemTrace, &ts) != 0) {
- // NB: fall-back for a chrome os build running on linux
- return TraceTicks(ClockNow(CLOCK_MONOTONIC));
- }
- return TraceTicks(ConvertTimespecToMicros(ts));
-}
-
-#else // !defined(OS_CHROMEOS)
-
-// static
-TraceTicks TraceTicks::Now() {
- return TraceTicks(ClockNow(CLOCK_MONOTONIC));
-}
-
-#endif // defined(OS_CHROMEOS)
-
#endif // !OS_MACOSX
// static
@@ -361,10 +338,8 @@ Time Time::FromTimeVal(struct timeval t) {
if (t.tv_usec == static_cast<suseconds_t>(Time::kMicrosecondsPerSecond) - 1 &&
t.tv_sec == std::numeric_limits<time_t>::max())
return Max();
- return Time(
- (static_cast<int64>(t.tv_sec) * Time::kMicrosecondsPerSecond) +
- t.tv_usec +
- kTimeTToMicrosecondsOffset);
+ return Time((static_cast<int64_t>(t.tv_sec) * Time::kMicrosecondsPerSecond) +
+ t.tv_usec + kTimeTToMicrosecondsOffset);
}
struct timeval Time::ToTimeVal() const {
@@ -379,7 +354,7 @@ struct timeval Time::ToTimeVal() const {
result.tv_usec = static_cast<suseconds_t>(Time::kMicrosecondsPerSecond) - 1;
return result;
}
- int64 us = us_ - kTimeTToMicrosecondsOffset;
+ int64_t us = us_ - kTimeTToMicrosecondsOffset;
result.tv_sec = us / Time::kMicrosecondsPerSecond;
result.tv_usec = us % Time::kMicrosecondsPerSecond;
return result;
diff --git a/chromium/base/time/time_unittest.cc b/chromium/base/time/time_unittest.cc
index 512fc37d3fc..8a6a7f51772 100644
--- a/chromium/base/time/time_unittest.cc
+++ b/chromium/base/time/time_unittest.cc
@@ -11,6 +11,7 @@
#include "base/compiler_specific.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/strings/stringprintf.h"
#include "base/threading/platform_thread.h"
#include "build/build_config.h"
@@ -494,7 +495,7 @@ TEST_F(TimeTest, Max) {
TEST_F(TimeTest, MaxConversions) {
Time t = Time::Max();
- EXPECT_EQ(std::numeric_limits<int64>::max(), t.ToInternalValue());
+ EXPECT_EQ(std::numeric_limits<int64_t>::max(), t.ToInternalValue());
t = Time::FromDoubleT(std::numeric_limits<double>::infinity());
EXPECT_TRUE(t.is_max());
@@ -541,7 +542,7 @@ TEST_F(TimeTest, MaxConversions) {
#if defined(OS_MACOSX)
TEST_F(TimeTest, TimeTOverflow) {
- Time t = Time::FromInternalValue(std::numeric_limits<int64>::max() - 1);
+ Time t = Time::FromInternalValue(std::numeric_limits<int64_t>::max() - 1);
EXPECT_FALSE(t.is_max());
EXPECT_EQ(std::numeric_limits<time_t>::max(), t.ToTimeT());
}
@@ -646,6 +647,7 @@ TEST(TimeTicks, HighRes) {
#endif
TEST(ThreadTicks, MAYBE_ThreadNow) {
if (ThreadTicks::IsSupported()) {
+ ThreadTicks::WaitUntilInitialized();
TimeTicks begin = TimeTicks::Now();
ThreadTicks begin_thread = ThreadTicks::Now();
// Make sure that ThreadNow value is non-zero.
@@ -664,12 +666,6 @@ TEST(ThreadTicks, MAYBE_ThreadNow) {
}
}
-TEST(TraceTicks, NowFromSystemTraceTime) {
- // Re-use HighRes test for now since clock properties are identical.
- using NowFunction = TimeTicks (*)(void);
- HighResClockTest(reinterpret_cast<NowFunction>(&TraceTicks::Now));
-}
-
TEST(TimeTicks, SnappedToNextTickBasic) {
base::TimeTicks phase = base::TimeTicks::FromInternalValue(4000);
base::TimeDelta interval = base::TimeDelta::FromMicroseconds(1000);
@@ -804,19 +800,19 @@ std::string AnyToString(Any any) {
}
TEST(TimeDelta, Magnitude) {
- const int64 zero = 0;
+ const int64_t zero = 0;
EXPECT_EQ(TimeDelta::FromMicroseconds(zero),
TimeDelta::FromMicroseconds(zero).magnitude());
- const int64 one = 1;
- const int64 negative_one = -1;
+ const int64_t one = 1;
+ const int64_t 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;
+ const int64_t max_int64_minus_one = std::numeric_limits<int64_t>::max() - 1;
+ const int64_t min_int64_plus_two = std::numeric_limits<int64_t>::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),
@@ -837,16 +833,16 @@ bool IsMin(TimeDelta delta) {
TEST(TimeDelta, MaxConversions) {
TimeDelta t = TimeDelta::Max();
- EXPECT_EQ(std::numeric_limits<int64>::max(), t.ToInternalValue());
+ EXPECT_EQ(std::numeric_limits<int64_t>::max(), t.ToInternalValue());
EXPECT_EQ(std::numeric_limits<int>::max(), t.InDays());
EXPECT_EQ(std::numeric_limits<int>::max(), t.InHours());
EXPECT_EQ(std::numeric_limits<int>::max(), t.InMinutes());
EXPECT_EQ(std::numeric_limits<double>::infinity(), t.InSecondsF());
- EXPECT_EQ(std::numeric_limits<int64>::max(), t.InSeconds());
+ EXPECT_EQ(std::numeric_limits<int64_t>::max(), t.InSeconds());
EXPECT_EQ(std::numeric_limits<double>::infinity(), t.InMillisecondsF());
- EXPECT_EQ(std::numeric_limits<int64>::max(), t.InMilliseconds());
- EXPECT_EQ(std::numeric_limits<int64>::max(), t.InMillisecondsRoundedUp());
+ EXPECT_EQ(std::numeric_limits<int64_t>::max(), t.InMilliseconds());
+ EXPECT_EQ(std::numeric_limits<int64_t>::max(), t.InMillisecondsRoundedUp());
t = TimeDelta::FromDays(std::numeric_limits<int>::max());
EXPECT_TRUE(t.is_max());
@@ -857,7 +853,7 @@ TEST(TimeDelta, MaxConversions) {
t = TimeDelta::FromMinutes(std::numeric_limits<int>::max());
EXPECT_TRUE(t.is_max());
- int64 max_int = std::numeric_limits<int64>::max();
+ int64_t max_int = std::numeric_limits<int64_t>::max();
t = TimeDelta::FromSeconds(max_int / Time::kMicrosecondsPerSecond + 1);
EXPECT_TRUE(t.is_max());
@@ -877,7 +873,7 @@ TEST(TimeDelta, MaxConversions) {
t = TimeDelta::FromMicroseconds(-max_int);
EXPECT_TRUE(IsMin(t));
- t = -TimeDelta::FromMicroseconds(std::numeric_limits<int64>::min());
+ t = -TimeDelta::FromMicroseconds(std::numeric_limits<int64_t>::min());
EXPECT_FALSE(IsMin(t));
t = TimeDelta::FromSecondsD(std::numeric_limits<double>::infinity());
diff --git a/chromium/base/time/time_win.cc b/chromium/base/time/time_win.cc
index 4543680741f..dc968ad6398 100644
--- a/chromium/base/time/time_win.cc
+++ b/chromium/base/time/time_win.cc
@@ -38,7 +38,7 @@
#include <mmsystem.h>
#include <stdint.h>
-#include "base/basictypes.h"
+#include "base/bit_cast.h"
#include "base/cpu.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
@@ -48,29 +48,28 @@ using base::ThreadTicks;
using base::Time;
using base::TimeDelta;
using base::TimeTicks;
-using base::TraceTicks;
namespace {
// From MSDN, FILETIME "Contains a 64-bit value representing the number of
// 100-nanosecond intervals since January 1, 1601 (UTC)."
-int64 FileTimeToMicroseconds(const FILETIME& ft) {
+int64_t FileTimeToMicroseconds(const FILETIME& ft) {
// Need to bit_cast to fix alignment, then divide by 10 to convert
- // 100-nanoseconds to milliseconds. This only works on little-endian
+ // 100-nanoseconds to microseconds. This only works on little-endian
// machines.
- return bit_cast<int64, FILETIME>(ft) / 10;
+ return bit_cast<int64_t, FILETIME>(ft) / 10;
}
-void MicrosecondsToFileTime(int64 us, FILETIME* ft) {
+void MicrosecondsToFileTime(int64_t us, FILETIME* ft) {
DCHECK_GE(us, 0LL) << "Time is less than 0, negative values are not "
"representable in FILETIME";
- // Multiply by 10 to convert milliseconds to 100-nanoseconds. Bit_cast will
+ // Multiply by 10 to convert microseconds to 100-nanoseconds. Bit_cast will
// handle alignment problems. This only works on little-endian machines.
- *ft = bit_cast<FILETIME, int64>(us * 10);
+ *ft = bit_cast<FILETIME, int64_t>(us * 10);
}
-int64 CurrentWallclockMicroseconds() {
+int64_t CurrentWallclockMicroseconds() {
FILETIME ft;
::GetSystemTimeAsFileTime(&ft);
return FileTimeToMicroseconds(ft);
@@ -79,7 +78,7 @@ int64 CurrentWallclockMicroseconds() {
// Time between resampling the un-granular clock for this API. 60 seconds.
const int kMaxMillisecondsToAvoidDrift = 60 * Time::kMillisecondsPerSecond;
-int64 initial_time = 0;
+int64_t initial_time = 0;
TimeTicks initial_ticks;
void InitializeClock() {
@@ -100,6 +99,26 @@ uint32_t g_high_res_timer_count = 0;
base::LazyInstance<base::Lock>::Leaky g_high_res_lock =
LAZY_INSTANCE_INITIALIZER;
+// Returns a pointer to the QueryThreadCycleTime() function from Windows.
+// Can't statically link to it because it is not available on XP.
+using QueryThreadCycleTimePtr = decltype(::QueryThreadCycleTime)*;
+QueryThreadCycleTimePtr GetQueryThreadCycleTimeFunction() {
+ static const QueryThreadCycleTimePtr query_thread_cycle_time_fn =
+ reinterpret_cast<QueryThreadCycleTimePtr>(::GetProcAddress(
+ ::GetModuleHandle(L"kernel32.dll"), "QueryThreadCycleTime"));
+ return query_thread_cycle_time_fn;
+}
+
+// Returns the current value of the performance counter.
+uint64_t QPCNowRaw() {
+ LARGE_INTEGER perf_counter_now = {};
+ // According to the MSDN documentation for QueryPerformanceCounter(), this
+ // will never fail on systems that run XP or later.
+ // https://msdn.microsoft.com/library/windows/desktop/ms644904.aspx
+ ::QueryPerformanceCounter(&perf_counter_now);
+ return perf_counter_now.QuadPart;
+}
+
} // namespace
// Time -----------------------------------------------------------------------
@@ -109,7 +128,7 @@ base::LazyInstance<base::Lock>::Leaky g_high_res_lock =
// number of leap year days between 1601 and 1970: (1970-1601)/4 excluding
// 1700, 1800, and 1900.
// static
-const int64 Time::kTimeTToMicrosecondsOffset = INT64_C(11644473600000000);
+const int64_t Time::kTimeTToMicrosecondsOffset = INT64_C(11644473600000000);
// static
Time Time::Now() {
@@ -151,7 +170,7 @@ Time Time::NowFromSystemTime() {
// static
Time Time::FromFileTime(FILETIME ft) {
- if (bit_cast<int64, FILETIME>(ft) == 0)
+ if (bit_cast<int64_t, FILETIME>(ft) == 0)
return Time();
if (ft.dwHighDateTime == std::numeric_limits<DWORD>::max() &&
ft.dwLowDateTime == std::numeric_limits<DWORD>::max())
@@ -161,7 +180,7 @@ Time Time::FromFileTime(FILETIME ft) {
FILETIME Time::ToFileTime() const {
if (is_null())
- return bit_cast<FILETIME, int64>(0);
+ return bit_cast<FILETIME, int64_t>(0);
if (is_max()) {
FILETIME result;
result.dwHighDateTime = std::numeric_limits<DWORD>::max();
@@ -313,7 +332,7 @@ DWORD timeGetTimeWrapper() {
DWORD (*g_tick_function)(void) = &timeGetTimeWrapper;
// Accumulation of time lost due to rollover (in milliseconds).
-int64 g_rollover_ms = 0;
+int64_t g_rollover_ms = 0;
// The last timeGetTime value we saw, to detect rollover.
DWORD g_last_seen_now = 0;
@@ -384,7 +403,7 @@ TimeDelta InitialNowFunction();
// See "threading notes" in InitializeNowFunctionPointer() for details on how
// concurrent reads/writes to these globals has been made safe.
NowFunction g_now_function = &InitialNowFunction;
-int64 g_qpc_ticks_per_second = 0;
+int64_t 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
@@ -406,8 +425,8 @@ TimeDelta QPCValueToTimeDelta(LONGLONG qpc_value) {
}
// 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);
+ int64_t whole_seconds = qpc_value / g_qpc_ticks_per_second;
+ int64_t leftover_ticks = qpc_value - (whole_seconds * g_qpc_ticks_per_second);
return TimeDelta::FromMicroseconds(
(whole_seconds * Time::kMicrosecondsPerSecond) +
((leftover_ticks * Time::kMicrosecondsPerSecond) /
@@ -415,9 +434,7 @@ TimeDelta QPCValueToTimeDelta(LONGLONG qpc_value) {
}
TimeDelta QPCNow() {
- LARGE_INTEGER now;
- QueryPerformanceCounter(&now);
- return QPCValueToTimeDelta(now.QuadPart);
+ return QPCValueToTimeDelta(QPCNowRaw());
}
bool IsBuggyAthlon(const base::CPU& cpu) {
@@ -441,14 +458,6 @@ void InitializeNowFunctionPointer() {
//
// Otherwise, Now uses the high-resolution QPC clock. As of 21 August 2015,
// ~72% of users fall within this category.
- //
- // TraceTicks::Now() always uses the same clock as TimeTicks::Now(), even
- // when the QPC exists but is expensive or unreliable. This is because we'd
- // eventually like to merge TraceTicks and TimeTicks and have one type of
- // timestamp that is reliable, monotonic, and comparable. Also, while we could
- // use the high-resolution timer for TraceTicks even when it's unreliable or
- // slow, it's easier to make tracing tools accommodate a coarse timer than
- // one that's unreliable or slow.
NowFunction now_function;
base::CPU cpu;
if (ticks_per_sec.QuadPart <= 0 ||
@@ -504,13 +513,94 @@ bool TimeTicks::IsHighResolution() {
// static
ThreadTicks ThreadTicks::Now() {
- NOTREACHED();
- return ThreadTicks();
+ DCHECK(IsSupported());
+
+ // Get the number of TSC ticks used by the current thread.
+ ULONG64 thread_cycle_time = 0;
+ GetQueryThreadCycleTimeFunction()(::GetCurrentThread(), &thread_cycle_time);
+
+ // Get the frequency of the TSC.
+ double tsc_ticks_per_second = TSCTicksPerSecond();
+ if (tsc_ticks_per_second == 0)
+ return ThreadTicks();
+
+ // Return the CPU time of the current thread.
+ double thread_time_seconds = thread_cycle_time / tsc_ticks_per_second;
+ return ThreadTicks(
+ static_cast<int64_t>(thread_time_seconds * Time::kMicrosecondsPerSecond));
+}
+
+// static
+bool ThreadTicks::IsSupportedWin() {
+ static bool is_supported = GetQueryThreadCycleTimeFunction() &&
+ base::CPU().has_non_stop_time_stamp_counter() &&
+ !IsBuggyAthlon(base::CPU());
+ return is_supported;
}
// static
-TraceTicks TraceTicks::Now() {
- return TraceTicks() + g_now_function();
+void ThreadTicks::WaitUntilInitializedWin() {
+ while (TSCTicksPerSecond() == 0)
+ ::Sleep(10);
+}
+
+double ThreadTicks::TSCTicksPerSecond() {
+ DCHECK(IsSupported());
+
+ // The value returned by QueryPerformanceFrequency() cannot be used as the TSC
+ // frequency, because there is no guarantee that the TSC frequency is equal to
+ // the performance counter frequency.
+
+ // The TSC frequency is cached in a static variable because it takes some time
+ // to compute it.
+ static double tsc_ticks_per_second = 0;
+ if (tsc_ticks_per_second != 0)
+ return tsc_ticks_per_second;
+
+ // Increase the thread priority to reduces the chances of having a context
+ // switch during a reading of the TSC and the performance counter.
+ int previous_priority = ::GetThreadPriority(::GetCurrentThread());
+ ::SetThreadPriority(::GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
+
+ // The first time that this function is called, make an initial reading of the
+ // TSC and the performance counter.
+ static const uint64_t tsc_initial = __rdtsc();
+ static const uint64_t perf_counter_initial = QPCNowRaw();
+
+ // Make a another reading of the TSC and the performance counter every time
+ // that this function is called.
+ uint64_t tsc_now = __rdtsc();
+ uint64_t perf_counter_now = QPCNowRaw();
+
+ // Reset the thread priority.
+ ::SetThreadPriority(::GetCurrentThread(), previous_priority);
+
+ // Make sure that at least 50 ms elapsed between the 2 readings. The first
+ // time that this function is called, we don't expect this to be the case.
+ // Note: The longer the elapsed time between the 2 readings is, the more
+ // accurate the computed TSC frequency will be. The 50 ms value was
+ // chosen because local benchmarks show that it allows us to get a
+ // stddev of less than 1 tick/us between multiple runs.
+ // Note: According to the MSDN documentation for QueryPerformanceFrequency(),
+ // this will never fail on systems that run XP or later.
+ // https://msdn.microsoft.com/library/windows/desktop/ms644905.aspx
+ LARGE_INTEGER perf_counter_frequency = {};
+ ::QueryPerformanceFrequency(&perf_counter_frequency);
+ DCHECK_GE(perf_counter_now, perf_counter_initial);
+ uint64_t perf_counter_ticks = perf_counter_now - perf_counter_initial;
+ double elapsed_time_seconds =
+ perf_counter_ticks / static_cast<double>(perf_counter_frequency.QuadPart);
+
+ const double kMinimumEvaluationPeriodSeconds = 0.05;
+ if (elapsed_time_seconds < kMinimumEvaluationPeriodSeconds)
+ return 0;
+
+ // Compute the frequency of the TSC.
+ DCHECK_GE(tsc_now, tsc_initial);
+ uint64_t tsc_ticks = tsc_now - tsc_initial;
+ tsc_ticks_per_second = tsc_ticks / elapsed_time_seconds;
+
+ return tsc_ticks_per_second;
}
// static
diff --git a/chromium/base/time/time_win_unittest.cc b/chromium/base/time/time_win_unittest.cc
index 75b237ed65d..ad5e0beb40a 100644
--- a/chromium/base/time/time_win_unittest.cc
+++ b/chromium/base/time/time_win_unittest.cc
@@ -5,6 +5,7 @@
#include <windows.h>
#include <mmsystem.h>
#include <process.h>
+#include <stdint.h>
#include <cmath>
#include <limits>
@@ -12,13 +13,10 @@
#include "base/threading/platform_thread.h"
#include "base/time/time.h"
+#include "base/win/registry.h"
#include "testing/gtest/include/gtest/gtest.h"
-using base::Time;
-using base::TimeDelta;
-using base::TimeTicks;
-using base::TraceTicks;
-
+namespace base {
namespace {
class MockTimeTicks : public TimeTicks {
@@ -47,14 +45,14 @@ MockTimeTicks::TickFunctionType MockTimeTicks::old_tick_function_;
HANDLE g_rollover_test_start;
unsigned __stdcall RolloverTestThreadMain(void* param) {
- int64 counter = reinterpret_cast<int64>(param);
+ int64_t counter = reinterpret_cast<int64_t>(param);
DWORD rv = WaitForSingleObject(g_rollover_test_start, INFINITE);
EXPECT_EQ(rv, WAIT_OBJECT_0);
TimeTicks last = TimeTicks::Now();
for (int index = 0; index < counter; index++) {
TimeTicks now = TimeTicks::Now();
- int64 milliseconds = (now - last).InMilliseconds();
+ int64_t milliseconds = (now - last).InMilliseconds();
// This is a tight loop; we could have looped faster than our
// measurements, so the time might be 0 millis.
EXPECT_GE(milliseconds, 0);
@@ -66,7 +64,14 @@ unsigned __stdcall RolloverTestThreadMain(void* param) {
} // namespace
-TEST(TimeTicks, WinRollover) {
+// This test spawns many threads, and can occasionally fail due to resource
+// exhaustion in the presence of ASan.
+#if defined(ADDRESS_SANITIZER)
+#define MAYBE_WinRollover DISABLED_WinRollover
+#else
+#define MAYBE_WinRollover WinRollover
+#endif
+TEST(TimeTicks, MAYBE_WinRollover) {
// The internal counter rolls over at ~49days. We'll use a mock
// timer to test this case.
// Basic test algorithm:
@@ -77,8 +82,8 @@ TEST(TimeTicks, WinRollover) {
// 5) Each thread verifies integrity of result.
const int kThreads = 8;
- // Use int64 so we can cast into a void* without a compiler warning.
- const int64 kChecks = 10;
+ // Use int64_t so we can cast into a void* without a compiler warning.
+ const int64_t kChecks = 10;
// It takes a lot of iterations to reproduce the bug!
// (See bug 1081395)
@@ -146,11 +151,7 @@ TEST(TimeTicks, TimeGetTimeCaps) {
TIMECAPS caps;
MMRESULT status = timeGetDevCaps(&caps, sizeof(caps));
- EXPECT_EQ(TIMERR_NOERROR, status);
- if (status != TIMERR_NOERROR) {
- printf("Could not get timeGetDevCaps\n");
- return;
- }
+ ASSERT_EQ(static_cast<MMRESULT>(MMSYSERR_NOERROR), status);
EXPECT_GE(static_cast<int>(caps.wPeriodMin), 1);
EXPECT_GT(static_cast<int>(caps.wPeriodMax), 1);
@@ -183,20 +184,22 @@ TEST(TimeTicks, TimerPerformance) {
};
// Cheating a bit here: assumes sizeof(TimeTicks) == sizeof(Time)
// in order to create a single test case list.
- COMPILE_ASSERT(sizeof(TimeTicks) == sizeof(Time),
- test_only_works_with_same_sizes);
- TestCase cases[] = {
- { reinterpret_cast<TestFunc>(&Time::Now), "Time::Now" },
- { &TimeTicks::Now, "TimeTicks::Now" },
- { reinterpret_cast<TestFunc>(&TraceTicks::Now), "TraceTicks::Now" },
- { NULL, "" }
- };
+ static_assert(sizeof(TimeTicks) == sizeof(Time),
+ "TimeTicks and Time must be the same size");
+ std::vector<TestCase> cases;
+ cases.push_back({reinterpret_cast<TestFunc>(&Time::Now), "Time::Now"});
+ cases.push_back({&TimeTicks::Now, "TimeTicks::Now"});
+
+ if (ThreadTicks::IsSupported()) {
+ ThreadTicks::WaitUntilInitialized();
+ cases.push_back(
+ {reinterpret_cast<TestFunc>(&ThreadTicks::Now), "ThreadTicks::Now"});
+ }
- int test_case = 0;
- while (cases[test_case].func) {
+ for (const auto& test_case : cases) {
TimeTicks start = TimeTicks::Now();
for (int index = 0; index < kLoops; index++)
- cases[test_case].func();
+ test_case.func();
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
@@ -206,9 +209,29 @@ TEST(TimeTicks, TimerPerformance) {
// slow, and there is really no value for checking against a max timer.
//const int kMaxTime = 35; // Maximum acceptible milliseconds for test.
//EXPECT_LT((stop - start).InMilliseconds(), kMaxTime);
- printf("%s: %1.2fus per call\n", cases[test_case].description,
- (stop - start).InMillisecondsF() * 1000 / kLoops);
- test_case++;
+ printf("%s: %1.2fus per call\n", test_case.description,
+ (stop - start).InMillisecondsF() * 1000 / kLoops);
+ }
+}
+
+TEST(TimeTicks, TSCTicksPerSecond) {
+ if (ThreadTicks::IsSupported()) {
+ ThreadTicks::WaitUntilInitialized();
+
+ // Read the CPU frequency from the registry.
+ base::win::RegKey processor_key(
+ HKEY_LOCAL_MACHINE,
+ L"Hardware\\Description\\System\\CentralProcessor\\0", KEY_QUERY_VALUE);
+ ASSERT_TRUE(processor_key.Valid());
+ DWORD processor_mhz_from_registry;
+ ASSERT_EQ(ERROR_SUCCESS,
+ processor_key.ReadValueDW(L"~MHz", &processor_mhz_from_registry));
+
+ // Expect the measured TSC frequency to be similar to the processor
+ // frequency from the registry (0.5% error).
+ double tsc_mhz_measured = ThreadTicks::TSCTicksPerSecond() / 1e6;
+ EXPECT_NEAR(tsc_mhz_measured, processor_mhz_from_registry,
+ 0.005 * processor_mhz_from_registry);
}
}
@@ -218,18 +241,18 @@ TEST(TimeTicks, FromQPCValue) {
LARGE_INTEGER frequency;
ASSERT_TRUE(QueryPerformanceFrequency(&frequency));
- const int64 ticks_per_second = frequency.QuadPart;
+ const int64_t 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;
+ std::vector<int64_t> test_cases;
test_cases.push_back(0);
const int kNumAdvancements = 100;
- int64 ticks = 0;
- int64 ticks_increment = 10;
+ int64_t ticks = 0;
+ int64_t ticks_increment = 10;
for (int i = 0; i < kNumAdvancements; ++i) {
test_cases.push_back(ticks);
ticks += ticks_increment;
@@ -245,14 +268,14 @@ TEST(TimeTicks, FromQPCValue) {
ticks += ticks_increment;
ticks_increment = ticks_increment * 6 / 5;
}
- test_cases.push_back(std::numeric_limits<int64>::max());
+ test_cases.push_back(std::numeric_limits<int64_t>::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) {
+ for (int64_t ticks : test_cases) {
const double expected_microseconds_since_origin =
(static_cast<double>(ticks) * Time::kMicrosecondsPerSecond) /
ticks_per_second;
@@ -266,3 +289,5 @@ TEST(TimeTicks, FromQPCValue) {
<< (ticks < Time::kQPCOverflowThreshold ? "FAST" : "SAFE");
}
}
+
+} // namespace base
diff --git a/chromium/base/timer/hi_res_timer_manager.h b/chromium/base/timer/hi_res_timer_manager.h
index ed0e1e04ad3..21cdfafb6ca 100644
--- a/chromium/base/timer/hi_res_timer_manager.h
+++ b/chromium/base/timer/hi_res_timer_manager.h
@@ -6,7 +6,7 @@
#define BASE_TIMER_HI_RES_TIMER_MANAGER_H_
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/power_monitor/power_observer.h"
namespace base {
diff --git a/chromium/base/timer/hi_res_timer_manager_unittest.cc b/chromium/base/timer/hi_res_timer_manager_unittest.cc
index 5475a91446b..94160486f9f 100644
--- a/chromium/base/timer/hi_res_timer_manager_unittest.cc
+++ b/chromium/base/timer/hi_res_timer_manager_unittest.cc
@@ -4,11 +4,14 @@
#include "base/timer/hi_res_timer_manager.h"
+#include <utility>
+
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/power_monitor/power_monitor.h"
#include "base/power_monitor/power_monitor_device_source.h"
#include "base/time/time.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
@@ -22,7 +25,7 @@ TEST(HiResTimerManagerTest, ToggleOnOff) {
scoped_ptr<base::PowerMonitorSource> power_monitor_source(
new base::PowerMonitorDeviceSource());
scoped_ptr<base::PowerMonitor> power_monitor(
- new base::PowerMonitor(power_monitor_source.Pass()));
+ new base::PowerMonitor(std::move(power_monitor_source)));
HighResolutionTimerManager manager;
// Simulate a on-AC power event to get to a known initial state.
diff --git a/chromium/base/timer/mock_timer_unittest.cc b/chromium/base/timer/mock_timer_unittest.cc
index f6b6953648a..a38981513a4 100644
--- a/chromium/base/timer/mock_timer_unittest.cc
+++ b/chromium/base/timer/mock_timer_unittest.cc
@@ -4,6 +4,7 @@
#include "base/timer/mock_timer.h"
+#include "base/macros.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
diff --git a/chromium/base/timer/timer.h b/chromium/base/timer/timer.h
index c5bd9ced5ae..661829b513d 100644
--- a/chromium/base/timer/timer.h
+++ b/chromium/base/timer/timer.h
@@ -50,11 +50,11 @@
// should be able to tell the difference.
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/location.h"
+#include "base/macros.h"
#include "base/time/time.h"
namespace base {
diff --git a/chromium/base/timer/timer_unittest.cc b/chromium/base/timer/timer_unittest.cc
index 35e4315ea46..b1d3c3e9323 100644
--- a/chromium/base/timer/timer_unittest.cc
+++ b/chromium/base/timer/timer_unittest.cc
@@ -2,10 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
+
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/test/test_simple_task_runner.h"
#include "base/timer/timer.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::TimeDelta;
diff --git a/chromium/base/tools_sanity_unittest.cc b/chromium/base/tools_sanity_unittest.cc
index 4340fcd9ba5..8d13837887b 100644
--- a/chromium/base/tools_sanity_unittest.cc
+++ b/chromium/base/tools_sanity_unittest.cc
@@ -6,12 +6,15 @@
// crashes if the test is ran without special memory testing tools. We use these
// errors to verify the sanity of the tools.
+#include <stddef.h>
+
#include "base/atomicops.h"
#include "base/debug/asan_invalid_access.h"
#include "base/debug/profiler.h"
#include "base/message_loop/message_loop.h"
#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
#include "base/threading/thread.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
diff --git a/chromium/base/trace_event/BUILD.gn b/chromium/base/trace_event/BUILD.gn
deleted file mode 100644
index a55c55d75ce..00000000000
--- a/chromium/base/trace_event/BUILD.gn
+++ /dev/null
@@ -1,127 +0,0 @@
-# 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_allocator_dump_guid.cc",
- "memory_allocator_dump_guid.h",
- "memory_dump_manager.cc",
- "memory_dump_manager.h",
- "memory_dump_provider.h",
- "memory_dump_request_args.cc",
- "memory_dump_request_args.h",
- "memory_dump_session_state.cc",
- "memory_dump_session_state.h",
- "memory_profiler_allocation_context.cc",
- "memory_profiler_allocation_context.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_buffer.cc",
- "trace_buffer.h",
- "trace_config.cc",
- "trace_config.h",
- "trace_event.h",
- "trace_event_android.cc",
- "trace_event_argument.cc",
- "trace_event_argument.h",
- "trace_event_common.h",
- "trace_event_etw_export_win.cc",
- "trace_event_etw_export_win.h",
- "trace_event_impl.cc",
- "trace_event_impl.h",
- "trace_event_memory.cc",
- "trace_event_memory.h",
- "trace_event_memory_overhead.cc",
- "trace_event_memory_overhead.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",
- "trace_log.cc",
- "trace_log.h",
- "trace_log_constants.cc",
- "trace_sampling_thread.cc",
- "trace_sampling_thread.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",
- "memory_profiler_allocation_context_unittest.cc",
- "process_memory_dump_unittest.cc",
- "process_memory_maps_dump_provider_unittest.cc",
- "process_memory_totals_dump_provider_unittest.cc",
- "trace_config_memory_test_util.h",
- "trace_config_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
index 5136401580d..9160267beaa 100644
--- a/chromium/base/trace_event/OWNERS
+++ b/chromium/base/trace_event/OWNERS
@@ -1,5 +1,6 @@
-nduca@chromium.org
dsinclair@chromium.org
+nduca@chromium.org
+oysteine@chromium.org
primiano@chromium.org
simonhatch@chromium.org
per-file trace_event_android.cc=wangxianzhu@chromium.org
diff --git a/chromium/base/trace_event/trace_event_common.h b/chromium/base/trace_event/common/trace_event_common.h
index aa5a4935362..a266cd53dab 100644
--- a/chromium/base/trace_event/trace_event_common.h
+++ b/chromium/base/trace_event/common/trace_event_common.h
@@ -203,40 +203,26 @@
// - category and name strings must have application lifetime (statics or
// literals). They may not include " chars.
#define TRACE_EVENT0(category_group, name) \
- INTERNAL_TRACE_MEMORY(category_group, name) \
INTERNAL_TRACE_EVENT_ADD_SCOPED(category_group, name)
#define TRACE_EVENT_WITH_FLOW0(category_group, name, bind_id, flow_flags) \
- INTERNAL_TRACE_MEMORY(category_group, name) \
INTERNAL_TRACE_EVENT_ADD_SCOPED_WITH_FLOW(category_group, name, bind_id, \
flow_flags)
#define TRACE_EVENT1(category_group, name, arg1_name, arg1_val) \
- INTERNAL_TRACE_MEMORY(category_group, name) \
INTERNAL_TRACE_EVENT_ADD_SCOPED(category_group, name, arg1_name, arg1_val)
#define TRACE_EVENT_WITH_FLOW1(category_group, name, bind_id, flow_flags, \
arg1_name, arg1_val) \
- INTERNAL_TRACE_MEMORY(category_group, name) \
INTERNAL_TRACE_EVENT_ADD_SCOPED_WITH_FLOW(category_group, name, bind_id, \
flow_flags, arg1_name, arg1_val)
#define TRACE_EVENT2(category_group, name, arg1_name, arg1_val, arg2_name, \
arg2_val) \
- INTERNAL_TRACE_MEMORY(category_group, name) \
INTERNAL_TRACE_EVENT_ADD_SCOPED(category_group, name, arg1_name, arg1_val, \
arg2_name, arg2_val)
#define TRACE_EVENT_WITH_FLOW2(category_group, name, bind_id, flow_flags, \
arg1_name, arg1_val, arg2_name, arg2_val) \
- INTERNAL_TRACE_MEMORY(category_group, name) \
INTERNAL_TRACE_EVENT_ADD_SCOPED_WITH_FLOW(category_group, name, bind_id, \
flow_flags, arg1_name, arg1_val, \
arg2_name, arg2_val)
-// Records events like TRACE_EVENT2 but uses |memory_tag| for memory tracing.
-// Use this where |name| is too generic to accurately aggregate allocations.
-#define TRACE_EVENT_WITH_MEMORY_TAG2(category, name, memory_tag, arg1_name, \
- arg1_val, arg2_name, arg2_val) \
- INTERNAL_TRACE_MEMORY(category, memory_tag) \
- INTERNAL_TRACE_EVENT_ADD_SCOPED(category, name, arg1_name, arg1_val, \
- arg2_name, arg2_val)
-
// UNSHIPPED_TRACE_EVENT* are like TRACE_EVENT* except that they are not
// included in official builds.
@@ -309,6 +295,12 @@
TRACE_EVENT_FLAG_COPY | scope, arg1_name, arg1_val, \
arg2_name, arg2_val)
+#define TRACE_EVENT_INSTANT_WITH_TIMESTAMP0(category_group, name, scope, \
+ timestamp) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+ TRACE_EVENT_PHASE_INSTANT, category_group, name, 0, 0, timestamp, \
+ TRACE_EVENT_FLAG_NONE | scope)
+
// Syntactic sugars for the sampling tracing in the main thread.
#define TRACE_EVENT_SCOPED_SAMPLING_STATE(category, name) \
TRACE_EVENT_SCOPED_SAMPLING_STATE_FOR_BUCKET(0, category, name)
@@ -403,23 +395,20 @@
TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \
arg2_name, arg2_val)
-#define TRACE_EVENT_MARK(category_group, name) \
- INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_MARK, category_group, name, \
- TRACE_EVENT_FLAG_NONE)
-
-#define TRACE_EVENT_MARK_WITH_TIMESTAMP(category_group, name, timestamp) \
- INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP(TRACE_EVENT_PHASE_MARK, \
- category_group, name, timestamp, \
- TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_MARK_WITH_TIMESTAMP1(category_group, name, timestamp, \
+ arg1_name, arg1_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+ TRACE_EVENT_PHASE_MARK, category_group, name, 0, 0, timestamp, \
+ TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
#define TRACE_EVENT_COPY_MARK(category_group, name) \
INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_MARK, category_group, name, \
TRACE_EVENT_FLAG_COPY)
#define TRACE_EVENT_COPY_MARK_WITH_TIMESTAMP(category_group, name, timestamp) \
- INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP(TRACE_EVENT_PHASE_MARK, \
- category_group, name, timestamp, \
- TRACE_EVENT_FLAG_COPY)
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+ TRACE_EVENT_PHASE_MARK, category_group, name, 0, 0, timestamp, \
+ TRACE_EVENT_FLAG_COPY)
// Similar to TRACE_EVENT_ENDx but with a custom |at| timestamp provided.
// - |id| is used to match the _BEGIN event with the _END event.
@@ -481,6 +470,20 @@
static_cast<int>(value1_val), value2_name, \
static_cast<int>(value2_val))
+// Similar to TRACE_COUNTERx, but with a custom |timestamp| provided.
+#define TRACE_COUNTER_WITH_TIMESTAMP1(category_group, name, timestamp, value) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP( \
+ TRACE_EVENT_PHASE_COUNTER, category_group, name, timestamp, \
+ TRACE_EVENT_FLAG_NONE, "value", static_cast<int>(value))
+
+#define TRACE_COUNTER_WITH_TIMESTAMP2(category_group, name, timestamp, \
+ value1_name, value1_val, value2_name, \
+ value2_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP( \
+ TRACE_EVENT_PHASE_COUNTER, category_group, name, timestamp, \
+ TRACE_EVENT_FLAG_NONE, value1_name, static_cast<int>(value1_val), \
+ value2_name, static_cast<int>(value2_val))
+
// Records the value of a counter called "name" immediately. Value
// must be representable as a 32 bit integer.
// - category and name strings must have application lifetime (statics or
@@ -603,6 +606,12 @@
INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, \
TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_ASYNC_BEGIN_WITH_TIMESTAMP1( \
+ category_group, name, id, timestamp, arg1_name, arg1_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+ TRACE_EVENT_PHASE_ASYNC_BEGIN, category_group, name, id, \
+ TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE, \
+ arg1_name, arg1_val)
#define TRACE_EVENT_COPY_ASYNC_BEGIN_WITH_TIMESTAMP0(category_group, name, id, \
timestamp) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
@@ -686,6 +695,12 @@
INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, \
TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE)
+#define TRACE_EVENT_ASYNC_END_WITH_TIMESTAMP1(category_group, name, id, \
+ timestamp, arg1_name, arg1_val) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+ TRACE_EVENT_PHASE_ASYNC_END, category_group, name, id, \
+ TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_NONE, \
+ arg1_name, arg1_val)
// NESTABLE_ASYNC_* APIs are used to describe an async operation, which can
// be nested within a NESTABLE_ASYNC event and/or have inner NESTABLE_ASYNC
@@ -790,14 +805,14 @@
#define TRACE_EVENT_COPY_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP0( \
category_group, name, id, timestamp) \
- INTERNAL_TRACE_EVENT_ADD_WITH_ID_AND_TIMESTAMP( \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN, category_group, name, id, \
- timestamp, TRACE_EVENT_FLAG_COPY)
+ TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_COPY)
#define TRACE_EVENT_COPY_NESTABLE_ASYNC_END_WITH_TIMESTAMP0( \
category_group, name, id, timestamp) \
- INTERNAL_TRACE_EVENT_ADD_WITH_ID_AND_TIMESTAMP( \
+ INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
TRACE_EVENT_PHASE_NESTABLE_ASYNC_END, category_group, name, id, \
- timestamp, TRACE_EVENT_FLAG_COPY)
+ TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, TRACE_EVENT_FLAG_COPY)
// Records a single NESTABLE_ASYNC_INSTANT event called "name" immediately,
// with 2 associated arguments. If the category is not enabled, then this
@@ -911,6 +926,17 @@
name, id, TRACE_EVENT_FLAG_COPY, arg1_name, \
arg1_val, arg2_name, arg2_val)
+// Records a clock sync event.
+#define TRACE_EVENT_CLOCK_SYNC_RECEIVER(sync_id) \
+ INTERNAL_TRACE_EVENT_ADD( \
+ TRACE_EVENT_PHASE_CLOCK_SYNC, "__metadata", "clock_sync", \
+ TRACE_EVENT_FLAG_NONE, "sync_id", sync_id)
+#define TRACE_EVENT_CLOCK_SYNC_ISSUER(sync_id, issue_ts, issue_end_ts) \
+ INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP( \
+ TRACE_EVENT_PHASE_CLOCK_SYNC, "__metadata", "clock_sync", \
+ issue_end_ts.ToInternalValue(), TRACE_EVENT_FLAG_NONE, \
+ "sync_id", sync_id, "issue_ts", issue_ts.ToInternalValue())
+
// Macros to track the life time and value of arbitrary client objects.
// See also TraceTrackableObject.
#define TRACE_EVENT_OBJECT_CREATED_WITH_ID(category_group, name, id) \
@@ -998,6 +1024,7 @@
#define TRACE_EVENT_PHASE_DELETE_OBJECT ('D')
#define TRACE_EVENT_PHASE_MEMORY_DUMP ('v')
#define TRACE_EVENT_PHASE_MARK ('R')
+#define TRACE_EVENT_PHASE_CLOCK_SYNC ('c')
// Flags for changing the behavior of TRACE_EVENT_API_ADD_TRACE_EVENT.
#define TRACE_EVENT_FLAG_NONE (static_cast<unsigned int>(0))
@@ -1012,6 +1039,7 @@
#define TRACE_EVENT_FLAG_FLOW_IN (static_cast<unsigned int>(1 << 8))
#define TRACE_EVENT_FLAG_FLOW_OUT (static_cast<unsigned int>(1 << 9))
#define TRACE_EVENT_FLAG_HAS_CONTEXT_ID (static_cast<unsigned int>(1 << 10))
+#define TRACE_EVENT_FLAG_HAS_PROCESS_ID (static_cast<unsigned int>(1 << 11))
#define TRACE_EVENT_FLAG_SCOPE_MASK \
(static_cast<unsigned int>(TRACE_EVENT_FLAG_SCOPE_OFFSET | \
diff --git a/chromium/base/trace_event/etw_manifest/BUILD.gn b/chromium/base/trace_event/etw_manifest/BUILD.gn
index f62e356b118..1e16672825e 100644
--- a/chromium/base/trace_event/etw_manifest/BUILD.gn
+++ b/chromium/base/trace_event/etw_manifest/BUILD.gn
@@ -2,47 +2,24 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/win/message_compiler.gni")
+
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"
+message_compiler("chrome_events_win") {
+ visibility = [
+ "//base/*",
+ "//chrome:main_dll",
+ ]
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")
+ user_mode_logging = true
- deps = [
- ":chrome_events_win_generate",
- ]
+ # TOOD(brucedawson) bug 569989: Enable ETW manifest and compile and link it
+ # into the proper places. Enabling as-is may add the resources to too many
+ # targets. See the bug for more information.
+ compile_generated_code = false
}
diff --git a/chromium/base/trace_event/etw_manifest/BUILD/message_compiler.py b/chromium/base/trace_event/etw_manifest/BUILD/message_compiler.py
deleted file mode 100644
index be5927d9bec..00000000000
--- a/chromium/base/trace_event/etw_manifest/BUILD/message_compiler.py
+++ /dev/null
@@ -1,16 +0,0 @@
-# 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/heap_profiler_allocation_context.cc b/chromium/base/trace_event/heap_profiler_allocation_context.cc
new file mode 100644
index 00000000000..038c083f0fa
--- /dev/null
+++ b/chromium/base/trace_event/heap_profiler_allocation_context.cc
@@ -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.
+
+#include "base/trace_event/heap_profiler_allocation_context.h"
+
+#include <cstring>
+
+#include "base/hash.h"
+#include "base/macros.h"
+
+namespace base {
+namespace trace_event {
+
+// Constructor that does not initialize members.
+AllocationContext::AllocationContext() {}
+
+// static
+AllocationContext AllocationContext::Empty() {
+ AllocationContext ctx;
+
+ for (size_t i = 0; i < arraysize(ctx.backtrace.frames); i++)
+ ctx.backtrace.frames[i] = nullptr;
+
+ ctx.type_name = nullptr;
+
+ return ctx;
+}
+
+bool operator==(const Backtrace& lhs, const Backtrace& rhs) {
+ // Pointer equality of the stack frames is assumed, so instead of doing a deep
+ // string comparison on all of the frames, a |memcmp| suffices.
+ return std::memcmp(lhs.frames, rhs.frames, sizeof(lhs.frames)) == 0;
+}
+
+bool operator==(const AllocationContext& lhs, const AllocationContext& rhs) {
+ return (lhs.backtrace == rhs.backtrace) && (lhs.type_name == rhs.type_name);
+}
+
+} // namespace trace_event
+} // namespace base
+
+namespace BASE_HASH_NAMESPACE {
+using base::trace_event::AllocationContext;
+using base::trace_event::Backtrace;
+
+size_t hash<Backtrace>::operator()(const Backtrace& backtrace) const {
+ return base::SuperFastHash(reinterpret_cast<const char*>(backtrace.frames),
+ sizeof(backtrace.frames));
+}
+
+size_t hash<AllocationContext>::operator()(const AllocationContext& ctx) const {
+ size_t backtrace_hash = hash<Backtrace>()(ctx.backtrace);
+
+ // Multiplicative hash from [Knuth 1998]. Works best if |size_t| is 32 bits,
+ // because the magic number is a prime very close to 2^32 / golden ratio, but
+ // will still redistribute keys bijectively on 64-bit architectures because
+ // the magic number is coprime to 2^64.
+ size_t type_hash = reinterpret_cast<size_t>(ctx.type_name) * 2654435761;
+
+ // Multiply one side to break the commutativity of +. Multiplication with a
+ // number coprime to |numeric_limits<size_t>::max() + 1| is bijective so
+ // randomness is preserved.
+ return (backtrace_hash * 3) + type_hash;
+}
+
+} // BASE_HASH_NAMESPACE
diff --git a/chromium/base/trace_event/heap_profiler_allocation_context.h b/chromium/base/trace_event/heap_profiler_allocation_context.h
new file mode 100644
index 00000000000..8544c78eb2c
--- /dev/null
+++ b/chromium/base/trace_event/heap_profiler_allocation_context.h
@@ -0,0 +1,97 @@
+// 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_HEAP_PROFILER_ALLOCATION_CONTEXT_H_
+#define BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/base_export.h"
+#include "base/containers/hash_tables.h"
+
+namespace base {
+namespace trace_event {
+
+// When heap profiling is enabled, tracing keeps track of the allocation
+// context for each allocation intercepted. It is generated by the
+// |AllocationContextTracker| which keeps stacks of context in TLS.
+// The tracker is initialized lazily.
+
+// The backtrace in the allocation context is a snapshot of the stack. For now,
+// this is the pseudo stack where frames are created by trace event macros. In
+// the future, we might add the option to use the native call stack. In that
+// case, |Backtrace| and |AllocationContextTracker::GetContextSnapshot| might
+// have different implementations that can be selected by a compile time flag.
+
+// The number of stack frames stored in the backtrace is a trade off between
+// memory used for tracing and accuracy. Measurements done on a prototype
+// revealed that:
+//
+// - In 60 percent of the cases, stack depth <= 7.
+// - In 87 percent of the cases, stack depth <= 9.
+// - In 95 percent of the cases, stack depth <= 11.
+//
+// See the design doc (https://goo.gl/4s7v7b) for more details.
+
+using StackFrame = const char*;
+
+struct BASE_EXPORT Backtrace {
+ // Unused backtrace frames are filled with nullptr frames. If the stack is
+ // higher than what can be stored here, the bottom frames are stored. Based
+ // on the data above, a depth of 12 captures the full stack in the vast
+ // majority of the cases.
+ StackFrame frames[12];
+};
+
+bool BASE_EXPORT operator==(const Backtrace& lhs, const Backtrace& rhs);
+
+// The |AllocationContext| is context metadata that is kept for every allocation
+// when heap profiling is enabled. To simplify memory management for book-
+// keeping, this struct has a fixed size. All |const char*|s here must have
+// static lifetime.
+struct BASE_EXPORT AllocationContext {
+ public:
+ // An allocation context with empty backtrace and unknown type.
+ static AllocationContext Empty();
+
+ Backtrace backtrace;
+
+ // Type name of the type stored in the allocated memory. A null pointer
+ // indicates "unknown type". Grouping is done by comparing pointers, not by
+ // deep string comparison. In a component build, where a type name can have a
+ // string literal in several dynamic libraries, this may distort grouping.
+ const char* type_name;
+
+ private:
+ friend class AllocationContextTracker;
+
+ // Don't allow uninitialized instances except inside the allocation context
+ // tracker. Except in tests, an |AllocationContext| should only be obtained
+ // from the tracker. In tests, paying the overhead of initializing the struct
+ // to |Empty| and then overwriting the members is not such a big deal.
+ AllocationContext();
+};
+
+bool BASE_EXPORT operator==(const AllocationContext& lhs,
+ const AllocationContext& rhs);
+
+} // namespace trace_event
+} // namespace base
+
+namespace BASE_HASH_NAMESPACE {
+
+template <>
+struct BASE_EXPORT hash<base::trace_event::Backtrace> {
+ size_t operator()(const base::trace_event::Backtrace& backtrace) const;
+};
+
+template <>
+struct BASE_EXPORT hash<base::trace_event::AllocationContext> {
+ size_t operator()(const base::trace_event::AllocationContext& context) const;
+};
+
+} // BASE_HASH_NAMESPACE
+
+#endif // BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_H_
diff --git a/chromium/base/trace_event/heap_profiler_allocation_context_tracker.cc b/chromium/base/trace_event/heap_profiler_allocation_context_tracker.cc
new file mode 100644
index 00000000000..791ab7a6fe1
--- /dev/null
+++ b/chromium/base/trace_event/heap_profiler_allocation_context_tracker.cc
@@ -0,0 +1,115 @@
+// 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/heap_profiler_allocation_context_tracker.h"
+
+#include <algorithm>
+#include <iterator>
+
+#include "base/atomicops.h"
+#include "base/threading/thread_local_storage.h"
+#include "base/trace_event/heap_profiler_allocation_context.h"
+
+namespace base {
+namespace trace_event {
+
+subtle::Atomic32 AllocationContextTracker::capture_enabled_ = 0;
+
+namespace {
+
+ThreadLocalStorage::StaticSlot g_tls_alloc_ctx_tracker = TLS_INITIALIZER;
+
+// This function is added to the TLS slot to clean up the instance when the
+// thread exits.
+void DestructAllocationContextTracker(void* alloc_ctx_tracker) {
+ delete static_cast<AllocationContextTracker*>(alloc_ctx_tracker);
+}
+
+} // namespace
+
+AllocationContextTracker::AllocationContextTracker() {}
+AllocationContextTracker::~AllocationContextTracker() {}
+
+// static
+AllocationContextTracker* AllocationContextTracker::GetThreadLocalTracker() {
+ auto tracker =
+ static_cast<AllocationContextTracker*>(g_tls_alloc_ctx_tracker.Get());
+
+ if (!tracker) {
+ tracker = new AllocationContextTracker();
+ g_tls_alloc_ctx_tracker.Set(tracker);
+ }
+
+ return tracker;
+}
+
+// static
+void AllocationContextTracker::SetCaptureEnabled(bool enabled) {
+ // When enabling capturing, also initialize the TLS slot. This does not create
+ // a TLS instance yet.
+ if (enabled && !g_tls_alloc_ctx_tracker.initialized())
+ g_tls_alloc_ctx_tracker.Initialize(DestructAllocationContextTracker);
+
+ // Release ordering ensures that when a thread observes |capture_enabled_| to
+ // be true through an acquire load, the TLS slot has been initialized.
+ subtle::Release_Store(&capture_enabled_, enabled);
+}
+
+// static
+void AllocationContextTracker::PushPseudoStackFrame(StackFrame frame) {
+ auto tracker = AllocationContextTracker::GetThreadLocalTracker();
+
+ // Impose a limit on the height to verify that every push is popped, because
+ // in practice the pseudo stack never grows higher than ~20 frames.
+ DCHECK_LT(tracker->pseudo_stack_.size(), 128u);
+ tracker->pseudo_stack_.push_back(frame);
+}
+
+// static
+void AllocationContextTracker::PopPseudoStackFrame(StackFrame frame) {
+ auto tracker = AllocationContextTracker::GetThreadLocalTracker();
+
+ // Guard for stack underflow. If tracing was started with a TRACE_EVENT in
+ // scope, the frame was never pushed, so it is possible that pop is called
+ // on an empty stack.
+ if (tracker->pseudo_stack_.empty())
+ return;
+
+ // Assert that pushes and pops are nested correctly. This DCHECK can be
+ // hit if some TRACE_EVENT macro is unbalanced (a TRACE_EVENT_END* call
+ // without a corresponding TRACE_EVENT_BEGIN).
+ DCHECK_EQ(frame, tracker->pseudo_stack_.back())
+ << "Encountered an unmatched TRACE_EVENT_END";
+
+ tracker->pseudo_stack_.pop_back();
+}
+
+// static
+AllocationContext AllocationContextTracker::GetContextSnapshot() {
+ AllocationContextTracker* tracker = GetThreadLocalTracker();
+ AllocationContext ctx;
+
+ // Fill the backtrace.
+ {
+ auto src = tracker->pseudo_stack_.begin();
+ auto dst = std::begin(ctx.backtrace.frames);
+ auto src_end = tracker->pseudo_stack_.end();
+ auto dst_end = std::end(ctx.backtrace.frames);
+
+ // Copy as much of the bottom of the pseudo stack into the backtrace as
+ // possible.
+ for (; src != src_end && dst != dst_end; src++, dst++)
+ *dst = *src;
+
+ // If there is room for more, fill the remaining slots with empty frames.
+ std::fill(dst, dst_end, nullptr);
+ }
+
+ ctx.type_name = nullptr;
+
+ return ctx;
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/chromium/base/trace_event/heap_profiler_allocation_context_tracker.h b/chromium/base/trace_event/heap_profiler_allocation_context_tracker.h
new file mode 100644
index 00000000000..9c9a3132aba
--- /dev/null
+++ b/chromium/base/trace_event/heap_profiler_allocation_context_tracker.h
@@ -0,0 +1,73 @@
+// 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_HEAP_PROFILER_ALLOCATION_CONTEXT_TRACKER_H_
+#define BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_TRACKER_H_
+
+#include <vector>
+
+#include "base/atomicops.h"
+#include "base/base_export.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/trace_event/heap_profiler_allocation_context.h"
+
+namespace base {
+namespace trace_event {
+
+// The allocation context tracker keeps track of thread-local context for heap
+// profiling. It includes a pseudo stack of trace events. On every allocation
+// the tracker provides a snapshot of its context in the form of an
+// |AllocationContext| that is to be stored together with the allocation
+// details.
+class BASE_EXPORT AllocationContextTracker {
+ public:
+ // Globally enables capturing allocation context.
+ // TODO(ruuda): Should this be replaced by |EnableCapturing| in the future?
+ // Or at least have something that guards agains enable -> disable -> enable?
+ static void SetCaptureEnabled(bool enabled);
+
+ // Returns whether capturing allocation context is enabled globally.
+ inline static bool capture_enabled() {
+ // A little lag after heap profiling is enabled or disabled is fine, it is
+ // more important that the check is as cheap as possible when capturing is
+ // not enabled, so do not issue a memory barrier in the fast path.
+ if (subtle::NoBarrier_Load(&capture_enabled_) == 0)
+ return false;
+
+ // In the slow path, an acquire load is required to pair with the release
+ // store in |SetCaptureEnabled|. This is to ensure that the TLS slot for
+ // the thread-local allocation context tracker has been initialized if
+ // |capture_enabled| returns true.
+ return subtle::Acquire_Load(&capture_enabled_) != 0;
+ }
+
+ // Pushes a frame onto the thread-local pseudo stack.
+ static void PushPseudoStackFrame(StackFrame frame);
+
+ // Pops a frame from the thread-local pseudo stack.
+ static void PopPseudoStackFrame(StackFrame frame);
+
+ // Returns a snapshot of the current thread-local context.
+ static AllocationContext GetContextSnapshot();
+
+ ~AllocationContextTracker();
+
+ private:
+ AllocationContextTracker();
+
+ static AllocationContextTracker* GetThreadLocalTracker();
+
+ static subtle::Atomic32 capture_enabled_;
+
+ // The pseudo stack where frames are |TRACE_EVENT| names.
+ std::vector<StackFrame> pseudo_stack_;
+
+ DISALLOW_COPY_AND_ASSIGN(AllocationContextTracker);
+};
+
+} // namespace trace_event
+} // namespace base
+
+#endif // BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_TRACKER_H_
diff --git a/chromium/base/trace_event/heap_profiler_allocation_context_tracker_unittest.cc b/chromium/base/trace_event/heap_profiler_allocation_context_tracker_unittest.cc
new file mode 100644
index 00000000000..58255ad788a
--- /dev/null
+++ b/chromium/base/trace_event/heap_profiler_allocation_context_tracker_unittest.cc
@@ -0,0 +1,225 @@
+// 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 <stddef.h>
+
+#include <iterator>
+
+#include "base/memory/ref_counted.h"
+#include "base/trace_event/heap_profiler_allocation_context.h"
+#include "base/trace_event/heap_profiler_allocation_context_tracker.h"
+#include "base/trace_event/trace_event.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+// Define all strings once, because the pseudo stack requires pointer equality,
+// and string interning is unreliable.
+const char kCupcake[] = "Cupcake";
+const char kDonut[] = "Donut";
+const char kEclair[] = "Eclair";
+const char kFroyo[] = "Froyo";
+const char kGingerbread[] = "Gingerbread";
+
+// Asserts that the fixed-size array |expected_backtrace| matches the backtrace
+// in |AllocationContextTracker::GetContextSnapshot|.
+template <size_t N>
+void AssertBacktraceEquals(const StackFrame(&expected_backtrace)[N]) {
+ AllocationContext ctx = AllocationContextTracker::GetContextSnapshot();
+
+ auto actual = std::begin(ctx.backtrace.frames);
+ auto actual_bottom = std::end(ctx.backtrace.frames);
+ auto expected = std::begin(expected_backtrace);
+ auto expected_bottom = std::end(expected_backtrace);
+
+ // Note that this requires the pointers to be equal, this is not doing a deep
+ // string comparison.
+ for (; actual != actual_bottom && expected != expected_bottom;
+ actual++, expected++)
+ ASSERT_EQ(*expected, *actual);
+
+ // Ensure that the height of the stacks is the same.
+ ASSERT_EQ(actual, actual_bottom);
+ ASSERT_EQ(expected, expected_bottom);
+}
+
+void AssertBacktraceEmpty() {
+ AllocationContext ctx = AllocationContextTracker::GetContextSnapshot();
+
+ for (StackFrame frame : ctx.backtrace.frames)
+ ASSERT_EQ(nullptr, frame);
+}
+
+class AllocationContextTrackerTest : public testing::Test {
+ public:
+ void SetUp() override {
+ TraceConfig config("");
+ TraceLog::GetInstance()->SetEnabled(config, TraceLog::RECORDING_MODE);
+ AllocationContextTracker::SetCaptureEnabled(true);
+ }
+
+ void TearDown() override {
+ AllocationContextTracker::SetCaptureEnabled(false);
+ TraceLog::GetInstance()->SetDisabled();
+ }
+};
+
+// Check that |TRACE_EVENT| macros push and pop to the pseudo stack correctly.
+// Also check that |GetContextSnapshot| fills the backtrace with null pointers
+// when the pseudo stack height is less than the capacity.
+TEST_F(AllocationContextTrackerTest, PseudoStackScopedTrace) {
+ StackFrame c = kCupcake;
+ StackFrame d = kDonut;
+ StackFrame e = kEclair;
+ StackFrame f = kFroyo;
+
+ AssertBacktraceEmpty();
+
+ {
+ TRACE_EVENT0("Testing", kCupcake);
+ StackFrame frame_c[] = {c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ AssertBacktraceEquals(frame_c);
+
+ {
+ TRACE_EVENT0("Testing", kDonut);
+ StackFrame frame_cd[] = {c, d, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ AssertBacktraceEquals(frame_cd);
+ }
+
+ AssertBacktraceEquals(frame_c);
+
+ {
+ TRACE_EVENT0("Testing", kEclair);
+ StackFrame frame_ce[] = {c, e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ AssertBacktraceEquals(frame_ce);
+ }
+
+ AssertBacktraceEquals(frame_c);
+ }
+
+ AssertBacktraceEmpty();
+
+ {
+ TRACE_EVENT0("Testing", kFroyo);
+ StackFrame frame_f[] = {f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ AssertBacktraceEquals(frame_f);
+ }
+
+ AssertBacktraceEmpty();
+}
+
+// Same as |PseudoStackScopedTrace|, but now test the |TRACE_EVENT_BEGIN| and
+// |TRACE_EVENT_END| macros.
+TEST_F(AllocationContextTrackerTest, PseudoStackBeginEndTrace) {
+ StackFrame c = kCupcake;
+ StackFrame d = kDonut;
+ StackFrame e = kEclair;
+ StackFrame f = kFroyo;
+
+ StackFrame frame_c[] = {c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ StackFrame frame_cd[] = {c, d, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ StackFrame frame_ce[] = {c, e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ StackFrame frame_f[] = {f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+ AssertBacktraceEmpty();
+
+ TRACE_EVENT_BEGIN0("Testing", kCupcake);
+ AssertBacktraceEquals(frame_c);
+
+ TRACE_EVENT_BEGIN0("Testing", kDonut);
+ AssertBacktraceEquals(frame_cd);
+ TRACE_EVENT_END0("Testing", kDonut);
+
+ AssertBacktraceEquals(frame_c);
+
+ TRACE_EVENT_BEGIN0("Testing", kEclair);
+ AssertBacktraceEquals(frame_ce);
+ TRACE_EVENT_END0("Testing", kEclair);
+
+ AssertBacktraceEquals(frame_c);
+ TRACE_EVENT_END0("Testing", kCupcake);
+
+ AssertBacktraceEmpty();
+
+ TRACE_EVENT_BEGIN0("Testing", kFroyo);
+ AssertBacktraceEquals(frame_f);
+ TRACE_EVENT_END0("Testing", kFroyo);
+
+ AssertBacktraceEmpty();
+}
+
+TEST_F(AllocationContextTrackerTest, PseudoStackMixedTrace) {
+ StackFrame c = kCupcake;
+ StackFrame d = kDonut;
+ StackFrame e = kEclair;
+ StackFrame f = kFroyo;
+
+ StackFrame frame_c[] = {c, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ StackFrame frame_cd[] = {c, d, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ StackFrame frame_e[] = {e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ StackFrame frame_ef[] = {e, f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+ AssertBacktraceEmpty();
+
+ TRACE_EVENT_BEGIN0("Testing", kCupcake);
+ AssertBacktraceEquals(frame_c);
+
+ {
+ TRACE_EVENT0("Testing", kDonut);
+ AssertBacktraceEquals(frame_cd);
+ }
+
+ AssertBacktraceEquals(frame_c);
+ TRACE_EVENT_END0("Testing", kCupcake);
+ AssertBacktraceEmpty();
+
+ {
+ TRACE_EVENT0("Testing", kEclair);
+ AssertBacktraceEquals(frame_e);
+
+ TRACE_EVENT_BEGIN0("Testing", kFroyo);
+ AssertBacktraceEquals(frame_ef);
+ TRACE_EVENT_END0("Testing", kFroyo);
+ AssertBacktraceEquals(frame_e);
+ }
+
+ AssertBacktraceEmpty();
+}
+
+TEST_F(AllocationContextTrackerTest, BacktraceTakesTop) {
+ // Push 12 events onto the pseudo stack.
+ TRACE_EVENT0("Testing", kCupcake);
+ TRACE_EVENT0("Testing", kCupcake);
+ TRACE_EVENT0("Testing", kCupcake);
+ TRACE_EVENT0("Testing", kCupcake);
+
+ TRACE_EVENT0("Testing", kCupcake);
+ TRACE_EVENT0("Testing", kCupcake);
+ TRACE_EVENT0("Testing", kCupcake);
+ TRACE_EVENT0("Testing", kCupcake);
+
+ TRACE_EVENT0("Testing", kCupcake);
+ TRACE_EVENT0("Testing", kDonut);
+ TRACE_EVENT0("Testing", kEclair);
+ TRACE_EVENT0("Testing", kFroyo);
+
+ {
+ TRACE_EVENT0("Testing", kGingerbread);
+ AllocationContext ctx = AllocationContextTracker::GetContextSnapshot();
+
+ // The pseudo stack relies on pointer equality, not deep string comparisons.
+ ASSERT_EQ(kCupcake, ctx.backtrace.frames[0]);
+ ASSERT_EQ(kFroyo, ctx.backtrace.frames[11]);
+ }
+
+ {
+ AllocationContext ctx = AllocationContextTracker::GetContextSnapshot();
+ ASSERT_EQ(kCupcake, ctx.backtrace.frames[0]);
+ ASSERT_EQ(kFroyo, ctx.backtrace.frames[11]);
+ }
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/chromium/base/trace_event/heap_profiler_allocation_register.cc b/chromium/base/trace_event/heap_profiler_allocation_register.cc
new file mode 100644
index 00000000000..9a846c5613c
--- /dev/null
+++ b/chromium/base/trace_event/heap_profiler_allocation_register.cc
@@ -0,0 +1,197 @@
+// 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/heap_profiler_allocation_register.h"
+
+#include "base/trace_event/trace_event_memory_overhead.h"
+
+namespace base {
+namespace trace_event {
+
+AllocationRegister::AllocationRegister()
+ : AllocationRegister(kNumBuckets * kNumCellsPerBucket) {}
+
+AllocationRegister::AllocationRegister(uint32_t num_cells)
+ // Reserve enough address space to store |num_cells_| entries if necessary,
+ // with a guard page after it to crash the program when attempting to store
+ // more entries.
+ : num_cells_(num_cells),
+ cells_(static_cast<Cell*>(AllocateVirtualMemory(num_cells_ *
+ sizeof(Cell)))),
+ buckets_(static_cast<CellIndex*>(
+ AllocateVirtualMemory(kNumBuckets * sizeof(CellIndex)))),
+
+ // The free list is empty. The first unused cell is cell 1, because index
+ // 0 is used as list terminator.
+ free_list_(0),
+ next_unused_cell_(1) {}
+
+AllocationRegister::~AllocationRegister() {
+ FreeVirtualMemory(buckets_, kNumBuckets * sizeof(CellIndex));
+ FreeVirtualMemory(cells_, num_cells_ * sizeof(Cell));
+}
+
+void AllocationRegister::Insert(void* address,
+ size_t size,
+ AllocationContext context) {
+ DCHECK(address != nullptr);
+
+ CellIndex* idx_ptr = Lookup(address);
+
+ // If the index is 0, the address is not yet present, so insert it.
+ if (*idx_ptr == 0) {
+ *idx_ptr = GetFreeCell();
+
+ // The address stored in a cell is const as long as it is exposed (via the
+ // iterators or |Get|), but because cells are re-used, a const cast is
+ // required to set it on insert and remove.
+ void* const& allocation_address = cells_[*idx_ptr].allocation.address;
+ const_cast<void*&>(allocation_address) = address;
+ cells_[*idx_ptr].next = 0;
+ }
+
+ cells_[*idx_ptr].allocation.size = size;
+ cells_[*idx_ptr].allocation.context = context;
+}
+
+void AllocationRegister::Remove(void* address) {
+ // Get a pointer to the index of the cell that stores |address|. The index can
+ // be an element of |buckets_| or the |next| member of a cell.
+ CellIndex* idx_ptr = Lookup(address);
+ CellIndex freed_idx = *idx_ptr;
+
+ // If the index is 0, the address was not there in the first place.
+ if (freed_idx == 0)
+ return;
+
+ // The cell at the index is now free, remove it from the linked list for
+ // |Hash(address)|.
+ Cell* freed_cell = &cells_[freed_idx];
+ *idx_ptr = freed_cell->next;
+
+ // Put the free cell at the front of the free list.
+ freed_cell->next = free_list_;
+ free_list_ = freed_idx;
+
+ // Reset the address, so that on iteration the free cell is ignored.
+ const_cast<void*&>(freed_cell->allocation.address) = nullptr;
+}
+
+AllocationRegister::Allocation* AllocationRegister::Get(void* address) {
+ CellIndex* idx_ptr = Lookup(address);
+
+ // If the index is 0, the address is not present in the table.
+ return *idx_ptr == 0 ? nullptr : &cells_[*idx_ptr].allocation;
+}
+
+AllocationRegister::ConstIterator AllocationRegister::begin() const {
+ // Initialize the iterator's index to 0. Cell 0 never stores an entry.
+ ConstIterator iterator(*this, 0);
+ // Incrementing will advance the iterator to the first used cell.
+ ++iterator;
+ return iterator;
+}
+
+AllocationRegister::ConstIterator AllocationRegister::end() const {
+ // Cell |next_unused_cell_ - 1| is the last cell that could contain an entry,
+ // so index |next_unused_cell_| is an iterator past the last element, in line
+ // with the STL iterator conventions.
+ return ConstIterator(*this, next_unused_cell_);
+}
+
+AllocationRegister::ConstIterator::ConstIterator(
+ const AllocationRegister& alloc_register,
+ CellIndex index)
+ : register_(alloc_register), index_(index) {}
+
+void AllocationRegister::ConstIterator::operator++() {
+ // Find the next cell with a non-null address until all cells that could
+ // possibly be used have been iterated. A null address indicates a free cell.
+ do {
+ index_++;
+ } while (index_ < register_.next_unused_cell_ &&
+ register_.cells_[index_].allocation.address == nullptr);
+}
+
+bool AllocationRegister::ConstIterator::operator!=(
+ const ConstIterator& other) const {
+ return index_ != other.index_;
+}
+
+const AllocationRegister::Allocation& AllocationRegister::ConstIterator::
+operator*() const {
+ return register_.cells_[index_].allocation;
+}
+
+AllocationRegister::CellIndex* AllocationRegister::Lookup(void* address) {
+ // The list head is in |buckets_| at the hash offset.
+ CellIndex* idx_ptr = &buckets_[Hash(address)];
+
+ // Chase down the list until the cell that holds |address| is found,
+ // or until the list ends.
+ while (*idx_ptr != 0 && cells_[*idx_ptr].allocation.address != address)
+ idx_ptr = &cells_[*idx_ptr].next;
+
+ return idx_ptr;
+}
+
+AllocationRegister::CellIndex AllocationRegister::GetFreeCell() {
+ // First try to re-use a cell from the freelist.
+ if (free_list_) {
+ CellIndex idx = free_list_;
+ free_list_ = cells_[idx].next;
+ return idx;
+ }
+
+ // Otherwise pick the next cell that has not been touched before.
+ CellIndex idx = next_unused_cell_;
+ next_unused_cell_++;
+
+ // If the hash table has too little capacity (when too little address space
+ // was reserved for |cells_|), |next_unused_cell_| can be an index outside of
+ // the allocated storage. A guard page is allocated there to crash the
+ // program in that case. There are alternative solutions:
+ // - Deal with it, increase capacity by reallocating |cells_|.
+ // - Refuse to insert and let the caller deal with it.
+ // Because free cells are re-used before accessing fresh cells with a higher
+ // index, and because reserving address space without touching it is cheap,
+ // the simplest solution is to just allocate a humongous chunk of address
+ // space.
+
+ DCHECK_LT(next_unused_cell_, num_cells_ + 1);
+
+ return idx;
+}
+
+// static
+uint32_t AllocationRegister::Hash(void* address) {
+ // The multiplicative hashing scheme from [Knuth 1998]. The value of |a| has
+ // been chosen carefully based on measurements with real-word data (addresses
+ // recorded from a Chrome trace run). It is the first prime after 2^17. For
+ // |shift|, 13, 14 and 15 yield good results. These values are tuned to 2^18
+ // buckets. Microbenchmarks show that this simple scheme outperforms fancy
+ // hashes like Murmur3 by 20 to 40 percent.
+ const uintptr_t key = reinterpret_cast<uintptr_t>(address);
+ const uintptr_t a = 131101;
+ const uintptr_t shift = 14;
+ const uintptr_t h = (key * a) >> shift;
+ return static_cast<uint32_t>(h) & kNumBucketsMask;
+}
+
+void AllocationRegister::EstimateTraceMemoryOverhead(
+ TraceEventMemoryOverhead* overhead) const {
+ // Estimate memory overhead by counting all of the cells that have ever been
+ // touched. Don't report mmapped memory as allocated, because it has not been
+ // allocated by malloc.
+ size_t allocated = sizeof(AllocationRegister);
+ size_t resident = sizeof(AllocationRegister)
+ // Include size of touched cells (size of |*cells_|).
+ + sizeof(Cell) * next_unused_cell_
+ // Size of |*buckets_|.
+ + sizeof(CellIndex) * kNumBuckets;
+ overhead->Add("AllocationRegister", allocated, resident);
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/chromium/base/trace_event/heap_profiler_allocation_register.h b/chromium/base/trace_event/heap_profiler_allocation_register.h
new file mode 100644
index 00000000000..804be898e4d
--- /dev/null
+++ b/chromium/base/trace_event/heap_profiler_allocation_register.h
@@ -0,0 +1,176 @@
+// 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_HEAP_PROFILER_ALLOCATION_REGISTER_H_
+#define BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_REGISTER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/trace_event/heap_profiler_allocation_context.h"
+
+namespace base {
+namespace trace_event {
+
+class TraceEventMemoryOverhead;
+
+// The allocation register keeps track of all allocations that have not been
+// freed. It is a memory map-backed hash table that stores size and context
+// indexed by address. The hash table is tailored specifically for this use
+// case. The common case is that an entry is inserted and removed after a
+// while, lookup without modifying the table is not an intended use case. The
+// hash table is implemented as an array of linked lists. The size of this
+// array is fixed, but it does not limit the amount of entries that can be
+// stored.
+//
+// Replaying a recording of Chrome's allocations and frees against this hash
+// table takes about 15% of the time that it takes to replay them against
+// |std::map|.
+class BASE_EXPORT AllocationRegister {
+ public:
+ // The data stored in the hash table;
+ // contains the details about an allocation.
+ struct Allocation {
+ void* const address;
+ size_t size;
+ AllocationContext context;
+ };
+
+ // An iterator that iterates entries in the hash table efficiently, but in no
+ // particular order. It can do this by iterating the cells and ignoring the
+ // linked lists altogether. Instead of checking whether a cell is in the free
+ // list to see if it should be skipped, a null address is used to indicate
+ // that a cell is free.
+ class BASE_EXPORT ConstIterator {
+ public:
+ void operator++();
+ bool operator!=(const ConstIterator& other) const;
+ const Allocation& operator*() const;
+
+ private:
+ friend class AllocationRegister;
+ using CellIndex = uint32_t;
+
+ ConstIterator(const AllocationRegister& alloc_register, CellIndex index);
+
+ const AllocationRegister& register_;
+ CellIndex index_;
+ };
+
+ AllocationRegister();
+ explicit AllocationRegister(uint32_t num_cells);
+
+ ~AllocationRegister();
+
+ // Inserts allocation details into the table. If the address was present
+ // already, its details are updated. |address| must not be null. (This is
+ // because null is used to mark free cells, to allow efficient iteration of
+ // the hash table.)
+ void Insert(void* address, size_t size, AllocationContext context);
+
+ // Removes the address from the table if it is present. It is ok to call this
+ // with a null pointer.
+ void Remove(void* address);
+
+ // Returns a pointer to the allocation at the address, or null if there is no
+ // allocation at that address. This can be used to change the allocation
+ // context after insertion, for example to change the type name.
+ Allocation* Get(void* address);
+
+ ConstIterator begin() const;
+ ConstIterator end() const;
+
+ // Estimates memory overhead including |sizeof(AllocationRegister)|.
+ void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead) const;
+
+ private:
+ friend class AllocationRegisterTest;
+ using CellIndex = uint32_t;
+
+ // A cell can store allocation details (size and context) by address. Cells
+ // are part of a linked list via the |next| member. This list is either the
+ // list for a particular hash, or the free list. All cells are contiguous in
+ // memory in one big array. Therefore, on 64-bit systems, space can be saved
+ // by storing 32-bit indices instead of pointers as links. Index 0 is used as
+ // the list terminator.
+ struct Cell {
+ CellIndex next;
+ Allocation allocation;
+ };
+
+ // The number of buckets, 2^18, approximately 260 000, has been tuned for
+ // Chrome's typical number of outstanding allocations. (This number varies
+ // between processes. Most processes have a sustained load of ~30k unfreed
+ // allocations, but some processes have peeks around 100k-400k allocations.)
+ // Because of the size of the table, it is likely that every |buckets_|
+ // access and every |cells_| access will incur a cache miss. Microbenchmarks
+ // suggest that it is worthwile to use more memory for the table to avoid
+ // chasing down the linked list, until the size is 2^18. The number of buckets
+ // is a power of two so modular indexing can be done with bitwise and.
+ static const uint32_t kNumBuckets = 0x40000;
+ static const uint32_t kNumBucketsMask = kNumBuckets - 1;
+
+ // Reserve address space to store at most this number of entries. High
+ // capacity does not imply high memory usage due to the access pattern. The
+ // only constraint on the number of cells is that on 32-bit systems address
+ // space is scarce (i.e. reserving 2GiB of address space for the entries is
+ // not an option). A value of ~3M entries is large enough to handle spikes in
+ // the number of allocations, and modest enough to require no more than a few
+ // dozens of MiB of address space.
+ static const uint32_t kNumCellsPerBucket = 10;
+
+ // Returns a value in the range [0, kNumBuckets - 1] (inclusive).
+ static uint32_t Hash(void* address);
+
+ // Allocates a region of virtual address space of |size| rounded up to the
+ // system page size. The memory is zeroed by the system. A guard page is
+ // added after the end.
+ static void* AllocateVirtualMemory(size_t size);
+
+ // Frees a region of virtual address space allocated by a call to
+ // |AllocateVirtualMemory|.
+ static void FreeVirtualMemory(void* address, size_t allocated_size);
+
+ // Returns a pointer to the variable that contains or should contain the
+ // index of the cell that stores the entry for |address|. The pointer may
+ // point at an element of |buckets_| or at the |next| member of an element of
+ // |cells_|. If the value pointed at is 0, |address| is not in the table.
+ CellIndex* Lookup(void* address);
+
+ // Takes a cell that is not being used to store an entry (either by recycling
+ // from the free list or by taking a fresh cell) and returns its index.
+ CellIndex GetFreeCell();
+
+ // The maximum number of cells which can be allocated.
+ uint32_t const num_cells_;
+
+ // The array of cells. This array is backed by mmapped memory. Lower indices
+ // are accessed first, higher indices are only accessed when required. In
+ // this way, even if a huge amount of address space has been mmapped, only
+ // the cells that are actually used will be backed by physical memory.
+ Cell* const cells_;
+
+ // The array of indices into |cells_|. |buckets_[Hash(address)]| will contain
+ // the index of the head of the linked list for |Hash(address)|. A value of 0
+ // indicates an empty list. This array is backed by mmapped memory.
+ CellIndex* const buckets_;
+
+ // The head of the free list. This is the index of the cell. A value of 0
+ // means that the free list is empty.
+ CellIndex free_list_;
+
+ // The index of the first element of |cells_| that has not been used before.
+ // If the free list is empty and a new cell is needed, the cell at this index
+ // is used. This is the high water mark for the number of entries stored.
+ CellIndex next_unused_cell_;
+
+ DISALLOW_COPY_AND_ASSIGN(AllocationRegister);
+};
+
+} // namespace trace_event
+} // namespace base
+
+#endif // BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_REGISTER_H_
diff --git a/chromium/base/trace_event/heap_profiler_allocation_register_posix.cc b/chromium/base/trace_event/heap_profiler_allocation_register_posix.cc
new file mode 100644
index 00000000000..c38d7e69182
--- /dev/null
+++ b/chromium/base/trace_event/heap_profiler_allocation_register_posix.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/heap_profiler_allocation_register.h"
+
+#include <stddef.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include "base/bits.h"
+#include "base/logging.h"
+#include "base/process/process_metrics.h"
+
+#ifndef MAP_ANONYMOUS
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+
+namespace base {
+namespace trace_event {
+
+namespace {
+size_t GetGuardSize() {
+ return GetPageSize();
+}
+}
+
+// static
+void* AllocationRegister::AllocateVirtualMemory(size_t size) {
+ size = bits::Align(size, GetPageSize());
+
+ // Add space for a guard page at the end.
+ size_t map_size = size + GetGuardSize();
+
+ void* addr = mmap(nullptr, map_size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+
+ PCHECK(addr != MAP_FAILED);
+
+ // Mark the last page of the allocated address space as inaccessible
+ // (PROT_NONE). The read/write accessible space is still at least |min_size|
+ // bytes.
+ void* guard_addr =
+ reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) + size);
+ int result = mprotect(guard_addr, GetGuardSize(), PROT_NONE);
+ PCHECK(result == 0);
+
+ return addr;
+}
+
+// static
+void AllocationRegister::FreeVirtualMemory(void* address,
+ size_t allocated_size) {
+ size_t size = bits::Align(allocated_size, GetPageSize()) + GetGuardSize();
+ munmap(address, size);
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/chromium/base/trace_event/heap_profiler_allocation_register_unittest.cc b/chromium/base/trace_event/heap_profiler_allocation_register_unittest.cc
new file mode 100644
index 00000000000..3ec4580be50
--- /dev/null
+++ b/chromium/base/trace_event/heap_profiler_allocation_register_unittest.cc
@@ -0,0 +1,286 @@
+// 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/heap_profiler_allocation_register.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/process/process_metrics.h"
+#include "base/trace_event/heap_profiler_allocation_context.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+class AllocationRegisterTest : public testing::Test {
+ public:
+ static const uint32_t kNumBuckets = AllocationRegister::kNumBuckets;
+
+ // Returns the number of cells that the |AllocationRegister| can store per
+ // system page.
+ size_t GetNumCellsPerPage() {
+ return GetPageSize() / sizeof(AllocationRegister::Cell);
+ }
+
+ uint32_t GetHighWaterMark(const AllocationRegister& reg) {
+ return reg.next_unused_cell_;
+ }
+
+ uint32_t GetNumCells(const AllocationRegister& reg) {
+ return reg.num_cells_;
+ }
+};
+
+// Iterates over all entries in the allocation register and returns the bitwise
+// or of all addresses stored in it.
+uintptr_t OrAllAddresses(const AllocationRegister& reg) {
+ uintptr_t acc = 0;
+
+ for (auto i : reg)
+ acc |= reinterpret_cast<uintptr_t>(i.address);
+
+ return acc;
+}
+
+// Iterates over all entries in the allocation register and returns the sum of
+// the sizes of the entries.
+size_t SumAllSizes(const AllocationRegister& reg) {
+ size_t sum = 0;
+
+ for (auto i : reg)
+ sum += i.size;
+
+ return sum;
+}
+
+TEST_F(AllocationRegisterTest, InsertRemove) {
+ AllocationRegister reg;
+ AllocationContext ctx = AllocationContext::Empty();
+
+ EXPECT_EQ(0u, OrAllAddresses(reg));
+
+ reg.Insert(reinterpret_cast<void*>(1), 0, ctx);
+
+ EXPECT_EQ(1u, OrAllAddresses(reg));
+
+ reg.Insert(reinterpret_cast<void*>(2), 0, ctx);
+
+ EXPECT_EQ(3u, OrAllAddresses(reg));
+
+ reg.Insert(reinterpret_cast<void*>(4), 0, ctx);
+
+ EXPECT_EQ(7u, OrAllAddresses(reg));
+
+ reg.Remove(reinterpret_cast<void*>(2));
+
+ EXPECT_EQ(5u, OrAllAddresses(reg));
+
+ reg.Remove(reinterpret_cast<void*>(4));
+
+ EXPECT_EQ(1u, OrAllAddresses(reg));
+
+ reg.Remove(reinterpret_cast<void*>(1));
+
+ EXPECT_EQ(0u, OrAllAddresses(reg));
+}
+
+TEST_F(AllocationRegisterTest, DoubleFreeIsAllowed) {
+ AllocationRegister reg;
+ AllocationContext ctx = AllocationContext::Empty();
+
+ reg.Insert(reinterpret_cast<void*>(1), 0, ctx);
+ reg.Insert(reinterpret_cast<void*>(2), 0, ctx);
+ reg.Remove(reinterpret_cast<void*>(1));
+ reg.Remove(reinterpret_cast<void*>(1)); // Remove for the second time.
+ reg.Remove(reinterpret_cast<void*>(4)); // Remove never inserted address.
+
+ EXPECT_EQ(2u, OrAllAddresses(reg));
+}
+
+TEST_F(AllocationRegisterTest, DoubleInsertOverwrites) {
+ // TODO(ruuda): Although double insert happens in practice, it should not.
+ // Find out the cause and ban double insert if possible.
+ AllocationRegister reg;
+ AllocationContext ctx = AllocationContext::Empty();
+ StackFrame frame1 = "Foo";
+ StackFrame frame2 = "Bar";
+
+ ctx.backtrace.frames[0] = frame1;
+ reg.Insert(reinterpret_cast<void*>(1), 11, ctx);
+
+ {
+ AllocationRegister::Allocation elem = *reg.begin();
+
+ EXPECT_EQ(frame1, elem.context.backtrace.frames[0]);
+ EXPECT_EQ(11u, elem.size);
+ EXPECT_EQ(reinterpret_cast<void*>(1), elem.address);
+ }
+
+ ctx.backtrace.frames[0] = frame2;
+ reg.Insert(reinterpret_cast<void*>(1), 13, ctx);
+
+ {
+ AllocationRegister::Allocation elem = *reg.begin();
+
+ EXPECT_EQ(frame2, elem.context.backtrace.frames[0]);
+ EXPECT_EQ(13u, elem.size);
+ EXPECT_EQ(reinterpret_cast<void*>(1), elem.address);
+ }
+}
+
+// Check that even if more entries than the number of buckets are inserted, the
+// register still behaves correctly.
+TEST_F(AllocationRegisterTest, InsertRemoveCollisions) {
+ size_t expected_sum = 0;
+ AllocationRegister reg;
+ AllocationContext ctx = AllocationContext::Empty();
+
+ // By inserting 100 more entries than the number of buckets, there will be at
+ // least 100 collisions.
+ for (uintptr_t i = 1; i <= kNumBuckets + 100; i++) {
+ size_t size = i % 31;
+ expected_sum += size;
+ reg.Insert(reinterpret_cast<void*>(i), size, ctx);
+
+ // Don't check the sum on every iteration to keep the test fast.
+ if (i % (1 << 14) == 0)
+ EXPECT_EQ(expected_sum, SumAllSizes(reg));
+ }
+
+ EXPECT_EQ(expected_sum, SumAllSizes(reg));
+
+ for (uintptr_t i = 1; i <= kNumBuckets + 100; i++) {
+ size_t size = i % 31;
+ expected_sum -= size;
+ reg.Remove(reinterpret_cast<void*>(i));
+
+ if (i % (1 << 14) == 0)
+ EXPECT_EQ(expected_sum, SumAllSizes(reg));
+ }
+
+ EXPECT_EQ(expected_sum, SumAllSizes(reg));
+}
+
+// The previous tests are not particularly good for testing iterators, because
+// elements are removed and inserted in the same order, meaning that the cells
+// fill up from low to high index, and are then freed from low to high index.
+// This test removes entries in a different order, to ensure that the iterator
+// skips over the freed cells properly. Then insert again to ensure that the
+// free list is utilised properly.
+TEST_F(AllocationRegisterTest, InsertRemoveRandomOrder) {
+ size_t expected_sum = 0;
+ AllocationRegister reg;
+ AllocationContext ctx = AllocationContext::Empty();
+
+ uintptr_t generator = 3;
+ uintptr_t prime = 1013;
+ uint32_t initial_water_mark = GetHighWaterMark(reg);
+
+ for (uintptr_t i = 2; i < prime; i++) {
+ size_t size = i % 31;
+ expected_sum += size;
+ reg.Insert(reinterpret_cast<void*>(i), size, ctx);
+ }
+
+ // This should have used a fresh slot for each of the |prime - 2| inserts.
+ ASSERT_EQ(prime - 2, GetHighWaterMark(reg) - initial_water_mark);
+
+ // Iterate the numbers 2, 3, ..., prime - 1 in pseudorandom order.
+ for (uintptr_t i = generator; i != 1; i = (i * generator) % prime) {
+ size_t size = i % 31;
+ expected_sum -= size;
+ reg.Remove(reinterpret_cast<void*>(i));
+ EXPECT_EQ(expected_sum, SumAllSizes(reg));
+ }
+
+ ASSERT_EQ(0u, expected_sum);
+
+ // Insert |prime - 2| entries again. This should use cells from the free list,
+ // so the |next_unused_cell_| index should not change.
+ for (uintptr_t i = 2; i < prime; i++)
+ reg.Insert(reinterpret_cast<void*>(i), 0, ctx);
+
+ ASSERT_EQ(prime - 2, GetHighWaterMark(reg) - initial_water_mark);
+
+ // Inserting one more entry should use a fresh cell again.
+ reg.Insert(reinterpret_cast<void*>(prime), 0, ctx);
+ ASSERT_EQ(prime - 1, GetHighWaterMark(reg) - initial_water_mark);
+}
+
+TEST_F(AllocationRegisterTest, ChangeContextAfterInsertion) {
+ using Allocation = AllocationRegister::Allocation;
+ const char kStdString[] = "std::string";
+ AllocationRegister reg;
+ AllocationContext ctx = AllocationContext::Empty();
+
+ reg.Insert(reinterpret_cast<void*>(17), 1, ctx);
+ reg.Insert(reinterpret_cast<void*>(19), 2, ctx);
+ reg.Insert(reinterpret_cast<void*>(23), 3, ctx);
+
+ // Looking up addresses that were not inserted should return null.
+ // A null pointer lookup is a valid thing to do.
+ EXPECT_EQ(nullptr, reg.Get(nullptr));
+ EXPECT_EQ(nullptr, reg.Get(reinterpret_cast<void*>(13)));
+
+ Allocation* a17 = reg.Get(reinterpret_cast<void*>(17));
+ Allocation* a19 = reg.Get(reinterpret_cast<void*>(19));
+ Allocation* a23 = reg.Get(reinterpret_cast<void*>(23));
+
+ EXPECT_NE(nullptr, a17);
+ EXPECT_NE(nullptr, a19);
+ EXPECT_NE(nullptr, a23);
+
+ a17->size = 100;
+ a19->context.type_name = kStdString;
+
+ reg.Remove(reinterpret_cast<void*>(23));
+
+ // Lookup should not find any garbage after removal.
+ EXPECT_EQ(nullptr, reg.Get(reinterpret_cast<void*>(23)));
+
+ // Mutating allocations should have modified the allocations in the register.
+ for (const Allocation& allocation : reg) {
+ if (allocation.address == reinterpret_cast<void*>(17))
+ EXPECT_EQ(100u, allocation.size);
+ if (allocation.address == reinterpret_cast<void*>(19))
+ EXPECT_EQ(kStdString, allocation.context.type_name);
+ }
+
+ reg.Remove(reinterpret_cast<void*>(17));
+ reg.Remove(reinterpret_cast<void*>(19));
+
+ EXPECT_EQ(nullptr, reg.Get(reinterpret_cast<void*>(17)));
+ EXPECT_EQ(nullptr, reg.Get(reinterpret_cast<void*>(19)));
+}
+
+// Check that the process aborts due to hitting the guard page when inserting
+// too many elements.
+#if GTEST_HAS_DEATH_TEST
+TEST_F(AllocationRegisterTest, OverflowDeathTest) {
+ // Use a smaller register to prevent OOM errors on low-end devices.
+ AllocationRegister reg(static_cast<uint32_t>(GetNumCellsPerPage()));
+ AllocationContext ctx = AllocationContext::Empty();
+ uintptr_t i;
+
+ // Fill up all of the memory allocated for the register. |GetNumCells(reg)|
+ // minus 1 elements are inserted, because cell 0 is unused, so this should
+ // fill up the available cells exactly.
+ for (i = 1; i < GetNumCells(reg); i++) {
+ reg.Insert(reinterpret_cast<void*>(i), 0, ctx);
+ }
+
+ // Adding just one extra element might still work because the allocated memory
+ // is rounded up to the page size. Adding a page full of elements should cause
+ // overflow.
+ const size_t cells_per_page = GetNumCellsPerPage();
+
+ ASSERT_DEATH(for (size_t j = 0; j < cells_per_page; j++) {
+ reg.Insert(reinterpret_cast<void*>(i + j), 0, ctx);
+ }, "");
+}
+#endif
+
+} // namespace trace_event
+} // namespace base
diff --git a/chromium/base/trace_event/heap_profiler_allocation_register_win.cc b/chromium/base/trace_event/heap_profiler_allocation_register_win.cc
new file mode 100644
index 00000000000..bc0afbf3401
--- /dev/null
+++ b/chromium/base/trace_event/heap_profiler_allocation_register_win.cc
@@ -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.
+
+#include "base/trace_event/heap_profiler_allocation_register.h"
+
+#include <windows.h>
+#include <stddef.h>
+
+#include "base/bits.h"
+#include "base/logging.h"
+#include "base/process/process_metrics.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+size_t GetGuardSize() {
+ return GetPageSize();
+}
+}
+
+// static
+void* AllocationRegister::AllocateVirtualMemory(size_t size) {
+ size = bits::Align(size, GetPageSize());
+
+ // Add space for a guard page at the end.
+ size_t map_size = size + GetGuardSize();
+
+ // Reserve the address space. This does not make the memory usable yet.
+ void* addr = VirtualAlloc(nullptr, map_size, MEM_RESERVE, PAGE_NOACCESS);
+
+ PCHECK(addr != nullptr);
+
+ // Commit the non-guard pages as read-write memory.
+ void* result = VirtualAlloc(addr, size, MEM_COMMIT, PAGE_READWRITE);
+
+ PCHECK(result != nullptr);
+
+ // Mark the last page of the allocated address space as guard page. (NB: The
+ // |PAGE_GUARD| flag is not the flag to use here, that flag can be used to
+ // detect and intercept access to a certain memory region. Accessing a
+ // |PAGE_NOACCESS| page will raise a general protection fault.) The
+ // read/write accessible space is still at least |min_size| bytes.
+ void* guard_addr =
+ reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(addr) + size);
+ result = VirtualAlloc(guard_addr, GetGuardSize(), MEM_COMMIT, PAGE_NOACCESS);
+ PCHECK(result != nullptr);
+
+ return addr;
+}
+
+// static
+void AllocationRegister::FreeVirtualMemory(void* address,
+ size_t allocated_size) {
+ // For |VirtualFree|, the size passed with |MEM_RELEASE| mut be 0. Windows
+ // automatically frees the entire region that was reserved by the
+ // |VirtualAlloc| with flag |MEM_RESERVE|.
+ VirtualFree(address, 0, MEM_RELEASE);
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/chromium/base/trace_event/heap_profiler_heap_dump_writer.cc b/chromium/base/trace_event/heap_profiler_heap_dump_writer.cc
new file mode 100644
index 00000000000..d14f8c47153
--- /dev/null
+++ b/chromium/base/trace_event/heap_profiler_heap_dump_writer.cc
@@ -0,0 +1,300 @@
+// 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/heap_profiler_heap_dump_writer.h"
+
+#include <stdint.h>
+
+#include <algorithm>
+#include <iterator>
+#include <tuple>
+#include <utility>
+#include <vector>
+
+#include "base/format_macros.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/heap_profiler_stack_frame_deduplicator.h"
+#include "base/trace_event/heap_profiler_type_name_deduplicator.h"
+#include "base/trace_event/trace_event_argument.h"
+
+// Most of what the |HeapDumpWriter| does is aggregating detailed information
+// about the heap and deciding what to dump. The Input to this process is a list
+// of |AllocationContext|s and size pairs.
+//
+// The pairs are grouped into |Bucket|s. A bucket is a group of (context, size)
+// pairs where the properties of the contexts share a prefix. (Type name is
+// considered a list of length one here.) First all pairs are put into one
+// bucket that represents the entire heap. Then this bucket is recursively
+// broken down into smaller buckets. Each bucket keeps track of whether further
+// breakdown is possible.
+
+namespace base {
+namespace trace_event {
+namespace internal {
+namespace {
+
+// Denotes a property of |AllocationContext| to break down by.
+enum class BreakDownMode { kByBacktrace, kByTypeName };
+
+// A group of bytes for which the context shares a prefix.
+struct Bucket {
+ Bucket() : size(0), backtrace_cursor(0), is_broken_down_by_type_name(false) {}
+
+ std::vector<std::pair<const AllocationContext*, size_t>> bytes_by_context;
+
+ // The sum of the sizes of |bytes_by_context|.
+ size_t size;
+
+ // The index of the stack frame that has not yet been broken down by. For all
+ // elements in this bucket, the stack frames 0 up to (but not including) the
+ // cursor, must be equal.
+ size_t backtrace_cursor;
+
+ // When true, the type name for all elements in this bucket must be equal.
+ bool is_broken_down_by_type_name;
+};
+
+// Comparison operator to order buckets by their size.
+bool operator<(const Bucket& lhs, const Bucket& rhs) {
+ return lhs.size < rhs.size;
+}
+
+// Groups the allocations in the bucket by |breakBy|. The buckets in the
+// returned list will have |backtrace_cursor| advanced or
+// |is_broken_down_by_type_name| set depending on the property to group by.
+std::vector<Bucket> GetSubbuckets(const Bucket& bucket, BreakDownMode breakBy) {
+ base::hash_map<const char*, Bucket> breakdown;
+
+ if (breakBy == BreakDownMode::kByBacktrace) {
+ for (const auto& context_and_size : bucket.bytes_by_context) {
+ const Backtrace& backtrace = context_and_size.first->backtrace;
+ const char* const* begin = std::begin(backtrace.frames);
+ const char* const* end = std::end(backtrace.frames);
+ const char* const* cursor = begin + bucket.backtrace_cursor;
+
+ // The backtrace in the context is padded with null pointers, but these
+ // should not be considered for breakdown. Adjust end to point past the
+ // last non-null frame.
+ while (begin != end && *(end - 1) == nullptr)
+ end--;
+
+ DCHECK_LE(cursor, end);
+
+ if (cursor != end) {
+ Bucket& subbucket = breakdown[*cursor];
+ subbucket.size += context_and_size.second;
+ subbucket.bytes_by_context.push_back(context_and_size);
+ subbucket.backtrace_cursor = bucket.backtrace_cursor + 1;
+ subbucket.is_broken_down_by_type_name =
+ bucket.is_broken_down_by_type_name;
+ DCHECK_GT(subbucket.size, 0u);
+ }
+ }
+ } else if (breakBy == BreakDownMode::kByTypeName) {
+ if (!bucket.is_broken_down_by_type_name) {
+ for (const auto& context_and_size : bucket.bytes_by_context) {
+ const AllocationContext* context = context_and_size.first;
+ Bucket& subbucket = breakdown[context->type_name];
+ subbucket.size += context_and_size.second;
+ subbucket.bytes_by_context.push_back(context_and_size);
+ subbucket.backtrace_cursor = bucket.backtrace_cursor;
+ subbucket.is_broken_down_by_type_name = true;
+ DCHECK_GT(subbucket.size, 0u);
+ }
+ }
+ }
+
+ std::vector<Bucket> buckets;
+ buckets.reserve(breakdown.size());
+ for (auto key_bucket : breakdown)
+ buckets.push_back(key_bucket.second);
+
+ return buckets;
+}
+
+// Breaks down the bucket by |breakBy|. Returns only buckets that contribute
+// significantly to the total size. The long tail is omitted.
+std::vector<Bucket> BreakDownBy(const Bucket& bucket, BreakDownMode breakBy) {
+ std::vector<Bucket> buckets = GetSubbuckets(bucket, breakBy);
+
+ // Ensure that |buckets| is a max-heap (the data structure, not memory heap),
+ // so its front contains the largest bucket. Buckets should be iterated
+ // ordered by size, but sorting the vector is overkill because the long tail
+ // of small buckets will be discarded. By using a max-heap, the optimal case
+ // where all but the first bucket are discarded is O(n). The worst case where
+ // no bucket is discarded is doing a heap sort, which is O(n log n).
+ std::make_heap(buckets.begin(), buckets.end());
+
+ // Keep including buckets until adding one would increase the number of
+ // bytes accounted for by less than a percent. The large buckets end up in
+ // [it, end()), [begin(), it) is the part that contains the max-heap of small
+ // buckets. TODO(ruuda): tweak the heuristic.
+ size_t accounted_for = 0;
+ std::vector<Bucket>::iterator it;
+ for (it = buckets.end(); it != buckets.begin(); --it) {
+ // Compute contribution to number of bytes accounted for in percent, rounded
+ // down due to integer division. Buckets are iterated by descending size,
+ // so later buckets cannot have a larger contribution than this one.
+ accounted_for += buckets.front().size;
+ size_t contribution = buckets.front().size * 100 / accounted_for;
+ if (contribution == 0)
+ break;
+
+ // Put the largest bucket in [begin, it) at |it - 1| and max-heapify
+ // [begin, it - 1). This puts the next largest bucket at |buckets.front()|.
+ std::pop_heap(buckets.begin(), it);
+ }
+
+ // At this point, |buckets| looks like this (numbers are bucket sizes):
+ //
+ // <-- max-heap of small buckets --->
+ // <-- large buckets by ascending size -->
+ // [ 19 | 11 | 13 | 7 | 2 | 5 | ... | 83 | 89 | 97 ]
+ // ^ ^ ^
+ // | | |
+ // begin() it end()
+
+ // Discard the long tail of buckets that contribute less than a percent.
+ buckets.erase(buckets.begin(), it);
+
+ return buckets;
+}
+
+} // namespace
+
+bool operator<(Entry lhs, Entry rhs) {
+ // There is no need to compare |size|. If the backtrace and type name are
+ // equal then the sizes must be equal as well.
+ return std::tie(lhs.stack_frame_id, lhs.type_id) <
+ std::tie(rhs.stack_frame_id, rhs.type_id);
+}
+
+HeapDumpWriter::HeapDumpWriter(StackFrameDeduplicator* stack_frame_deduplicator,
+ TypeNameDeduplicator* type_name_deduplicator)
+ : stack_frame_deduplicator_(stack_frame_deduplicator),
+ type_name_deduplicator_(type_name_deduplicator) {}
+
+HeapDumpWriter::~HeapDumpWriter() {}
+
+bool HeapDumpWriter::AddEntryForBucket(const Bucket& bucket) {
+ // The contexts in the bucket are all different, but the [begin, cursor) range
+ // is equal for all contexts in the bucket, and the type names are the same if
+ // |is_broken_down_by_type_name| is set.
+ DCHECK(!bucket.bytes_by_context.empty());
+
+ const AllocationContext* context = bucket.bytes_by_context.front().first;
+
+ const char* const* backtrace_begin = std::begin(context->backtrace.frames);
+ const char* const* backtrace_end = backtrace_begin + bucket.backtrace_cursor;
+ DCHECK_LE(bucket.backtrace_cursor, arraysize(context->backtrace.frames));
+
+ Entry entry;
+ entry.stack_frame_id =
+ stack_frame_deduplicator_->Insert(backtrace_begin, backtrace_end);
+
+ // Deduplicate the type name, or use ID -1 if type name is not set.
+ entry.type_id = bucket.is_broken_down_by_type_name
+ ? type_name_deduplicator_->Insert(context->type_name)
+ : -1;
+
+ entry.size = bucket.size;
+
+ auto position_and_inserted = entries_.insert(entry);
+ return position_and_inserted.second;
+}
+
+void HeapDumpWriter::BreakDown(const Bucket& bucket) {
+ auto by_backtrace = BreakDownBy(bucket, BreakDownMode::kByBacktrace);
+ auto by_type_name = BreakDownBy(bucket, BreakDownMode::kByTypeName);
+
+ // Insert entries for the buckets. If a bucket was not present before, it has
+ // not been broken down before, so recursively continue breaking down in that
+ // case. There might be multiple routes to the same entry (first break down
+ // by type name, then by backtrace, or first by backtrace and then by type),
+ // so a set is used to avoid dumping and breaking down entries more than once.
+
+ for (const Bucket& subbucket : by_backtrace)
+ if (AddEntryForBucket(subbucket))
+ BreakDown(subbucket);
+
+ for (const Bucket& subbucket : by_type_name)
+ if (AddEntryForBucket(subbucket))
+ BreakDown(subbucket);
+}
+
+const std::set<Entry>& HeapDumpWriter::Summarize(
+ const hash_map<AllocationContext, size_t>& bytes_by_context) {
+ // Start with one bucket that represents the entire heap. Iterate by
+ // reference, because the allocation contexts are going to point to allocation
+ // contexts stored in |bytes_by_context|.
+ Bucket root_bucket;
+ for (const auto& context_and_size : bytes_by_context) {
+ const AllocationContext* context = &context_and_size.first;
+ const size_t size = context_and_size.second;
+ root_bucket.bytes_by_context.push_back(std::make_pair(context, size));
+ root_bucket.size += size;
+ }
+
+ AddEntryForBucket(root_bucket);
+
+ // Recursively break down the heap and fill |entries_| with entries to dump.
+ BreakDown(root_bucket);
+
+ return entries_;
+}
+
+scoped_refptr<TracedValue> Serialize(const std::set<Entry>& entries) {
+ std::string buffer;
+ scoped_refptr<TracedValue> traced_value = new TracedValue;
+
+ traced_value->BeginArray("entries");
+
+ for (const Entry& entry : entries) {
+ traced_value->BeginDictionary();
+
+ // Format size as hexadecimal string into |buffer|.
+ SStringPrintf(&buffer, "%" PRIx64, static_cast<uint64_t>(entry.size));
+ traced_value->SetString("size", buffer);
+
+ if (entry.stack_frame_id == -1) {
+ // An empty backtrace (which will have ID -1) is represented by the empty
+ // string, because there is no leaf frame to reference in |stackFrames|.
+ traced_value->SetString("bt", "");
+ } else {
+ // Format index of the leaf frame as a string, because |stackFrames| is a
+ // dictionary, not an array.
+ SStringPrintf(&buffer, "%i", entry.stack_frame_id);
+ traced_value->SetString("bt", buffer);
+ }
+
+ // Type ID -1 (cumulative size for all types) is represented by the absence
+ // of the "type" key in the dictionary.
+ if (entry.type_id != -1) {
+ // Format the type ID as a string.
+ SStringPrintf(&buffer, "%i", entry.type_id);
+ traced_value->SetString("type", buffer);
+ }
+
+ traced_value->EndDictionary();
+ }
+
+ traced_value->EndArray(); // "entries"
+ return traced_value;
+}
+
+} // namespace internal
+
+scoped_refptr<TracedValue> ExportHeapDump(
+ const hash_map<AllocationContext, size_t>& bytes_by_size,
+ StackFrameDeduplicator* stack_frame_deduplicator,
+ TypeNameDeduplicator* type_name_deduplicator) {
+ internal::HeapDumpWriter writer(stack_frame_deduplicator,
+ type_name_deduplicator);
+ return Serialize(writer.Summarize(bytes_by_size));
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/chromium/base/trace_event/heap_profiler_heap_dump_writer.h b/chromium/base/trace_event/heap_profiler_heap_dump_writer.h
new file mode 100644
index 00000000000..41f5488e358
--- /dev/null
+++ b/chromium/base/trace_event/heap_profiler_heap_dump_writer.h
@@ -0,0 +1,106 @@
+// 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_HEAP_PROFILER_HEAP_DUMP_WRITER_H_
+#define BASE_TRACE_EVENT_HEAP_PROFILER_HEAP_DUMP_WRITER_H_
+
+#include <stddef.h>
+
+#include <set>
+
+#include "base/base_export.h"
+#include "base/containers/hash_tables.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/trace_event/heap_profiler_allocation_context.h"
+
+namespace base {
+namespace trace_event {
+
+class StackFrameDeduplicator;
+class TracedValue;
+class TypeNameDeduplicator;
+
+// Aggregates |bytes_by_context|, recursively breaks down the heap, and returns
+// a traced value with an "entries" array that can be dumped in the trace log,
+// following the format described in https://goo.gl/KY7zVE. The number of
+// entries is kept reasonable because long tails are not included.
+BASE_EXPORT scoped_refptr<TracedValue> ExportHeapDump(
+ const hash_map<AllocationContext, size_t>& bytes_by_context,
+ StackFrameDeduplicator* stack_frame_deduplicator,
+ TypeNameDeduplicator* type_name_deduplicator);
+
+namespace internal {
+
+namespace {
+struct Bucket;
+}
+
+// An entry in the "entries" array as described in https://goo.gl/KY7zVE.
+struct BASE_EXPORT Entry {
+ size_t size;
+
+ // References a backtrace in the stack frame deduplicator. -1 means empty
+ // backtrace (the root of the tree).
+ int stack_frame_id;
+
+ // References a type name in the type name deduplicator. -1 indicates that
+ // the size is the cumulative size for all types (the root of the tree).
+ int type_id;
+};
+
+// Comparison operator to enable putting |Entry| in a |std::set|.
+BASE_EXPORT bool operator<(Entry lhs, Entry rhs);
+
+// Serializes entries to an "entries" array in a traced value.
+BASE_EXPORT scoped_refptr<TracedValue> Serialize(const std::set<Entry>& dump);
+
+// Helper class to dump a snapshot of an |AllocationRegister| or other heap
+// bookkeeping structure into a |TracedValue|. This class is intended to be
+// used as a one-shot local instance on the stack.
+class BASE_EXPORT HeapDumpWriter {
+ public:
+ // The |StackFrameDeduplicator| and |TypeNameDeduplicator| are not owned. The
+ // heap dump writer assumes exclusive access to them during the lifetime of
+ // the dump writer.
+ HeapDumpWriter(StackFrameDeduplicator* stack_frame_deduplicator,
+ TypeNameDeduplicator* type_name_deduplicator);
+
+ ~HeapDumpWriter();
+
+ // Aggregates allocations to compute the total size of the heap, then breaks
+ // down the heap recursively. This produces the values that should be dumped
+ // in the "entries" array. The number of entries is kept reasonable because
+ // long tails are not included. Use |Serialize| to convert to a traced value.
+ const std::set<Entry>& Summarize(
+ const hash_map<AllocationContext, size_t>& bytes_by_context);
+
+ private:
+ // Inserts an |Entry| for |Bucket| into |entries_|. Returns false if the
+ // entry was present before, true if it was not.
+ bool AddEntryForBucket(const Bucket& bucket);
+
+ // Recursively breaks down a bucket into smaller buckets and adds entries for
+ // the buckets worth dumping to |entries_|.
+ void BreakDown(const Bucket& bucket);
+
+ // The collection of entries that is filled by |Summarize|.
+ std::set<Entry> entries_;
+
+ // Helper for generating the |stackFrames| dictionary. Not owned, must outlive
+ // this heap dump writer instance.
+ StackFrameDeduplicator* const stack_frame_deduplicator_;
+
+ // Helper for converting type names to IDs. Not owned, must outlive this heap
+ // dump writer instance.
+ TypeNameDeduplicator* const type_name_deduplicator_;
+
+ DISALLOW_COPY_AND_ASSIGN(HeapDumpWriter);
+};
+
+} // namespace internal
+} // namespace trace_event
+} // namespace base
+
+#endif // BASE_TRACE_EVENT_HEAP_PROFILER_HEAP_DUMP_WRITER_H_
diff --git a/chromium/base/trace_event/heap_profiler_heap_dump_writer_unittest.cc b/chromium/base/trace_event/heap_profiler_heap_dump_writer_unittest.cc
new file mode 100644
index 00000000000..2b94b5e4426
--- /dev/null
+++ b/chromium/base/trace_event/heap_profiler_heap_dump_writer_unittest.cc
@@ -0,0 +1,236 @@
+// 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 <stddef.h>
+
+#include <set>
+#include <string>
+
+#include "base/json/json_reader.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/trace_event/heap_profiler_allocation_context.h"
+#include "base/trace_event/heap_profiler_heap_dump_writer.h"
+#include "base/trace_event/heap_profiler_stack_frame_deduplicator.h"
+#include "base/trace_event/heap_profiler_type_name_deduplicator.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// Define all strings once, because the deduplicator requires pointer equality,
+// and string interning is unreliable.
+const char kBrowserMain[] = "BrowserMain";
+const char kRendererMain[] = "RendererMain";
+const char kCreateWidget[] = "CreateWidget";
+const char kInitialize[] = "Initialize";
+
+const char kInt[] = "int";
+const char kBool[] = "bool";
+const char kString[] = "string";
+
+} // namespace
+
+namespace base {
+namespace trace_event {
+namespace internal {
+
+scoped_ptr<const Value> WriteAndReadBack(const std::set<Entry>& entries) {
+ scoped_refptr<TracedValue> traced_value = Serialize(entries);
+ std::string json;
+ traced_value->AppendAsTraceFormat(&json);
+ return JSONReader::Read(json);
+}
+
+scoped_ptr<const DictionaryValue> WriteAndReadBackEntry(Entry entry) {
+ std::set<Entry> input_entries;
+ input_entries.insert(entry);
+
+ scoped_ptr<const Value> json_dict = WriteAndReadBack(input_entries);
+
+ // Note: Ideally these should use |ASSERT_TRUE| instead of |EXPECT_TRUE|, but
+ // |ASSERT_TRUE| can only be used in void functions.
+ const DictionaryValue* dictionary;
+ EXPECT_TRUE(json_dict->GetAsDictionary(&dictionary));
+
+ const ListValue* json_entries;
+ EXPECT_TRUE(dictionary->GetList("entries", &json_entries));
+
+ const DictionaryValue* json_entry;
+ EXPECT_TRUE(json_entries->GetDictionary(0, &json_entry));
+
+ return json_entry->CreateDeepCopy();
+}
+
+// Given a desired stack frame ID and type ID, looks up the entry in the set and
+// asserts that it is present and has the expected size.
+void AssertSizeEq(const std::set<Entry>& entries,
+ int stack_frame_id,
+ int type_id,
+ size_t expected_size) {
+ // The comparison operator for |Entry| does not take size into account, so by
+ // setting only stack frame ID and type ID, the real entry can be found.
+ Entry entry;
+ entry.stack_frame_id = stack_frame_id;
+ entry.type_id = type_id;
+ auto it = entries.find(entry);
+
+ ASSERT_NE(entries.end(), it) << "No entry found for sf = " << stack_frame_id
+ << ", type = " << type_id << ".";
+ ASSERT_EQ(expected_size, it->size) << "Wrong size for sf = " << stack_frame_id
+ << ", type = " << type_id << ".";
+}
+
+TEST(HeapDumpWriterTest, BacktraceIndex) {
+ Entry entry;
+ entry.stack_frame_id = -1; // -1 means empty backtrace.
+ entry.type_id = 0;
+ entry.size = 1;
+
+ scoped_ptr<const DictionaryValue> json_entry = WriteAndReadBackEntry(entry);
+
+ // For an empty backtrace, the "bt" key cannot reference a stack frame.
+ // Instead it should be set to the empty string.
+ std::string backtrace_index;
+ ASSERT_TRUE(json_entry->GetString("bt", &backtrace_index));
+ ASSERT_EQ("", backtrace_index);
+
+ // Also verify that a non-negative backtrace index is dumped properly.
+ entry.stack_frame_id = 2;
+ json_entry = WriteAndReadBackEntry(entry);
+ ASSERT_TRUE(json_entry->GetString("bt", &backtrace_index));
+ ASSERT_EQ("2", backtrace_index);
+}
+
+TEST(HeapDumpWriterTest, TypeId) {
+ Entry entry;
+ entry.type_id = -1; // -1 means sum over all types.
+ entry.stack_frame_id = 0;
+ entry.size = 1;
+
+ scoped_ptr<const DictionaryValue> json_entry = WriteAndReadBackEntry(entry);
+
+ // Entries for the cumulative size of all types should not have the "type"
+ // key set.
+ ASSERT_FALSE(json_entry->HasKey("type"));
+
+ // Also verify that a non-negative type ID is dumped properly.
+ entry.type_id = 2;
+ json_entry = WriteAndReadBackEntry(entry);
+ std::string type_id;
+ ASSERT_TRUE(json_entry->GetString("type", &type_id));
+ ASSERT_EQ("2", type_id);
+}
+
+TEST(HeapDumpWriterTest, SizeIsHexadecimalString) {
+ // Take a number between 2^63 and 2^64 (or between 2^31 and 2^32 if |size_t|
+ // is not 64 bits).
+ const size_t large_value =
+ sizeof(size_t) == 8 ? 0xffffffffffffffc5 : 0xffffff9d;
+ const char* large_value_str =
+ sizeof(size_t) == 8 ? "ffffffffffffffc5" : "ffffff9d";
+ Entry entry;
+ entry.type_id = 0;
+ entry.stack_frame_id = 0;
+ entry.size = large_value;
+
+ scoped_ptr<const DictionaryValue> json_entry = WriteAndReadBackEntry(entry);
+
+ std::string size;
+ ASSERT_TRUE(json_entry->GetString("size", &size));
+ ASSERT_EQ(large_value_str, size);
+}
+
+TEST(HeapDumpWriterTest, BacktraceTypeNameTable) {
+ hash_map<AllocationContext, size_t> bytes_by_context;
+
+ AllocationContext ctx = AllocationContext::Empty();
+ ctx.backtrace.frames[0] = kBrowserMain;
+ ctx.backtrace.frames[1] = kCreateWidget;
+ ctx.type_name = kInt;
+
+ // 10 bytes with context { type: int, bt: [BrowserMain, CreateWidget] }.
+ bytes_by_context[ctx] = 10;
+
+ ctx.type_name = kBool;
+
+ // 18 bytes with context { type: bool, bt: [BrowserMain, CreateWidget] }.
+ bytes_by_context[ctx] = 18;
+
+ ctx.backtrace.frames[0] = kRendererMain;
+ ctx.backtrace.frames[1] = kInitialize;
+
+ // 30 bytes with context { type: bool, bt: [RendererMain, Initialize] }.
+ bytes_by_context[ctx] = 30;
+
+ ctx.type_name = kString;
+
+ // 19 bytes with context { type: string, bt: [RendererMain, Initialize] }.
+ bytes_by_context[ctx] = 19;
+
+ // At this point the heap looks like this:
+ //
+ // | | CrWidget <- BrMain | Init <- RenMain | Sum |
+ // +--------+--------------------+-----------------+-----+
+ // | int | 10 | 0 | 10 |
+ // | bool | 18 | 30 | 48 |
+ // | string | 0 | 19 | 19 |
+ // +--------+--------------------+-----------------+-----+
+ // | Sum | 28 | 49 | 77 |
+
+ auto sf_deduplicator = make_scoped_refptr(new StackFrameDeduplicator);
+ auto tn_deduplicator = make_scoped_refptr(new TypeNameDeduplicator);
+ HeapDumpWriter writer(sf_deduplicator.get(), tn_deduplicator.get());
+ const std::set<Entry>& dump = writer.Summarize(bytes_by_context);
+
+ // Get the indices of the backtraces and types by adding them again to the
+ // deduplicator. Because they were added before, the same number is returned.
+ StackFrame bt0[] = {kRendererMain, kInitialize};
+ StackFrame bt1[] = {kBrowserMain, kCreateWidget};
+ int bt_renderer_main = sf_deduplicator->Insert(bt0, bt0 + 1);
+ int bt_browser_main = sf_deduplicator->Insert(bt1, bt1 + 1);
+ int bt_renderer_main_initialize = sf_deduplicator->Insert(bt0, bt0 + 2);
+ int bt_browser_main_create_widget = sf_deduplicator->Insert(bt1, bt1 + 2);
+ int type_id_int = tn_deduplicator->Insert(kInt);
+ int type_id_bool = tn_deduplicator->Insert(kBool);
+ int type_id_string = tn_deduplicator->Insert(kString);
+
+ // Full heap should have size 77.
+ AssertSizeEq(dump, -1, -1, 77);
+
+ // 49 bytes were allocated in RendererMain and children. Also check the type
+ // breakdown.
+ AssertSizeEq(dump, bt_renderer_main, -1, 49);
+ AssertSizeEq(dump, bt_renderer_main, type_id_bool, 30);
+ AssertSizeEq(dump, bt_renderer_main, type_id_string, 19);
+
+ // 28 bytes were allocated in BrowserMain and children. Also check the type
+ // breakdown.
+ AssertSizeEq(dump, bt_browser_main, -1, 28);
+ AssertSizeEq(dump, bt_browser_main, type_id_int, 10);
+ AssertSizeEq(dump, bt_browser_main, type_id_bool, 18);
+
+ // In this test all bytes are allocated in leaf nodes, so check again one
+ // level deeper.
+ AssertSizeEq(dump, bt_renderer_main_initialize, -1, 49);
+ AssertSizeEq(dump, bt_renderer_main_initialize, type_id_bool, 30);
+ AssertSizeEq(dump, bt_renderer_main_initialize, type_id_string, 19);
+ AssertSizeEq(dump, bt_browser_main_create_widget, -1, 28);
+ AssertSizeEq(dump, bt_browser_main_create_widget, type_id_int, 10);
+ AssertSizeEq(dump, bt_browser_main_create_widget, type_id_bool, 18);
+
+ // The type breakdown of the entrie heap should have been dumped as well.
+ AssertSizeEq(dump, -1, type_id_int, 10);
+ AssertSizeEq(dump, -1, type_id_bool, 48);
+ AssertSizeEq(dump, -1, type_id_string, 19);
+}
+
+// TODO(ruuda): Verify that cumulative sizes are computed correctly.
+// TODO(ruuda): Verify that insignificant values are not dumped.
+
+} // namespace internal
+} // namespace trace_event
+} // namespace base
diff --git a/chromium/base/trace_event/heap_profiler_stack_frame_deduplicator.cc b/chromium/base/trace_event/heap_profiler_stack_frame_deduplicator.cc
new file mode 100644
index 00000000000..cf3d1987979
--- /dev/null
+++ b/chromium/base/trace_event/heap_profiler_stack_frame_deduplicator.cc
@@ -0,0 +1,115 @@
+// 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/heap_profiler_stack_frame_deduplicator.h"
+
+#include <stddef.h>
+
+#include <string>
+#include <utility>
+
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "base/trace_event/trace_event_memory_overhead.h"
+
+namespace base {
+namespace trace_event {
+
+StackFrameDeduplicator::FrameNode::FrameNode(StackFrame frame,
+ int parent_frame_index)
+ : frame(frame), parent_frame_index(parent_frame_index) {}
+StackFrameDeduplicator::FrameNode::~FrameNode() {}
+
+StackFrameDeduplicator::StackFrameDeduplicator() {}
+StackFrameDeduplicator::~StackFrameDeduplicator() {}
+
+int StackFrameDeduplicator::Insert(const StackFrame* beginFrame,
+ const StackFrame* endFrame) {
+ int frame_index = -1;
+ std::map<StackFrame, int>* nodes = &roots_;
+
+ // Loop through the frames, early out when a frame is null.
+ for (const StackFrame* it = beginFrame; it != endFrame && *it; it++) {
+ StackFrame frame = *it;
+
+ auto node = nodes->find(frame);
+ if (node == nodes->end()) {
+ // There is no tree node for this frame yet, create it. The parent node
+ // is the node associated with the previous frame.
+ FrameNode frame_node(frame, frame_index);
+
+ // The new frame node will be appended, so its index is the current size
+ // of the vector.
+ frame_index = static_cast<int>(frames_.size());
+
+ // Add the node to the trie so it will be found next time.
+ nodes->insert(std::make_pair(frame, frame_index));
+
+ // Append the node after modifying |nodes|, because the |frames_| vector
+ // might need to resize, and this invalidates the |nodes| pointer.
+ frames_.push_back(frame_node);
+ } else {
+ // A tree node for this frame exists. Look for the next one.
+ frame_index = node->second;
+ }
+
+ nodes = &frames_[frame_index].children;
+ }
+
+ return frame_index;
+}
+
+void StackFrameDeduplicator::AppendAsTraceFormat(std::string* out) const {
+ out->append("{"); // Begin the |stackFrames| dictionary.
+
+ int i = 0;
+ auto frame_node = begin();
+ auto it_end = end();
+ std::string stringify_buffer;
+
+ while (frame_node != it_end) {
+ // The |stackFrames| format is a dictionary, not an array, so the
+ // keys are stringified indices. Write the index manually, then use
+ // |TracedValue| to format the object. This is to avoid building the
+ // entire dictionary as a |TracedValue| in memory.
+ SStringPrintf(&stringify_buffer, "\"%d\":", i);
+ out->append(stringify_buffer);
+
+ scoped_refptr<TracedValue> frame_node_value = new TracedValue;
+ frame_node_value->SetString("name", frame_node->frame);
+ if (frame_node->parent_frame_index >= 0) {
+ SStringPrintf(&stringify_buffer, "%d", frame_node->parent_frame_index);
+ frame_node_value->SetString("parent", stringify_buffer);
+ }
+ frame_node_value->AppendAsTraceFormat(out);
+
+ i++;
+ frame_node++;
+
+ if (frame_node != it_end)
+ out->append(",");
+ }
+
+ out->append("}"); // End the |stackFrames| dictionary.
+}
+
+void StackFrameDeduplicator::EstimateTraceMemoryOverhead(
+ TraceEventMemoryOverhead* overhead) {
+ // The sizes here are only estimates; they fail to take into account the
+ // overhead of the tree nodes for the map, but as an estimate this should be
+ // fine.
+ size_t maps_size = roots_.size() * sizeof(std::pair<StackFrame, int>);
+ size_t frames_allocated = frames_.capacity() * sizeof(FrameNode);
+ size_t frames_resident = frames_.size() * sizeof(FrameNode);
+
+ for (const FrameNode& node : frames_)
+ maps_size += node.children.size() * sizeof(std::pair<StackFrame, int>);
+
+ overhead->Add("StackFrameDeduplicator",
+ sizeof(StackFrameDeduplicator) + maps_size + frames_allocated,
+ sizeof(StackFrameDeduplicator) + maps_size + frames_resident);
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/chromium/base/trace_event/heap_profiler_stack_frame_deduplicator.h b/chromium/base/trace_event/heap_profiler_stack_frame_deduplicator.h
new file mode 100644
index 00000000000..60df1ba8b40
--- /dev/null
+++ b/chromium/base/trace_event/heap_profiler_stack_frame_deduplicator.h
@@ -0,0 +1,79 @@
+// 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_HEAP_PROFILER_STACK_FRAME_DEDUPLICATOR_H_
+#define BASE_TRACE_EVENT_HEAP_PROFILER_STACK_FRAME_DEDUPLICATOR_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "base/trace_event/heap_profiler_allocation_context.h"
+#include "base/trace_event/trace_event_impl.h"
+
+namespace base {
+namespace trace_event {
+
+class TraceEventMemoryOverhead;
+
+// A data structure that allows grouping a set of backtraces in a space-
+// efficient manner by creating a call tree and writing it as a set of (node,
+// parent) pairs. The tree nodes reference both parent and children. The parent
+// is referenced by index into |frames_|. The children are referenced via a map
+// of |StackFrame|s to index into |frames_|. So there is a trie for bottum-up
+// lookup of a backtrace for deduplication, and a tree for compact storage in
+// the trace log.
+class BASE_EXPORT StackFrameDeduplicator : public ConvertableToTraceFormat {
+ public:
+ // A node in the call tree.
+ struct FrameNode {
+ FrameNode(StackFrame frame, int parent_frame_index);
+ ~FrameNode();
+
+ StackFrame frame;
+
+ // The index of the parent stack frame in |frames_|, or -1 if there is no
+ // parent frame (when it is at the bottom of the call stack).
+ int parent_frame_index;
+
+ // Indices into |frames_| of frames called from the current frame.
+ std::map<StackFrame, int> children;
+ };
+
+ using ConstIterator = std::vector<FrameNode>::const_iterator;
+
+ StackFrameDeduplicator();
+
+ // Inserts a backtrace where |beginFrame| is a pointer to the bottom frame
+ // (e.g. main) and |endFrame| is a pointer past the top frame (most recently
+ // called function), and returns the index of its leaf node in |frames_|.
+ // Returns -1 if the backtrace is empty.
+ int Insert(const StackFrame* beginFrame, const StackFrame* endFrame);
+
+ // Iterators over the frame nodes in the call tree.
+ ConstIterator begin() const { return frames_.begin(); }
+ ConstIterator end() const { return frames_.end(); }
+
+ // Writes the |stackFrames| dictionary as defined in https://goo.gl/GerkV8 to
+ // the trace log.
+ void AppendAsTraceFormat(std::string* out) const override;
+
+ // Estimates memory overhead including |sizeof(StackFrameDeduplicator)|.
+ void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead) override;
+
+ private:
+ ~StackFrameDeduplicator() override;
+
+ std::map<StackFrame, int> roots_;
+ std::vector<FrameNode> frames_;
+
+ DISALLOW_COPY_AND_ASSIGN(StackFrameDeduplicator);
+};
+
+} // namespace trace_event
+} // namespace base
+
+#endif // BASE_TRACE_EVENT_HEAP_PROFILER_STACK_FRAME_DEDUPLICATOR_H_
diff --git a/chromium/base/trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc b/chromium/base/trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc
new file mode 100644
index 00000000000..433c633ca54
--- /dev/null
+++ b/chromium/base/trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc
@@ -0,0 +1,134 @@
+// 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 <iterator>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/trace_event/heap_profiler_allocation_context.h"
+#include "base/trace_event/heap_profiler_stack_frame_deduplicator.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+// Define all strings once, because the deduplicator requires pointer equality,
+// and string interning is unreliable.
+const char kBrowserMain[] = "BrowserMain";
+const char kRendererMain[] = "RendererMain";
+const char kCreateWidget[] = "CreateWidget";
+const char kInitialize[] = "Initialize";
+const char kMalloc[] = "malloc";
+
+TEST(StackFrameDeduplicatorTest, SingleBacktrace) {
+ StackFrame bt[] = {kBrowserMain, kCreateWidget, kMalloc};
+
+ // The call tree should look like this (index in brackets).
+ //
+ // BrowserMain [0]
+ // CreateWidget [1]
+ // malloc [2]
+
+ scoped_refptr<StackFrameDeduplicator> dedup = new StackFrameDeduplicator;
+ ASSERT_EQ(2, dedup->Insert(std::begin(bt), std::end(bt)));
+
+ auto iter = dedup->begin();
+ ASSERT_EQ(kBrowserMain, (iter + 0)->frame);
+ ASSERT_EQ(-1, (iter + 0)->parent_frame_index);
+
+ ASSERT_EQ(kCreateWidget, (iter + 1)->frame);
+ ASSERT_EQ(0, (iter + 1)->parent_frame_index);
+
+ ASSERT_EQ(kMalloc, (iter + 2)->frame);
+ ASSERT_EQ(1, (iter + 2)->parent_frame_index);
+
+ ASSERT_EQ(iter + 3, dedup->end());
+}
+
+// Test that there can be different call trees (there can be multiple bottom
+// frames). Also verify that frames with the same name but a different caller
+// are represented as distinct nodes.
+TEST(StackFrameDeduplicatorTest, MultipleRoots) {
+ StackFrame bt0[] = {kBrowserMain, kCreateWidget};
+ StackFrame bt1[] = {kRendererMain, kCreateWidget};
+
+ // The call tree should look like this (index in brackets).
+ //
+ // BrowserMain [0]
+ // CreateWidget [1]
+ // RendererMain [2]
+ // CreateWidget [3]
+ //
+ // Note that there will be two instances of CreateWidget,
+ // with different parents.
+
+ scoped_refptr<StackFrameDeduplicator> dedup = new StackFrameDeduplicator;
+ ASSERT_EQ(1, dedup->Insert(std::begin(bt0), std::end(bt0)));
+ ASSERT_EQ(3, dedup->Insert(std::begin(bt1), std::end(bt1)));
+
+ auto iter = dedup->begin();
+ ASSERT_EQ(kBrowserMain, (iter + 0)->frame);
+ ASSERT_EQ(-1, (iter + 0)->parent_frame_index);
+
+ ASSERT_EQ(kCreateWidget, (iter + 1)->frame);
+ ASSERT_EQ(0, (iter + 1)->parent_frame_index);
+
+ ASSERT_EQ(kRendererMain, (iter + 2)->frame);
+ ASSERT_EQ(-1, (iter + 2)->parent_frame_index);
+
+ ASSERT_EQ(kCreateWidget, (iter + 3)->frame);
+ ASSERT_EQ(2, (iter + 3)->parent_frame_index);
+
+ ASSERT_EQ(iter + 4, dedup->end());
+}
+
+TEST(StackFrameDeduplicatorTest, Deduplication) {
+ StackFrame bt0[] = {kBrowserMain, kCreateWidget};
+ StackFrame bt1[] = {kBrowserMain, kInitialize};
+
+ // The call tree should look like this (index in brackets).
+ //
+ // BrowserMain [0]
+ // CreateWidget [1]
+ // Initialize [2]
+ //
+ // Note that BrowserMain will be re-used.
+
+ scoped_refptr<StackFrameDeduplicator> dedup = new StackFrameDeduplicator;
+ ASSERT_EQ(1, dedup->Insert(std::begin(bt0), std::end(bt0)));
+ ASSERT_EQ(2, dedup->Insert(std::begin(bt1), std::end(bt1)));
+
+ auto iter = dedup->begin();
+ ASSERT_EQ(kBrowserMain, (iter + 0)->frame);
+ ASSERT_EQ(-1, (iter + 0)->parent_frame_index);
+
+ ASSERT_EQ(kCreateWidget, (iter + 1)->frame);
+ ASSERT_EQ(0, (iter + 1)->parent_frame_index);
+
+ ASSERT_EQ(kInitialize, (iter + 2)->frame);
+ ASSERT_EQ(0, (iter + 2)->parent_frame_index);
+
+ ASSERT_EQ(iter + 3, dedup->end());
+
+ // Inserting the same backtrace again should return the index of the existing
+ // node.
+ ASSERT_EQ(1, dedup->Insert(std::begin(bt0), std::end(bt0)));
+ ASSERT_EQ(2, dedup->Insert(std::begin(bt1), std::end(bt1)));
+ ASSERT_EQ(dedup->begin() + 3, dedup->end());
+}
+
+TEST(StackFrameDeduplicatorTest, NullPaddingIsRemoved) {
+ StackFrame bt0[] = {kBrowserMain, nullptr, nullptr, nullptr};
+
+ scoped_refptr<StackFrameDeduplicator> dedup = new StackFrameDeduplicator;
+
+ // There are four frames in the backtrace, but the null pointers should be
+ // skipped, so only one frame is inserted, which will have index 0.
+ ASSERT_EQ(4u, arraysize(bt0));
+ ASSERT_EQ(0, dedup->Insert(std::begin(bt0), std::end(bt0)));
+ ASSERT_EQ(dedup->begin() + 1, dedup->end());
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/chromium/base/trace_event/heap_profiler_type_name_deduplicator.cc b/chromium/base/trace_event/heap_profiler_type_name_deduplicator.cc
new file mode 100644
index 00000000000..e7f57c8ae0e
--- /dev/null
+++ b/chromium/base/trace_event/heap_profiler_type_name_deduplicator.cc
@@ -0,0 +1,76 @@
+// 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/heap_profiler_type_name_deduplicator.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string>
+#include <utility>
+
+#include "base/json/string_escape.h"
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/trace_event_memory_overhead.h"
+
+namespace base {
+namespace trace_event {
+
+TypeNameDeduplicator::TypeNameDeduplicator() {
+ // A null pointer has type ID 0 ("unknown type");
+ type_ids_.insert(std::make_pair(nullptr, 0));
+}
+
+TypeNameDeduplicator::~TypeNameDeduplicator() {}
+
+int TypeNameDeduplicator::Insert(const char* type_name) {
+ auto result = type_ids_.insert(std::make_pair(type_name, 0));
+ auto& elem = result.first;
+ bool did_not_exist_before = result.second;
+
+ if (did_not_exist_before) {
+ // The type IDs are assigned sequentially and they are zero-based, so
+ // |size() - 1| is the ID of the new element.
+ elem->second = static_cast<int>(type_ids_.size() - 1);
+ }
+
+ return elem->second;
+}
+
+void TypeNameDeduplicator::AppendAsTraceFormat(std::string* out) const {
+ out->append("{"); // Begin the type names dictionary.
+
+ auto it = type_ids_.begin();
+ std::string buffer;
+
+ // Write the first entry manually; the null pointer must not be dereferenced.
+ // (The first entry is the null pointer because a |std::map| is ordered.)
+ it++;
+ out->append("\"0\":\"[unknown]\"");
+
+ for (; it != type_ids_.end(); it++) {
+ // Type IDs in the trace are strings, write them as stringified keys of
+ // a dictionary.
+ SStringPrintf(&buffer, ",\"%d\":", it->second);
+
+ // |EscapeJSONString| appends, it does not overwrite |buffer|.
+ bool put_in_quotes = true;
+ EscapeJSONString(it->first, put_in_quotes, &buffer);
+ out->append(buffer);
+ }
+
+ out->append("}"); // End the type names dictionary.
+}
+
+void TypeNameDeduplicator::EstimateTraceMemoryOverhead(
+ TraceEventMemoryOverhead* overhead) {
+ // The size here is only an estimate; it fails to take into account the size
+ // of the tree nodes for the map, but as an estimate this should be fine.
+ size_t map_size = type_ids_.size() * sizeof(std::pair<const char*, int>);
+
+ overhead->Add("TypeNameDeduplicator",
+ sizeof(TypeNameDeduplicator) + map_size);
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/chromium/base/trace_event/heap_profiler_type_name_deduplicator.h b/chromium/base/trace_event/heap_profiler_type_name_deduplicator.h
new file mode 100644
index 00000000000..317ea5ee1e3
--- /dev/null
+++ b/chromium/base/trace_event/heap_profiler_type_name_deduplicator.h
@@ -0,0 +1,46 @@
+// 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_HEAP_PROFILER_TYPE_NAME_DEDUPLICATOR_H_
+#define BASE_TRACE_EVENT_HEAP_PROFILER_TYPE_NAME_DEDUPLICATOR_H_
+
+#include <map>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/macros.h"
+#include "base/trace_event/trace_event_impl.h"
+
+namespace base {
+namespace trace_event {
+
+class TraceEventMemoryOverhead;
+
+// Data structure that assigns a unique numeric ID to |const char*|s.
+class BASE_EXPORT TypeNameDeduplicator : public ConvertableToTraceFormat {
+ public:
+ TypeNameDeduplicator();
+
+ // Inserts a type name and returns its ID.
+ int Insert(const char* type_name);
+
+ // Estimates memory overhead including |sizeof(TypeNameDeduplicator)|.
+ void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead) override;
+
+ private:
+ ~TypeNameDeduplicator() override;
+
+ // Writes the type ID -> type name mapping to the trace log.
+ void AppendAsTraceFormat(std::string* out) const override;
+
+ // Map from type name to type ID.
+ std::map<const char*, int> type_ids_;
+
+ DISALLOW_COPY_AND_ASSIGN(TypeNameDeduplicator);
+};
+
+} // namespace trace_event
+} // namespace base
+
+#endif // BASE_TRACE_EVENT_HEAP_PROFILER_TYPE_NAME_DEDUPLICATOR_H_
diff --git a/chromium/base/trace_event/heap_profiler_type_name_deduplicator_unittest.cc b/chromium/base/trace_event/heap_profiler_type_name_deduplicator_unittest.cc
new file mode 100644
index 00000000000..82c8fb505e7
--- /dev/null
+++ b/chromium/base/trace_event/heap_profiler_type_name_deduplicator_unittest.cc
@@ -0,0 +1,71 @@
+// 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 <string>
+
+#include "base/json/json_reader.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/trace_event/heap_profiler_type_name_deduplicator.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+// Define all strings once, because the deduplicator requires pointer equality,
+// and string interning is unreliable.
+const char kInt[] = "int";
+const char kBool[] = "bool";
+const char kString[] = "string";
+const char kNeedsEscape[] = "\"quotes\"";
+
+scoped_ptr<Value> DumpAndReadBack(const ConvertableToTraceFormat& convertable) {
+ std::string json;
+ convertable.AppendAsTraceFormat(&json);
+ return JSONReader::Read(json);
+}
+
+TEST(TypeNameDeduplicatorTest, Deduplication) {
+ // The type IDs should be like this:
+ // 0: [unknown]
+ // 1: int
+ // 2: bool
+ // 3: string
+
+ scoped_refptr<TypeNameDeduplicator> dedup = new TypeNameDeduplicator;
+ ASSERT_EQ(1, dedup->Insert(kInt));
+ ASSERT_EQ(2, dedup->Insert(kBool));
+ ASSERT_EQ(3, dedup->Insert(kString));
+
+ // Inserting again should return the same IDs.
+ ASSERT_EQ(2, dedup->Insert(kBool));
+ ASSERT_EQ(1, dedup->Insert(kInt));
+ ASSERT_EQ(3, dedup->Insert(kString));
+
+ // A null pointer should yield type ID 0.
+ ASSERT_EQ(0, dedup->Insert(nullptr));
+}
+
+TEST(TypeNameDeduplicatorTest, EscapeTypeName) {
+ scoped_refptr<TypeNameDeduplicator> dedup = new TypeNameDeduplicator;
+ ASSERT_EQ(1, dedup->Insert(kNeedsEscape));
+
+ // Reading json should not fail, because the type name should have been
+ // escaped properly.
+ scoped_ptr<Value> type_names = DumpAndReadBack(*dedup);
+ ASSERT_NE(nullptr, type_names);
+
+ const DictionaryValue* dictionary;
+ ASSERT_TRUE(type_names->GetAsDictionary(&dictionary));
+
+ // When the type name was inserted, it got ID 1. The exported key "1"
+ // should contain the name, with quotes.
+ std::string type_name;
+ ASSERT_TRUE(dictionary->GetString("1", &type_name));
+ ASSERT_EQ("\"quotes\"", type_name);
+}
+
+} // 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
index e69c28102ad..b9f2333089c 100644
--- a/chromium/base/trace_event/java_heap_dump_provider_android.h
+++ b/chromium/base/trace_event/java_heap_dump_provider_android.h
@@ -5,6 +5,7 @@
#ifndef BASE_TRACE_EVENT_JAVA_HEAP_DUMP_PROVIDER_ANDROID_H_
#define BASE_TRACE_EVENT_JAVA_HEAP_DUMP_PROVIDER_ANDROID_H_
+#include "base/macros.h"
#include "base/memory/singleton.h"
#include "base/trace_event/memory_dump_provider.h"
diff --git a/chromium/base/trace_event/malloc_dump_provider.cc b/chromium/base/trace_event/malloc_dump_provider.cc
index 28aa140d670..6f9aa9602f7 100644
--- a/chromium/base/trace_event/malloc_dump_provider.cc
+++ b/chromium/base/trace_event/malloc_dump_provider.cc
@@ -4,9 +4,17 @@
#include "base/trace_event/malloc_dump_provider.h"
-#include <malloc.h>
+#include <stddef.h>
+#include "base/allocator/allocator_extension.h"
#include "base/trace_event/process_memory_dump.h"
+#include "build/build_config.h"
+
+#if defined(OS_MACOSX)
+#include <malloc/malloc.h>
+#else
+#include <malloc.h>
+#endif
namespace base {
namespace trace_event {
@@ -20,33 +28,73 @@ MallocDumpProvider* MallocDumpProvider::GetInstance() {
LeakySingletonTraits<MallocDumpProvider>>::get();
}
-MallocDumpProvider::MallocDumpProvider() {
-}
+MallocDumpProvider::MallocDumpProvider() {}
-MallocDumpProvider::~MallocDumpProvider() {
-}
+MallocDumpProvider::~MallocDumpProvider() {}
// Called at trace dump point time. Creates a snapshot the memory counters for
// the current process.
bool MallocDumpProvider::OnMemoryDump(const MemoryDumpArgs& args,
ProcessMemoryDump* pmd) {
+ size_t total_virtual_size = 0;
+ size_t resident_size = 0;
+ size_t allocated_objects_size = 0;
+#if defined(USE_TCMALLOC)
+ bool res =
+ allocator::GetNumericProperty("generic.heap_size", &total_virtual_size);
+ DCHECK(res);
+ res = allocator::GetNumericProperty("generic.total_physical_bytes",
+ &resident_size);
+ DCHECK(res);
+ res = allocator::GetNumericProperty("generic.current_allocated_bytes",
+ &allocated_objects_size);
+ DCHECK(res);
+#elif defined(OS_MACOSX) || defined(OS_IOS)
+ malloc_statistics_t stats = {0};
+ malloc_zone_statistics(nullptr, &stats);
+ total_virtual_size = stats.size_allocated;
+ allocated_objects_size = stats.size_in_use;
+
+ // The resident size is approximated to the max size in use, which would count
+ // the total size of all regions other than the free bytes at the end of each
+ // region. In each allocation region the allocations are rounded off to a
+ // fixed quantum, so the excess region will not be resident.
+ // See crrev.com/1531463004 for detailed explanation.
+ resident_size = stats.max_size_in_use;
+#else
struct mallinfo info = mallinfo();
DCHECK_GE(info.arena + info.hblkhd, info.uordblks);
- // When the system allocator is implemented by tcmalloc, the total heap
- // 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.
+ // 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.
+ total_virtual_size = info.arena + info.hblkhd;
+ resident_size = info.uordblks;
+ allocated_objects_size = info.uordblks;
+#endif
+
MemoryAllocatorDump* outer_dump = pmd->CreateAllocatorDump("malloc");
- outer_dump->AddScalar("virtual_size",
- MemoryAllocatorDump::kUnitsBytes,
- info.arena + info.hblkhd);
+ outer_dump->AddScalar("virtual_size", MemoryAllocatorDump::kUnitsBytes,
+ total_virtual_size);
+ outer_dump->AddScalar(MemoryAllocatorDump::kNameSize,
+ MemoryAllocatorDump::kUnitsBytes, resident_size);
// Total allocated space is given by |uordblks|.
MemoryAllocatorDump* inner_dump = pmd->CreateAllocatorDump(kAllocatedObjects);
inner_dump->AddScalar(MemoryAllocatorDump::kNameSize,
- MemoryAllocatorDump::kUnitsBytes, info.uordblks);
+ MemoryAllocatorDump::kUnitsBytes,
+ allocated_objects_size);
+
+ if (resident_size - allocated_objects_size > 0) {
+ // Explicitly specify why is extra memory resident. In tcmalloc it accounts
+ // for free lists and caches. In mac and ios it accounts for the
+ // fragmentation and metadata.
+ MemoryAllocatorDump* other_dump =
+ pmd->CreateAllocatorDump("malloc/metadata_fragmentation_caches");
+ other_dump->AddScalar(MemoryAllocatorDump::kNameSize,
+ MemoryAllocatorDump::kUnitsBytes,
+ resident_size - allocated_objects_size);
+ }
return true;
}
diff --git a/chromium/base/trace_event/malloc_dump_provider.h b/chromium/base/trace_event/malloc_dump_provider.h
index f35199937ea..63fc1b08267 100644
--- a/chromium/base/trace_event/malloc_dump_provider.h
+++ b/chromium/base/trace_event/malloc_dump_provider.h
@@ -7,8 +7,15 @@
#include <istream>
+#include "base/macros.h"
#include "base/memory/singleton.h"
#include "base/trace_event/memory_dump_provider.h"
+#include "build/build_config.h"
+
+#if defined(OS_LINUX) || defined(OS_ANDROID) || \
+ (defined(OS_MACOSX) && !defined(OS_IOS))
+#define MALLOC_MEMORY_TRACING_SUPPORTED
+#endif
namespace base {
namespace trace_event {
diff --git a/chromium/base/trace_event/memory_allocator_dump.cc b/chromium/base/trace_event/memory_allocator_dump.cc
index 76d53eb4762..5c5af7ee458 100644
--- a/chromium/base/trace_event/memory_allocator_dump.cc
+++ b/chromium/base/trace_event/memory_allocator_dump.cc
@@ -35,10 +35,6 @@ MemoryAllocatorDump::MemoryAllocatorDump(const std::string& absolute_name,
// 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('.'));
}
// If the caller didn't provide a guid, make one up by hashing the
@@ -61,7 +57,7 @@ MemoryAllocatorDump::~MemoryAllocatorDump() {
void MemoryAllocatorDump::AddScalar(const char* name,
const char* units,
- uint64 value) {
+ uint64_t value) {
SStringPrintf(&string_conversion_buffer_, "%" PRIx64, value);
attributes_->BeginDictionary(name);
attributes_->SetString("type", kTypeScalar);
diff --git a/chromium/base/trace_event/memory_allocator_dump.h b/chromium/base/trace_event/memory_allocator_dump.h
index 6ad3d64110e..6c514fa6a62 100644
--- a/chromium/base/trace_event/memory_allocator_dump.h
+++ b/chromium/base/trace_event/memory_allocator_dump.h
@@ -5,11 +5,13 @@
#ifndef BASE_TRACE_EVENT_MEMORY_ALLOCATOR_DUMP_H_
#define BASE_TRACE_EVENT_MEMORY_ALLOCATOR_DUMP_H_
+#include <stdint.h>
+
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/trace_event/memory_allocator_dump_guid.h"
#include "base/values.h"
@@ -51,7 +53,7 @@ class BASE_EXPORT MemoryAllocatorDump {
// AddScalar("number_of_freelist_entires", kUnitsObjects, 42)
// - Other informational column (will not be auto-added in the UI)
// AddScalarF("kittens_ratio", "ratio", 42.0f)
- void AddScalar(const char* name, const char* units, uint64 value);
+ void AddScalar(const char* name, const char* units, uint64_t value);
void AddScalarF(const char* name, const char* units, double value);
void AddString(const char* name, const char* units, const std::string& value);
diff --git a/chromium/base/trace_event/memory_allocator_dump_guid.cc b/chromium/base/trace_event/memory_allocator_dump_guid.cc
index d4ed900b9fe..bf4389a4c75 100644
--- a/chromium/base/trace_event/memory_allocator_dump_guid.cc
+++ b/chromium/base/trace_event/memory_allocator_dump_guid.cc
@@ -12,16 +12,15 @@ namespace base {
namespace trace_event {
namespace {
-uint64 HashString(const std::string& str) {
- uint64 hash[(kSHA1Length + sizeof(uint64) - 1) / sizeof(uint64)] = { 0 };
+uint64_t HashString(const std::string& str) {
+ uint64_t hash[(kSHA1Length + sizeof(uint64_t) - 1) / sizeof(uint64_t)] = {0};
SHA1HashBytes(reinterpret_cast<const unsigned char*>(str.data()), str.size(),
reinterpret_cast<unsigned char*>(hash));
return hash[0];
}
} // namespace
-MemoryAllocatorDumpGuid::MemoryAllocatorDumpGuid(uint64 guid) : guid_(guid) {
-}
+MemoryAllocatorDumpGuid::MemoryAllocatorDumpGuid(uint64_t guid) : guid_(guid) {}
MemoryAllocatorDumpGuid::MemoryAllocatorDumpGuid()
: MemoryAllocatorDumpGuid(0u) {
diff --git a/chromium/base/trace_event/memory_allocator_dump_guid.h b/chromium/base/trace_event/memory_allocator_dump_guid.h
index 634ca8133b5..b6472c66129 100644
--- a/chromium/base/trace_event/memory_allocator_dump_guid.h
+++ b/chromium/base/trace_event/memory_allocator_dump_guid.h
@@ -5,10 +5,11 @@
#ifndef BASE_TRACE_EVENT_MEMORY_ALLOCATOR_DUMP_GUID_H_
#define BASE_TRACE_EVENT_MEMORY_ALLOCATOR_DUMP_GUID_H_
+#include <stdint.h>
+
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
namespace base {
namespace trace_event {
@@ -16,14 +17,14 @@ namespace trace_event {
class BASE_EXPORT MemoryAllocatorDumpGuid {
public:
MemoryAllocatorDumpGuid();
- explicit MemoryAllocatorDumpGuid(uint64 guid);
+ explicit MemoryAllocatorDumpGuid(uint64_t guid);
// Utility ctor to hash a GUID if the caller prefers a string. The caller
// still has to ensure that |guid_str| is unique, per snapshot, within the
// global scope of all the traced processes.
explicit MemoryAllocatorDumpGuid(const std::string& guid_str);
- uint64 ToUint64() const { return guid_; }
+ uint64_t ToUint64() const { return guid_; }
// Returns a (hex-encoded) string representation of the guid.
std::string ToString() const;
@@ -39,7 +40,7 @@ class BASE_EXPORT MemoryAllocatorDumpGuid {
}
private:
- uint64 guid_;
+ uint64_t guid_;
// Deliberately copy-able.
};
diff --git a/chromium/base/trace_event/memory_allocator_dump_unittest.cc b/chromium/base/trace_event/memory_allocator_dump_unittest.cc
index f787e64f067..d1cfe91a4f1 100644
--- a/chromium/base/trace_event/memory_allocator_dump_unittest.cc
+++ b/chromium/base/trace_event/memory_allocator_dump_unittest.cc
@@ -4,6 +4,8 @@
#include "base/trace_event/memory_allocator_dump.h"
+#include <stdint.h>
+
#include "base/format_macros.h"
#include "base/strings/stringprintf.h"
#include "base/trace_event/memory_allocator_dump_guid.h"
@@ -12,6 +14,7 @@
#include "base/trace_event/process_memory_dump.h"
#include "base/trace_event/trace_event_argument.h"
#include "base/values.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
@@ -82,7 +85,7 @@ void CheckString(const MemoryAllocatorDump* dump,
void CheckScalar(const MemoryAllocatorDump* dump,
const std::string& name,
const char* expected_units,
- uint64 expected_value) {
+ uint64_t expected_value) {
CheckString(dump, name, MemoryAllocatorDump::kTypeScalar, expected_units,
StringPrintf("%" PRIx64, expected_value));
}
@@ -125,7 +128,7 @@ TEST(MemoryAllocatorDumpTest, GuidGeneration) {
TEST(MemoryAllocatorDumpTest, DumpIntoProcessMemoryDump) {
FakeMemoryAllocatorDumpProvider fmadp;
- ProcessMemoryDump pmd(make_scoped_refptr(new MemoryDumpSessionState()));
+ ProcessMemoryDump pmd(new MemoryDumpSessionState(nullptr, nullptr));
MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::DETAILED};
fmadp.OnMemoryDump(dump_args, &pmd);
@@ -172,7 +175,7 @@ TEST(MemoryAllocatorDumpTest, DumpIntoProcessMemoryDump) {
#if !defined(NDEBUG) && !defined(OS_ANDROID) && !defined(OS_IOS)
TEST(MemoryAllocatorDumpTest, ForbidDuplicatesDeathTest) {
FakeMemoryAllocatorDumpProvider fmadp;
- ProcessMemoryDump pmd(make_scoped_refptr(new MemoryDumpSessionState()));
+ ProcessMemoryDump pmd(new MemoryDumpSessionState(nullptr, nullptr));
pmd.CreateAllocatorDump("foo_allocator");
pmd.CreateAllocatorDump("bar_allocator/heap");
ASSERT_DEATH(pmd.CreateAllocatorDump("foo_allocator"), "");
diff --git a/chromium/base/trace_event/memory_dump_manager.cc b/chromium/base/trace_event/memory_dump_manager.cc
index a2fa9539636..aa81e00a5da 100644
--- a/chromium/base/trace_event/memory_dump_manager.cc
+++ b/chromium/base/trace_event/memory_dump_manager.cc
@@ -5,11 +5,18 @@
#include "base/trace_event/memory_dump_manager.h"
#include <algorithm>
+#include <utility>
#include "base/atomic_sequence_num.h"
+#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/thread_task_runner_handle.h"
+#include "base/threading/thread.h"
+#include "base/trace_event/heap_profiler_allocation_context_tracker.h"
+#include "base/trace_event/heap_profiler_stack_frame_deduplicator.h"
+#include "base/trace_event/heap_profiler_type_name_deduplicator.h"
+#include "base/trace_event/malloc_dump_provider.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"
@@ -21,7 +28,6 @@
#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
@@ -43,8 +49,8 @@ const char* kTraceEventArgNames[] = {"dumps"};
const unsigned char kTraceEventArgTypes[] = {TRACE_VALUE_TYPE_CONVERTABLE};
StaticAtomicSequenceNumber g_next_guid;
-uint32 g_periodic_dumps_count = 0;
-uint32 g_heavy_dumps_rate = 0;
+uint32_t g_periodic_dumps_count = 0;
+uint32_t g_heavy_dumps_rate = 0;
MemoryDumpManager* g_instance_for_testing = nullptr;
void RequestPeriodicGlobalDump() {
@@ -64,6 +70,21 @@ void RequestPeriodicGlobalDump() {
MemoryDumpType::PERIODIC_INTERVAL, level_of_detail);
}
+// Callback wrapper to hook upon the completion of RequestGlobalDump() and
+// inject trace markers.
+void OnGlobalDumpDone(MemoryDumpCallback wrapped_callback,
+ uint64_t dump_guid,
+ bool success) {
+ TRACE_EVENT_NESTABLE_ASYNC_END1(
+ MemoryDumpManager::kTraceCategory, "GlobalMemoryDump",
+ TRACE_ID_MANGLE(dump_guid), "success", success);
+
+ if (!wrapped_callback.is_null()) {
+ wrapped_callback.Run(dump_guid, success);
+ wrapped_callback.Reset();
+ }
+}
+
} // namespace
// static
@@ -74,11 +95,11 @@ const char* const MemoryDumpManager::kTraceCategory =
const int MemoryDumpManager::kMaxConsecutiveFailuresCount = 3;
// static
-const uint64 MemoryDumpManager::kInvalidTracingProcessId = 0;
+const uint64_t MemoryDumpManager::kInvalidTracingProcessId = 0;
// static
const char* const MemoryDumpManager::kSystemAllocatorPoolName =
-#if defined(OS_LINUX) || defined(OS_ANDROID)
+#if defined(MALLOC_MEMORY_TRACING_SUPPORTED)
MallocDumpProvider::kAllocatedObjects;
#elif defined(OS_WIN)
WinHeapDumpProvider::kAllocatedObjects;
@@ -86,7 +107,6 @@ const char* const MemoryDumpManager::kSystemAllocatorPoolName =
nullptr;
#endif
-
// static
MemoryDumpManager* MemoryDumpManager::GetInstance() {
if (g_instance_for_testing)
@@ -98,8 +118,6 @@ MemoryDumpManager* MemoryDumpManager::GetInstance() {
// static
void MemoryDumpManager::SetInstanceForTesting(MemoryDumpManager* instance) {
- if (instance)
- instance->skip_core_dumpers_auto_registration_for_testing_ = true;
g_instance_for_testing = instance;
}
@@ -108,8 +126,16 @@ MemoryDumpManager::MemoryDumpManager()
is_coordinator_(false),
memory_tracing_enabled_(0),
tracing_process_id_(kInvalidTracingProcessId),
- skip_core_dumpers_auto_registration_for_testing_(false) {
+ dumper_registrations_ignored_for_testing_(false) {
g_next_guid.GetNext(); // Make sure that first guid is not zero.
+
+ heap_profiling_enabled_ = CommandLine::InitializedForCurrentProcess()
+ ? CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableHeapProfiling)
+ : false;
+
+ if (heap_profiling_enabled_)
+ AllocationContextTracker::SetCaptureEnabled(true);
}
MemoryDumpManager::~MemoryDumpManager() {
@@ -126,25 +152,29 @@ void MemoryDumpManager::Initialize(MemoryDumpManagerDelegate* delegate,
is_coordinator_ = is_coordinator;
}
- // Enable the core dump providers.
- if (!skip_core_dumpers_auto_registration_for_testing_) {
+// Enable the core dump providers.
#if !defined(OS_NACL)
- RegisterDumpProvider(ProcessMemoryTotalsDumpProvider::GetInstance());
+ RegisterDumpProvider(ProcessMemoryTotalsDumpProvider::GetInstance(),
+ "ProcessMemoryTotals", nullptr);
+#endif
+
+#if defined(MALLOC_MEMORY_TRACING_SUPPORTED)
+ RegisterDumpProvider(MallocDumpProvider::GetInstance(), "Malloc", nullptr);
#endif
#if defined(OS_LINUX) || defined(OS_ANDROID)
- RegisterDumpProvider(ProcessMemoryMapsDumpProvider::GetInstance());
- RegisterDumpProvider(MallocDumpProvider::GetInstance());
+ RegisterDumpProvider(ProcessMemoryMapsDumpProvider::GetInstance(),
+ "ProcessMemoryMaps", nullptr);
#endif
#if defined(OS_ANDROID)
- RegisterDumpProvider(JavaHeapDumpProvider::GetInstance());
+ RegisterDumpProvider(JavaHeapDumpProvider::GetInstance(), "JavaHeap",
+ nullptr);
#endif
#if defined(OS_WIN)
- RegisterDumpProvider(WinHeapDumpProvider::GetInstance());
+ RegisterDumpProvider(WinHeapDumpProvider::GetInstance(), "WinHeap", nullptr);
#endif
- } // !skip_core_dumpers_auto_registration_for_testing_
// If tracing was enabled before initializing MemoryDumpManager, we missed the
// OnTraceLogEnabled() event. Synthetize it so we can late-join the party.
@@ -157,50 +187,91 @@ void MemoryDumpManager::Initialize(MemoryDumpManagerDelegate* delegate,
void MemoryDumpManager::RegisterDumpProvider(
MemoryDumpProvider* mdp,
- const scoped_refptr<SingleThreadTaskRunner>& task_runner) {
- MemoryDumpProviderInfo mdp_info(mdp, task_runner);
- AutoLock lock(lock_);
- auto iter_new = dump_providers_.insert(mdp_info);
-
- // If there was a previous entry, replace it with the new one. This is to deal
- // with the case where a dump provider unregisters itself and then re-
- // registers before a memory dump happens, so its entry was still in the
- // collection but flagged |unregistered|.
- if (!iter_new.second) {
- dump_providers_.erase(iter_new.first);
- dump_providers_.insert(mdp_info);
+ const char* name,
+ const scoped_refptr<SingleThreadTaskRunner>& task_runner,
+ const MemoryDumpProvider::Options& options) {
+ if (dumper_registrations_ignored_for_testing_)
+ return;
+
+ scoped_refptr<MemoryDumpProviderInfo> mdpinfo =
+ new MemoryDumpProviderInfo(mdp, name, task_runner, options);
+
+ {
+ AutoLock lock(lock_);
+ bool already_registered = !dump_providers_.insert(mdpinfo).second;
+ // This actually happens in some tests which don't have a clean tear-down
+ // path for RenderThreadImpl::Init().
+ if (already_registered)
+ return;
}
+
+ if (heap_profiling_enabled_)
+ mdp->OnHeapProfilingEnabled(true);
}
-void MemoryDumpManager::RegisterDumpProvider(MemoryDumpProvider* mdp) {
- RegisterDumpProvider(mdp, nullptr);
+void MemoryDumpManager::RegisterDumpProvider(
+ MemoryDumpProvider* mdp,
+ const char* name,
+ const scoped_refptr<SingleThreadTaskRunner>& task_runner) {
+ RegisterDumpProvider(mdp, name, task_runner, MemoryDumpProvider::Options());
}
void MemoryDumpManager::UnregisterDumpProvider(MemoryDumpProvider* mdp) {
+ UnregisterDumpProviderInternal(mdp, false /* delete_async */);
+}
+
+void MemoryDumpManager::UnregisterAndDeleteDumpProviderSoon(
+ scoped_ptr<MemoryDumpProvider> mdp) {
+ UnregisterDumpProviderInternal(mdp.release(), true /* delete_async */);
+}
+
+void MemoryDumpManager::UnregisterDumpProviderInternal(
+ MemoryDumpProvider* mdp,
+ bool take_mdp_ownership_and_delete_async) {
+ scoped_ptr<MemoryDumpProvider> owned_mdp;
+ if (take_mdp_ownership_and_delete_async)
+ owned_mdp.reset(mdp);
+
AutoLock lock(lock_);
auto mdp_iter = dump_providers_.begin();
for (; mdp_iter != dump_providers_.end(); ++mdp_iter) {
- if (mdp_iter->dump_provider == mdp)
+ if ((*mdp_iter)->dump_provider == mdp)
break;
}
if (mdp_iter == dump_providers_.end())
- return;
+ return; // Not registered / already unregistered.
+
+ if (take_mdp_ownership_and_delete_async) {
+ // The MDP will be deleted whenever the MDPInfo struct will, that is either:
+ // - At the end of this function, if no dump is in progress.
+ // - In the prologue of the ContinueAsyncProcessDump().
+ DCHECK(!(*mdp_iter)->owned_dump_provider);
+ (*mdp_iter)->owned_dump_provider = std::move(owned_mdp);
+ } else if (subtle::NoBarrier_Load(&memory_tracing_enabled_)) {
+ // If you hit this DCHECK, your dump provider has a bug.
+ // Unregistration of a MemoryDumpProvider 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 be in the middle of a OnMemoryDump() at the same time.
+ // - The MDP has NOT specified a thread affinity and its ownership is
+ // transferred via UnregisterAndDeleteDumpProviderSoon().
+ // In all the other cases, it is not possible to guarantee that the
+ // unregistration will not race with OnMemoryDump() calls.
+ DCHECK((*mdp_iter)->task_runner &&
+ (*mdp_iter)->task_runner->BelongsToCurrentThread())
+ << "MemoryDumpProvider \"" << (*mdp_iter)->name << "\" attempted to "
+ << "unregister itself in a racy way. Please file a crbug.";
+ }
- // 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_iter->task_runner && mdp_iter->task_runner->BelongsToCurrentThread())
- << "The MemoryDumpProvider attempted to unregister itself in a racy way. "
- << "Please file a crbug.";
-
- mdp_iter->unregistered = true;
+ // The MDPInfo instance can still be referenced by the
+ // |ProcessMemoryDumpAsyncState.pending_dump_providers|. For this reason
+ // the MDPInfo is flagged as disabled. It will cause ContinueAsyncProcessDump
+ // to just skip it, without actually invoking the |mdp|, which might be
+ // destroyed by the caller soon after this method returns.
+ (*mdp_iter)->disabled = true;
+ dump_providers_.erase(mdp_iter);
}
void MemoryDumpManager::RequestGlobalDump(
@@ -214,9 +285,16 @@ void MemoryDumpManager::RequestGlobalDump(
return;
}
- const uint64 guid =
+ const uint64_t guid =
TraceLog::GetInstance()->MangleEventId(g_next_guid.GetNext());
+ // Creates an async event to keep track of the global dump evolution.
+ // The |wrapped_callback| will generate the ASYNC_END event and then invoke
+ // the real |callback| provided by the caller.
+ TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(kTraceCategory, "GlobalMemoryDump",
+ TRACE_ID_MANGLE(guid));
+ MemoryDumpCallback wrapped_callback = Bind(&OnGlobalDumpDone, callback);
+
// Technically there is no need to grab the |lock_| here as the delegate is
// long-lived and can only be set by Initialize(), which is locked and
// necessarily happens before memory_tracing_enabled_ == true.
@@ -231,7 +309,7 @@ void MemoryDumpManager::RequestGlobalDump(
// The delegate will coordinate the IPC broadcast and at some point invoke
// CreateProcessDump() to get a dump for the current process.
MemoryDumpRequestArgs args = {guid, dump_type, level_of_detail};
- delegate->RequestGlobalMemoryDump(args, callback);
+ delegate->RequestGlobalMemoryDump(args, wrapped_callback);
}
void MemoryDumpManager::RequestGlobalDump(
@@ -242,17 +320,25 @@ void MemoryDumpManager::RequestGlobalDump(
void MemoryDumpManager::CreateProcessDump(const MemoryDumpRequestArgs& args,
const MemoryDumpCallback& callback) {
+ TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(kTraceCategory, "ProcessMemoryDump",
+ TRACE_ID_MANGLE(args.dump_guid));
+
scoped_ptr<ProcessMemoryDumpAsyncState> pmd_async_state;
{
AutoLock lock(lock_);
- pmd_async_state.reset(new ProcessMemoryDumpAsyncState(
- args, dump_providers_.begin(), session_state_, callback));
+ pmd_async_state.reset(
+ new ProcessMemoryDumpAsyncState(args, dump_providers_, session_state_,
+ callback, dump_thread_->task_runner()));
}
+ TRACE_EVENT_WITH_FLOW0(kTraceCategory, "MemoryDumpManager::CreateProcessDump",
+ TRACE_ID_MANGLE(args.dump_guid),
+ TRACE_EVENT_FLAG_FLOW_OUT);
+
// Start the thread hop. |dump_providers_| are kept sorted by thread, so
// ContinueAsyncProcessDump will hop at most once per thread (w.r.t. thread
// affinity specified by the MemoryDumpProvider(s) in RegisterDumpProvider()).
- ContinueAsyncProcessDump(pmd_async_state.Pass());
+ ContinueAsyncProcessDump(pmd_async_state.release());
}
// At most one ContinueAsyncProcessDump() can be active at any time for a given
@@ -262,146 +348,159 @@ void MemoryDumpManager::CreateProcessDump(const MemoryDumpRequestArgs& args,
// means of subsequent PostTask(s).
//
// 1) Prologue:
-// - Check if the dump provider is disabled, if so skip the dump.
+// - If this was the last hop, create a trace event, add it to the trace
+// and finalize (invoke callback).
// - Check if we are on the right thread. If not hop and continue there.
+// - Check if the dump provider is disabled, if so skip the dump.
// 2) Invoke the dump provider's OnMemoryDump() (unless skipped).
// 3) Epilogue:
-// - Unregister the dump provider if it failed too many times consecutively.
-// - Advance the |next_dump_provider| iterator to the next dump provider.
-// - If this was the last hop, create a trace event, add it to the trace
-// and finalize (invoke callback).
-
+// - Unregister the dump provider if it failed too many times consecutively.
+// - Pop() the MDP from the |pending_dump_providers| list, eventually
+// destroying the MDPInfo if that was unregistered in the meantime.
void MemoryDumpManager::ContinueAsyncProcessDump(
- scoped_ptr<ProcessMemoryDumpAsyncState> pmd_async_state) {
+ ProcessMemoryDumpAsyncState* owned_pmd_async_state) {
// Initalizes the ThreadLocalEventBuffer to guarantee that the TRACE_EVENTs
// in the PostTask below don't end up registering their own dump providers
// (for discounting trace memory overhead) while holding the |lock_|.
TraceLog::GetInstance()->InitializeThreadLocalEventBufferIfSupported();
- // DO NOT put any LOG() statement in the locked sections, as in some contexts
- // (GPU process) LOG() ends up performing PostTask/IPCs.
- MemoryDumpProvider* mdp;
- bool skip_dump = false;
- {
- AutoLock lock(lock_);
-
- auto mdp_info = pmd_async_state->next_dump_provider;
- mdp = mdp_info->dump_provider;
- if (mdp_info->disabled || mdp_info->unregistered) {
- skip_dump = true;
- } else if (mdp_info->task_runner &&
- !mdp_info->task_runner->BelongsToCurrentThread()) {
- // It's time to hop onto another thread.
-
- // Copy the callback + arguments just for the unlikley case in which
- // PostTask fails. In such case the Bind helper will destroy the
- // pmd_async_state and we must keep a copy of the fields to notify the
- // abort.
- MemoryDumpCallback callback = pmd_async_state->callback;
- scoped_refptr<SingleThreadTaskRunner> callback_task_runner =
- pmd_async_state->task_runner;
- const uint64 dump_guid = pmd_async_state->req_args.dump_guid;
-
- const bool did_post_task = mdp_info->task_runner->PostTask(
- FROM_HERE, Bind(&MemoryDumpManager::ContinueAsyncProcessDump,
- Unretained(this), Passed(pmd_async_state.Pass())));
- if (did_post_task)
- return;
-
- // The thread is gone. At this point the best thing we can do is to
- // disable the dump provider and abort this dump.
- mdp_info->disabled = true;
- return AbortDumpLocked(callback, callback_task_runner, dump_guid);
+ // In theory |owned_pmd_async_state| should be a scoped_ptr. The only reason
+ // why it isn't is because of the corner case logic of |did_post_task| below,
+ // which needs to take back the ownership of the |pmd_async_state| when a
+ // thread goes away and consequently the PostTask() fails.
+ // Unfortunately, PostTask() destroys the scoped_ptr arguments upon failure
+ // to prevent accidental leaks. Using a scoped_ptr would prevent us to to
+ // skip the hop and move on. Hence the manual naked -> scoped ptr juggling.
+ auto pmd_async_state = make_scoped_ptr(owned_pmd_async_state);
+ owned_pmd_async_state = nullptr;
+
+ if (pmd_async_state->pending_dump_providers.empty())
+ return FinalizeDumpAndAddToTrace(std::move(pmd_async_state));
+
+ // Read MemoryDumpProviderInfo thread safety considerations in
+ // memory_dump_manager.h when accessing |mdpinfo| fields.
+ MemoryDumpProviderInfo* mdpinfo =
+ pmd_async_state->pending_dump_providers.back().get();
+
+ // If the dump provider did not specify a thread affinity, dump on
+ // |dump_thread_|. Note that |dump_thread_| might have been Stop()-ed at this
+ // point (if tracing was disabled in the meanwhile). In such case the
+ // PostTask() below will fail, but |task_runner| should always be non-null.
+ SingleThreadTaskRunner* task_runner = mdpinfo->task_runner.get();
+ if (!task_runner)
+ task_runner = pmd_async_state->dump_thread_task_runner.get();
+
+ bool post_task_failed = false;
+ if (!task_runner->BelongsToCurrentThread()) {
+ // It's time to hop onto another thread.
+ post_task_failed = !task_runner->PostTask(
+ FROM_HERE, Bind(&MemoryDumpManager::ContinueAsyncProcessDump,
+ Unretained(this), Unretained(pmd_async_state.get())));
+ if (!post_task_failed) {
+ // Ownership is tranferred to the next ContinueAsyncProcessDump().
+ ignore_result(pmd_async_state.release());
+ return;
}
- } // AutoLock(lock_)
-
- // Invoke the dump provider without holding the |lock_|.
- bool finalize = false;
- bool dump_successful = false;
-
- if (!skip_dump) {
- MemoryDumpArgs args = {pmd_async_state->req_args.level_of_detail};
- dump_successful =
- mdp->OnMemoryDump(args, &pmd_async_state->process_memory_dump);
}
+ // At this point either:
+ // - The MDP has a task runner affinity and we are on the right thread.
+ // - The MDP has a task runner affinity but the underlying thread is gone,
+ // hence the above |post_task_failed| == true.
+ // - The MDP does NOT have a task runner affinity. A locked access is required
+ // to R/W |disabled| (for the UnregisterAndDeleteDumpProviderSoon() case).
+ bool should_dump;
+ const char* disabled_reason = nullptr;
{
AutoLock lock(lock_);
- auto mdp_info = pmd_async_state->next_dump_provider;
- if (dump_successful) {
- mdp_info->consecutive_failures = 0;
- } else if (!skip_dump) {
- ++mdp_info->consecutive_failures;
- if (mdp_info->consecutive_failures >= kMaxConsecutiveFailuresCount) {
- mdp_info->disabled = true;
+ if (!mdpinfo->disabled) {
+ if (mdpinfo->consecutive_failures >= kMaxConsecutiveFailuresCount) {
+ mdpinfo->disabled = true;
+ disabled_reason =
+ "Dump failure, possibly related with sandboxing (crbug.com/461788)."
+ " Try --no-sandbox.";
+ } else if (post_task_failed) {
+ disabled_reason = "The thread it was meant to dump onto is gone.";
+ mdpinfo->disabled = true;
}
}
- ++pmd_async_state->next_dump_provider;
- finalize = pmd_async_state->next_dump_provider == dump_providers_.end();
-
- if (mdp_info->unregistered)
- dump_providers_.erase(mdp_info);
+ should_dump = !mdpinfo->disabled;
}
- if (!skip_dump && !dump_successful) {
- LOG(ERROR) << "A memory dumper failed, possibly due to sandboxing "
- "(crbug.com/461788). Disabling dumper for current process. "
- "Try restarting chrome with the --no-sandbox switch.";
+ if (disabled_reason) {
+ LOG(ERROR) << "Disabling MemoryDumpProvider \"" << mdpinfo->name << "\". "
+ << disabled_reason;
}
- if (finalize)
- return FinalizeDumpAndAddToTrace(pmd_async_state.Pass());
+ if (should_dump) {
+ // Invoke the dump provider.
+ TRACE_EVENT_WITH_FLOW1(kTraceCategory,
+ "MemoryDumpManager::ContinueAsyncProcessDump",
+ TRACE_ID_MANGLE(pmd_async_state->req_args.dump_guid),
+ TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
+ "dump_provider.name", mdpinfo->name);
+
+ // Pid of the target process being dumped. Often kNullProcessId (= current
+ // process), non-zero when the coordinator process creates dumps on behalf
+ // of child processes (see crbug.com/461788).
+ ProcessId target_pid = mdpinfo->options.target_pid;
+ ProcessMemoryDump* pmd =
+ pmd_async_state->GetOrCreateMemoryDumpContainerForProcess(target_pid);
+ MemoryDumpArgs args = {pmd_async_state->req_args.level_of_detail};
+ bool dump_successful = mdpinfo->dump_provider->OnMemoryDump(args, pmd);
+ mdpinfo->consecutive_failures =
+ dump_successful ? 0 : mdpinfo->consecutive_failures + 1;
+ } // if (!mdpinfo->disabled)
- ContinueAsyncProcessDump(pmd_async_state.Pass());
+ pmd_async_state->pending_dump_providers.pop_back();
+ ContinueAsyncProcessDump(pmd_async_state.release());
}
// static
void MemoryDumpManager::FinalizeDumpAndAddToTrace(
scoped_ptr<ProcessMemoryDumpAsyncState> pmd_async_state) {
- if (!pmd_async_state->task_runner->BelongsToCurrentThread()) {
- scoped_refptr<SingleThreadTaskRunner> task_runner =
- pmd_async_state->task_runner;
- task_runner->PostTask(FROM_HERE,
- Bind(&MemoryDumpManager::FinalizeDumpAndAddToTrace,
- Passed(pmd_async_state.Pass())));
+ DCHECK(pmd_async_state->pending_dump_providers.empty());
+ const uint64_t dump_guid = pmd_async_state->req_args.dump_guid;
+ if (!pmd_async_state->callback_task_runner->BelongsToCurrentThread()) {
+ scoped_refptr<SingleThreadTaskRunner> callback_task_runner =
+ pmd_async_state->callback_task_runner;
+ callback_task_runner->PostTask(
+ FROM_HERE, Bind(&MemoryDumpManager::FinalizeDumpAndAddToTrace,
+ Passed(&pmd_async_state)));
return;
}
- TracedValue* traced_value = new TracedValue();
- scoped_refptr<ConvertableToTraceFormat> event_value(traced_value);
- pmd_async_state->process_memory_dump.AsValueInto(traced_value);
- traced_value->SetString("level_of_detail",
- MemoryDumpLevelOfDetailToString(
- pmd_async_state->req_args.level_of_detail));
- const char* const event_name =
- MemoryDumpTypeToString(pmd_async_state->req_args.dump_type);
-
- TRACE_EVENT_API_ADD_TRACE_EVENT(
- TRACE_EVENT_PHASE_MEMORY_DUMP,
- TraceLog::GetCategoryGroupEnabled(kTraceCategory), event_name,
- pmd_async_state->req_args.dump_guid, kTraceEventNumArgs,
- kTraceEventArgNames, kTraceEventArgTypes, nullptr /* arg_values */,
- &event_value, TRACE_EVENT_FLAG_HAS_ID);
+ TRACE_EVENT_WITH_FLOW0(kTraceCategory,
+ "MemoryDumpManager::FinalizeDumpAndAddToTrace",
+ TRACE_ID_MANGLE(dump_guid), TRACE_EVENT_FLAG_FLOW_IN);
+
+ for (const auto& kv : pmd_async_state->process_dumps) {
+ ProcessId pid = kv.first; // kNullProcessId for the current process.
+ ProcessMemoryDump* process_memory_dump = kv.second.get();
+ TracedValue* traced_value = new TracedValue();
+ scoped_refptr<ConvertableToTraceFormat> event_value(traced_value);
+ process_memory_dump->AsValueInto(traced_value);
+ traced_value->SetString("level_of_detail",
+ MemoryDumpLevelOfDetailToString(
+ pmd_async_state->req_args.level_of_detail));
+ const char* const event_name =
+ MemoryDumpTypeToString(pmd_async_state->req_args.dump_type);
+
+ TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_PROCESS_ID(
+ TRACE_EVENT_PHASE_MEMORY_DUMP,
+ TraceLog::GetCategoryGroupEnabled(kTraceCategory), event_name,
+ dump_guid, pid, kTraceEventNumArgs, kTraceEventArgNames,
+ kTraceEventArgTypes, nullptr /* arg_values */, &event_value,
+ TRACE_EVENT_FLAG_HAS_ID);
+ }
if (!pmd_async_state->callback.is_null()) {
- pmd_async_state->callback.Run(pmd_async_state->req_args.dump_guid,
- true /* success */);
+ pmd_async_state->callback.Run(dump_guid, true /* success */);
pmd_async_state->callback.Reset();
}
-}
-// static
-void MemoryDumpManager::AbortDumpLocked(
- MemoryDumpCallback callback,
- scoped_refptr<SingleThreadTaskRunner> task_runner,
- uint64 dump_guid) {
- if (callback.is_null())
- return; // There is nothing to NACK.
-
- // Post the callback even if we are already on the right thread to avoid
- // invoking the callback while holding the lock_.
- task_runner->PostTask(FROM_HERE,
- Bind(callback, dump_guid, false /* success */));
+ TRACE_EVENT_NESTABLE_ASYNC_END0(kTraceCategory, "ProcessMemoryDump",
+ TRACE_ID_MANGLE(dump_guid));
}
void MemoryDumpManager::OnTraceLogEnabled() {
@@ -415,16 +514,39 @@ void MemoryDumpManager::OnTraceLogEnabled() {
// while the |lock_| is taken;
TraceLog::GetInstance()->InitializeThreadLocalEventBufferIfSupported();
+ // Spin-up the thread used to invoke unbound dump providers.
+ scoped_ptr<Thread> dump_thread(new Thread("MemoryInfra"));
+ if (!dump_thread->Start()) {
+ LOG(ERROR) << "Failed to start the memory-infra thread for tracing";
+ return;
+ }
+
AutoLock lock(lock_);
DCHECK(delegate_); // At this point we must have a delegate.
- session_state_ = new MemoryDumpSessionState();
- for (auto it = dump_providers_.begin(); it != dump_providers_.end(); ++it) {
- it->disabled = false;
- it->consecutive_failures = 0;
+ scoped_refptr<StackFrameDeduplicator> stack_frame_deduplicator = nullptr;
+ scoped_refptr<TypeNameDeduplicator> type_name_deduplicator = nullptr;
+
+ if (heap_profiling_enabled_) {
+ // If heap profiling is enabled, the stack frame deduplicator and type name
+ // deduplicator will be in use. Add a metadata events to write the frames
+ // and type IDs.
+ stack_frame_deduplicator = new StackFrameDeduplicator;
+ type_name_deduplicator = new TypeNameDeduplicator;
+ TRACE_EVENT_API_ADD_METADATA_EVENT(
+ "stackFrames", "stackFrames",
+ scoped_refptr<ConvertableToTraceFormat>(stack_frame_deduplicator));
+ TRACE_EVENT_API_ADD_METADATA_EVENT(
+ "typeNames", "typeNames",
+ scoped_refptr<ConvertableToTraceFormat>(type_name_deduplicator));
}
+ DCHECK(!dump_thread_);
+ dump_thread_ = std::move(dump_thread);
+ session_state_ = new MemoryDumpSessionState(stack_frame_deduplicator,
+ type_name_deduplicator);
+
subtle::NoBarrier_Store(&memory_tracing_enabled_, 1);
// TODO(primiano): This is a temporary hack to disable periodic memory dumps
@@ -448,8 +570,8 @@ void MemoryDumpManager::OnTraceLogEnabled() {
if (config_list.empty())
return;
- uint32 min_timer_period_ms = std::numeric_limits<uint32>::max();
- uint32 heavy_dump_period_ms = 0;
+ uint32_t min_timer_period_ms = std::numeric_limits<uint32_t>::max();
+ uint32_t heavy_dump_period_ms = 0;
DCHECK_LE(config_list.size(), 2u);
for (const TraceConfig::MemoryDumpTriggerConfig& config : config_list) {
DCHECK(config.periodic_interval_ms);
@@ -467,49 +589,78 @@ void MemoryDumpManager::OnTraceLogEnabled() {
}
void MemoryDumpManager::OnTraceLogDisabled() {
- AutoLock lock(lock_);
- periodic_dump_timer_.Stop();
subtle::NoBarrier_Store(&memory_tracing_enabled_, 0);
- session_state_ = nullptr;
+ scoped_ptr<Thread> dump_thread;
+ {
+ AutoLock lock(lock_);
+ dump_thread = std::move(dump_thread_);
+ session_state_ = nullptr;
+ }
+
+ // Thread stops are blocking and must be performed outside of the |lock_|
+ // or will deadlock (e.g., if ContinueAsyncProcessDump() tries to acquire it).
+ periodic_dump_timer_.Stop();
+ if (dump_thread)
+ dump_thread->Stop();
}
-uint64 MemoryDumpManager::GetTracingProcessId() const {
+uint64_t MemoryDumpManager::GetTracingProcessId() const {
return delegate_->GetTracingProcessId();
}
MemoryDumpManager::MemoryDumpProviderInfo::MemoryDumpProviderInfo(
MemoryDumpProvider* dump_provider,
- const scoped_refptr<SingleThreadTaskRunner>& task_runner)
+ const char* name,
+ const scoped_refptr<SingleThreadTaskRunner>& task_runner,
+ const MemoryDumpProvider::Options& options)
: dump_provider(dump_provider),
+ name(name),
task_runner(task_runner),
+ options(options),
consecutive_failures(0),
- disabled(false),
- unregistered(false) {}
-
-MemoryDumpManager::MemoryDumpProviderInfo::~MemoryDumpProviderInfo() {
-}
-
-bool MemoryDumpManager::MemoryDumpProviderInfo::operator<(
- const MemoryDumpProviderInfo& other) const {
- if (task_runner == other.task_runner)
- return dump_provider < other.dump_provider;
- return task_runner < other.task_runner;
+ disabled(false) {}
+
+MemoryDumpManager::MemoryDumpProviderInfo::~MemoryDumpProviderInfo() {}
+
+bool MemoryDumpManager::MemoryDumpProviderInfo::Comparator::operator()(
+ const scoped_refptr<MemoryDumpManager::MemoryDumpProviderInfo>& a,
+ const scoped_refptr<MemoryDumpManager::MemoryDumpProviderInfo>& b) const {
+ if (!a || !b)
+ return a.get() < b.get();
+ // Ensure that unbound providers (task_runner == nullptr) always run last.
+ // Rationale: some unbound dump providers are known to be slow, keep them last
+ // to avoid skewing timings of the other dump providers.
+ return std::tie(a->task_runner, a->dump_provider) >
+ std::tie(b->task_runner, b->dump_provider);
}
MemoryDumpManager::ProcessMemoryDumpAsyncState::ProcessMemoryDumpAsyncState(
MemoryDumpRequestArgs req_args,
- MemoryDumpProviderInfoSet::iterator next_dump_provider,
+ const MemoryDumpProviderInfo::OrderedSet& dump_providers,
const scoped_refptr<MemoryDumpSessionState>& session_state,
- MemoryDumpCallback callback)
- : process_memory_dump(session_state),
- req_args(req_args),
- next_dump_provider(next_dump_provider),
+ MemoryDumpCallback callback,
+ const scoped_refptr<SingleThreadTaskRunner>& dump_thread_task_runner)
+ : req_args(req_args),
+ session_state(session_state),
callback(callback),
- task_runner(MessageLoop::current()->task_runner()) {
+ callback_task_runner(MessageLoop::current()->task_runner()),
+ dump_thread_task_runner(dump_thread_task_runner) {
+ pending_dump_providers.reserve(dump_providers.size());
+ pending_dump_providers.assign(dump_providers.rbegin(), dump_providers.rend());
}
MemoryDumpManager::ProcessMemoryDumpAsyncState::~ProcessMemoryDumpAsyncState() {
}
+ProcessMemoryDump* MemoryDumpManager::ProcessMemoryDumpAsyncState::
+ GetOrCreateMemoryDumpContainerForProcess(ProcessId pid) {
+ auto iter = process_dumps.find(pid);
+ if (iter == process_dumps.end()) {
+ scoped_ptr<ProcessMemoryDump> new_pmd(new ProcessMemoryDump(session_state));
+ iter = process_dumps.insert(std::make_pair(pid, std::move(new_pmd))).first;
+ }
+ return iter->second.get();
+}
+
} // 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
index 0f352ed7797..b3880afdf47 100644
--- a/chromium/base/trace_event/memory_dump_manager.h
+++ b/chromium/base/trace_event/memory_dump_manager.h
@@ -5,10 +5,16 @@
#ifndef BASE_TRACE_EVENT_MEMORY_DUMP_MANAGER_H_
#define BASE_TRACE_EVENT_MEMORY_DUMP_MANAGER_H_
+#include <stdint.h>
+
+#include <map>
+#include <memory>
#include <set>
+#include <vector>
#include "base/atomicops.h"
#include "base/containers/hash_tables.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/singleton.h"
#include "base/synchronization/lock.h"
@@ -20,6 +26,7 @@
namespace base {
class SingleThreadTaskRunner;
+class Thread;
namespace trace_event {
@@ -36,7 +43,7 @@ class BASE_EXPORT MemoryDumpManager : public TraceLog::EnabledStateObserver {
// This value is returned as the tracing id of the child processes by
// GetTracingProcessId() when tracing is not enabled.
- static const uint64 kInvalidTracingProcessId;
+ static const uint64_t kInvalidTracingProcessId;
static MemoryDumpManager* GetInstance();
@@ -54,17 +61,38 @@ class BASE_EXPORT MemoryDumpManager : public TraceLog::EnabledStateObserver {
// requirements in the |MemoryDumpManagerDelegate| docstring.
void Initialize(MemoryDumpManagerDelegate* delegate, bool is_coordinator);
- // 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.
+ // (Un)Registers a MemoryDumpProvider instance.
+ // Args:
+ // - mdp: the MemoryDumpProvider instance to be registered. MemoryDumpManager
+ // does NOT take memory ownership of |mdp|, which is expected to either
+ // be a singleton or unregister itself.
+ // - name: a friendly name (duplicates allowed). Used for debugging and
+ // run-time profiling of memory-infra internals. Must be a long-lived
+ // C string.
+ // - task_runner: if non-null, all the calls to |mdp| will be
+ // issued on the given thread. Otherwise, |mdp| should be able to
+ // handle calls on arbitrary threads.
+ // - options: extra optional arguments. See memory_dump_provider.h.
void RegisterDumpProvider(
MemoryDumpProvider* mdp,
+ const char* name,
const scoped_refptr<SingleThreadTaskRunner>& task_runner);
- void RegisterDumpProvider(MemoryDumpProvider* mdp);
+ void RegisterDumpProvider(
+ MemoryDumpProvider* mdp,
+ const char* name,
+ const scoped_refptr<SingleThreadTaskRunner>& task_runner,
+ const MemoryDumpProvider::Options& options);
void UnregisterDumpProvider(MemoryDumpProvider* mdp);
+ // Unregisters an unbound dump provider and takes care about its deletion
+ // asynchronously. Can be used only for for dump providers with no
+ // task-runner affinity.
+ // This method takes ownership of the dump provider and guarantees that:
+ // - The |mdp| will be deleted at some point in the near future.
+ // - Its deletion will not happen concurrently with the OnMemoryDump() call.
+ // Note that OnMemoryDump() calls can still happen after this method returns.
+ void UnregisterAndDeleteDumpProviderSoon(scoped_ptr<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,
@@ -94,7 +122,7 @@ class BASE_EXPORT MemoryDumpManager : public TraceLog::EnabledStateObserver {
// retrieved by child processes only when tracing is enabled. This is
// intended to express cross-process sharing of memory dumps on the
// child-process side, without having to know its own child process id.
- uint64 GetTracingProcessId() const;
+ uint64_t GetTracingProcessId() const;
// Returns the name for a the allocated_objects dump. Use this to declare
// suballocator dumps from other dump providers.
@@ -104,39 +132,76 @@ class BASE_EXPORT MemoryDumpManager : public TraceLog::EnabledStateObserver {
return kSystemAllocatorPoolName;
};
+ // When set to true, calling |RegisterMemoryDumpProvider| is a no-op.
+ void set_dumper_registrations_ignored_for_testing(bool ignored) {
+ dumper_registrations_ignored_for_testing_ = ignored;
+ }
+
private:
- friend struct DefaultDeleter<MemoryDumpManager>; // For the testing instance.
+ friend std::default_delete<MemoryDumpManager>; // For the testing instance.
friend struct DefaultSingletonTraits<MemoryDumpManager>;
friend class MemoryDumpManagerDelegate;
friend class MemoryDumpManagerTest;
- // Descriptor struct used to hold information about registered MDPs. It is
- // deliberately copyable, in order to allow it to be used as std::set value.
- struct MemoryDumpProviderInfo {
- MemoryDumpProviderInfo(
- MemoryDumpProvider* dump_provider,
- const scoped_refptr<SingleThreadTaskRunner>& task_runner);
- ~MemoryDumpProviderInfo();
-
+ // Descriptor used to hold information about registered MDPs.
+ // Some important considerations about lifetime of this object:
+ // - In nominal conditions, all the MemoryDumpProviderInfo instances live in
+ // the |dump_providers_| collection (% unregistration while dumping).
+ // - Upon each dump they (actually their scoped_refptr-s) are copied into
+ // the ProcessMemoryDumpAsyncState. This is to allow removal (see below).
+ // - When the MDP.OnMemoryDump() is invoked, the corresponding MDPInfo copy
+ // inside ProcessMemoryDumpAsyncState is removed.
+ // - In most cases, the MDPInfo is destroyed within UnregisterDumpProvider().
+ // - If UnregisterDumpProvider() is called while a dump is in progress, the
+ // MDPInfo is destroyed in the epilogue of ContinueAsyncProcessDump(), when
+ // the copy inside ProcessMemoryDumpAsyncState is erase()-d.
+ // - The non-const fields of MemoryDumpProviderInfo are safe to access only
+ // in the |task_runner| thread, unless the thread has been destroyed.
+ struct MemoryDumpProviderInfo
+ : public RefCountedThreadSafe<MemoryDumpProviderInfo> {
// Define a total order based on the thread (i.e. |task_runner|) affinity,
// so that all MDP belonging to the same thread are adjacent in the set.
- bool operator<(const MemoryDumpProviderInfo& other) const;
+ struct Comparator {
+ bool operator()(const scoped_refptr<MemoryDumpProviderInfo>& a,
+ const scoped_refptr<MemoryDumpProviderInfo>& b) const;
+ };
+ using OrderedSet =
+ std::set<scoped_refptr<MemoryDumpProviderInfo>, Comparator>;
+
+ MemoryDumpProviderInfo(
+ MemoryDumpProvider* dump_provider,
+ const char* name,
+ const scoped_refptr<SingleThreadTaskRunner>& task_runner,
+ const MemoryDumpProvider::Options& options);
MemoryDumpProvider* const dump_provider;
- scoped_refptr<SingleThreadTaskRunner> task_runner; // Optional.
- // For fail-safe logic (auto-disable failing MDPs). These fields are mutable
- // as can be safely changed without impacting the order within the set.
- mutable int consecutive_failures;
- mutable bool disabled;
+ // Used to transfer ownership for UnregisterAndDeleteDumpProviderSoon().
+ // nullptr in all other cases.
+ scoped_ptr<MemoryDumpProvider> owned_dump_provider;
- // When a dump provider unregisters, it is flagged as |unregistered| and it
- // is removed only upon the next memory dump. This is to avoid altering the
- // |dump_providers_| collection while a dump is in progress.
- mutable bool unregistered;
- };
+ // Human readable name, for debugging and testing. Not necessarily unique.
+ const char* const name;
+
+ // The task_runner affinity. Can be nullptr, in which case the dump provider
+ // will be invoked on |dump_thread_|.
+ const scoped_refptr<SingleThreadTaskRunner> task_runner;
- using MemoryDumpProviderInfoSet = std::set<MemoryDumpProviderInfo>;
+ // The |options| arg passed to RegisterDumpProvider().
+ const MemoryDumpProvider::Options options;
+
+ // For fail-safe logic (auto-disable failing MDPs).
+ int consecutive_failures;
+
+ // Flagged either by the auto-disable logic or during unregistration.
+ bool disabled;
+
+ private:
+ friend class base::RefCountedThreadSafe<MemoryDumpProviderInfo>;
+ ~MemoryDumpProviderInfo();
+
+ DISALLOW_COPY_AND_ASSIGN(MemoryDumpProviderInfo);
+ };
// Holds the state of a process memory dump that needs to be carried over
// across threads in order to fulfil an asynchronous CreateProcessDump()
@@ -144,21 +209,31 @@ class BASE_EXPORT MemoryDumpManager : public TraceLog::EnabledStateObserver {
struct ProcessMemoryDumpAsyncState {
ProcessMemoryDumpAsyncState(
MemoryDumpRequestArgs req_args,
- MemoryDumpProviderInfoSet::iterator next_dump_provider,
+ const MemoryDumpProviderInfo::OrderedSet& dump_providers,
const scoped_refptr<MemoryDumpSessionState>& session_state,
- MemoryDumpCallback callback);
+ MemoryDumpCallback callback,
+ const scoped_refptr<SingleThreadTaskRunner>& dump_thread_task_runner);
~ProcessMemoryDumpAsyncState();
- // The ProcessMemoryDump container, where each dump provider will dump its
- // own MemoryAllocatorDump(s) upon the OnMemoryDump() call.
- ProcessMemoryDump process_memory_dump;
+ // Gets or creates the memory dump container for the given target process.
+ ProcessMemoryDump* GetOrCreateMemoryDumpContainerForProcess(ProcessId pid);
+
+ // A map of ProcessId -> ProcessMemoryDump, one for each target process
+ // being dumped from the current process. Typically each process dumps only
+ // for itself, unless dump providers specify a different |target_process| in
+ // MemoryDumpProvider::Options.
+ std::map<ProcessId, scoped_ptr<ProcessMemoryDump>> process_dumps;
// The arguments passed to the initial CreateProcessDump() request.
const MemoryDumpRequestArgs req_args;
- // The |dump_providers_| iterator to the next dump provider that should be
- // invoked (or dump_providers_.end() if at the end of the sequence).
- MemoryDumpProviderInfoSet::iterator next_dump_provider;
+ // An ordered sequence of dump providers that have to be invoked to complete
+ // the dump. This is a copy of |dump_providers_| at the beginning of a dump
+ // and becomes empty at the end, when all dump providers have been invoked.
+ std::vector<scoped_refptr<MemoryDumpProviderInfo>> pending_dump_providers;
+
+ // The trace-global session state.
+ scoped_refptr<MemoryDumpSessionState> session_state;
// Callback passed to the initial call to CreateProcessDump().
MemoryDumpCallback callback;
@@ -166,7 +241,14 @@ class BASE_EXPORT MemoryDumpManager : public TraceLog::EnabledStateObserver {
// The thread on which FinalizeDumpAndAddToTrace() (and hence |callback|)
// should be invoked. This is the thread on which the initial
// CreateProcessDump() request was called.
- const scoped_refptr<SingleThreadTaskRunner> task_runner;
+ const scoped_refptr<SingleThreadTaskRunner> callback_task_runner;
+
+ // The thread on which unbound dump providers should be invoked.
+ // This is essentially |dump_thread_|.task_runner() but needs to be kept
+ // as a separate variable as it needs to be accessed by arbitrary dumpers'
+ // threads outside of the lock_ to avoid races when disabling tracing.
+ // It is immutable for all the duration of a tracing session.
+ const scoped_refptr<SingleThreadTaskRunner> dump_thread_task_runner;
private:
DISALLOW_COPY_AND_ASSIGN(ProcessMemoryDumpAsyncState);
@@ -181,9 +263,6 @@ class BASE_EXPORT MemoryDumpManager : public TraceLog::EnabledStateObserver {
static void SetInstanceForTesting(MemoryDumpManager* instance);
static void FinalizeDumpAndAddToTrace(
scoped_ptr<ProcessMemoryDumpAsyncState> pmd_async_state);
- static void AbortDumpLocked(MemoryDumpCallback callback,
- scoped_refptr<SingleThreadTaskRunner> task_runner,
- uint64 dump_guid);
// Internal, used only by MemoryDumpManagerDelegate.
// Creates a memory dump for the current process and appends it to the trace.
@@ -195,11 +274,15 @@ class BASE_EXPORT MemoryDumpManager : public TraceLog::EnabledStateObserver {
// Continues the ProcessMemoryDump started by CreateProcessDump(), hopping
// across threads as needed as specified by MDPs in RegisterDumpProvider().
void ContinueAsyncProcessDump(
- scoped_ptr<ProcessMemoryDumpAsyncState> pmd_async_state);
+ ProcessMemoryDumpAsyncState* owned_pmd_async_state);
+
+ // Helper for the public UnregisterDumpProvider* functions.
+ void UnregisterDumpProviderInternal(MemoryDumpProvider* mdp,
+ bool take_mdp_ownership_and_delete_async);
// An ordererd set of registered MemoryDumpProviderInfo(s), sorted by thread
// affinity (MDPs belonging to the same thread are adjacent).
- MemoryDumpProviderInfoSet dump_providers_;
+ MemoryDumpProviderInfo::OrderedSet dump_providers_;
// Shared among all the PMDs to keep state scoped to the tracing session.
scoped_refptr<MemoryDumpSessionState> session_state_;
@@ -220,12 +303,18 @@ class BASE_EXPORT MemoryDumpManager : public TraceLog::EnabledStateObserver {
// For time-triggered periodic dumps.
RepeatingTimer periodic_dump_timer_;
+ // Thread used for MemoryDumpProviders which don't specify a thread affinity.
+ scoped_ptr<Thread> dump_thread_;
+
// The unique id of the child process. This is created only for tracing and is
// expected to be valid only when tracing is enabled.
- uint64 tracing_process_id_;
+ uint64_t tracing_process_id_;
+
+ // When true, calling |RegisterMemoryDumpProvider| is a no-op.
+ bool dumper_registrations_ignored_for_testing_;
- // Skips the auto-registration of the core dumpers during Initialize().
- bool skip_core_dumpers_auto_registration_for_testing_;
+ // Whether new memory dump providers should be told to enable heap profiling.
+ bool heap_profiling_enabled_;
DISALLOW_COPY_AND_ASSIGN(MemoryDumpManager);
};
@@ -239,7 +328,7 @@ class BASE_EXPORT MemoryDumpManagerDelegate {
// Returns tracing process id of the current process. This is used by
// MemoryDumpManager::GetTracingProcessId.
- virtual uint64 GetTracingProcessId() const = 0;
+ virtual uint64_t GetTracingProcessId() const = 0;
protected:
MemoryDumpManagerDelegate() {}
diff --git a/chromium/base/trace_event/memory_dump_manager_unittest.cc b/chromium/base/trace_event/memory_dump_manager_unittest.cc
index af3287ddfde..03b3afa32e5 100644
--- a/chromium/base/trace_event/memory_dump_manager_unittest.cc
+++ b/chromium/base/trace_event/memory_dump_manager_unittest.cc
@@ -4,16 +4,24 @@
#include "base/trace_event/memory_dump_manager.h"
+#include <stdint.h>
+
+#include <vector>
+
#include "base/bind_helpers.h"
-#include "base/memory/scoped_vector.h"
+#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
+#include "base/synchronization/waitable_event.h"
#include "base/test/test_io_thread.h"
+#include "base/test/trace_event_analyzer.h"
#include "base/thread_task_runner_handle.h"
+#include "base/threading/platform_thread.h"
#include "base/threading/thread.h"
#include "base/trace_event/memory_dump_provider.h"
#include "base/trace_event/process_memory_dump.h"
+#include "base/trace_event/trace_buffer.h"
#include "base/trace_event/trace_config_memory_test_util.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -37,6 +45,33 @@ MATCHER(IsLightDump, "") {
return arg.level_of_detail == MemoryDumpLevelOfDetail::LIGHT;
}
+namespace {
+
+void RegisterDumpProvider(
+ MemoryDumpProvider* mdp,
+ const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
+ const MemoryDumpProvider::Options& options) {
+ MemoryDumpManager* mdm = MemoryDumpManager::GetInstance();
+ mdm->set_dumper_registrations_ignored_for_testing(false);
+ mdm->RegisterDumpProvider(mdp, "TestDumpProvider", task_runner, options);
+ mdm->set_dumper_registrations_ignored_for_testing(true);
+}
+
+void RegisterDumpProvider(MemoryDumpProvider* mdp) {
+ RegisterDumpProvider(mdp, nullptr, MemoryDumpProvider::Options());
+}
+
+void OnTraceDataCollected(Closure quit_closure,
+ trace_event::TraceResultBuffer* buffer,
+ const scoped_refptr<RefCountedString>& json,
+ bool has_more_events) {
+ buffer->AddFragment(json->data());
+ if (!has_more_events)
+ quit_closure.Run();
+}
+
+} // namespace
+
// Testing MemoryDumpManagerDelegate which, by default, short-circuits dump
// requests locally to the MemoryDumpManager instead of performing IPC dances.
class MemoryDumpManagerDelegateForTesting : public MemoryDumpManagerDelegate {
@@ -51,7 +86,7 @@ class MemoryDumpManagerDelegateForTesting : public MemoryDumpManagerDelegate {
void(const MemoryDumpRequestArgs& args,
const MemoryDumpCallback& callback));
- uint64 GetTracingProcessId() const override {
+ uint64_t GetTracingProcessId() const override {
NOTREACHED();
return MemoryDumpManager::kInvalidTracingProcessId;
}
@@ -59,18 +94,29 @@ class MemoryDumpManagerDelegateForTesting : public MemoryDumpManagerDelegate {
class MockMemoryDumpProvider : public MemoryDumpProvider {
public:
+ MOCK_METHOD0(Destructor, void());
MOCK_METHOD2(OnMemoryDump,
bool(const MemoryDumpArgs& args, ProcessMemoryDump* pmd));
+
+ MockMemoryDumpProvider() : enable_mock_destructor(false) {}
+ ~MockMemoryDumpProvider() override {
+ if (enable_mock_destructor)
+ Destructor();
+ }
+
+ bool enable_mock_destructor;
};
class MemoryDumpManagerTest : public testing::Test {
public:
+ MemoryDumpManagerTest() : testing::Test(), kDefaultOptions() {}
+
void SetUp() override {
last_callback_success_ = false;
message_loop_.reset(new MessageLoop());
mdm_.reset(new MemoryDumpManager());
MemoryDumpManager::SetInstanceForTesting(mdm_.get());
- ASSERT_EQ(mdm_, MemoryDumpManager::GetInstance());
+ ASSERT_EQ(mdm_.get(), MemoryDumpManager::GetInstance());
delegate_.reset(new MemoryDumpManagerDelegateForTesting);
}
@@ -82,9 +128,11 @@ class MemoryDumpManagerTest : public testing::Test {
TraceLog::DeleteForTesting();
}
+ // Turns a Closure into a MemoryDumpCallback, keeping track of the callback
+ // result and taking care of posting the closure on the correct task runner.
void DumpCallbackAdapter(scoped_refptr<SingleThreadTaskRunner> task_runner,
Closure closure,
- uint64 dump_guid,
+ uint64_t dump_guid,
bool success) {
last_callback_success_ = success;
task_runner->PostTask(FROM_HERE, closure);
@@ -92,9 +140,20 @@ class MemoryDumpManagerTest : public testing::Test {
protected:
void InitializeMemoryDumpManager(bool is_coordinator) {
+ mdm_->set_dumper_registrations_ignored_for_testing(true);
mdm_->Initialize(delegate_.get(), is_coordinator);
}
+ void RequestGlobalDumpAndWait(MemoryDumpType dump_type,
+ MemoryDumpLevelOfDetail level_of_detail) {
+ RunLoop run_loop;
+ MemoryDumpCallback callback =
+ Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this),
+ MessageLoop::current()->task_runner(), run_loop.QuitClosure());
+ mdm_->RequestGlobalDump(dump_type, level_of_detail, callback);
+ run_loop.Run();
+ }
+
void EnableTracingWithLegacyCategories(const char* category) {
TraceLog::GetInstance()->SetEnabled(TraceConfig(category, ""),
TraceLog::RECORDING_MODE);
@@ -115,6 +174,7 @@ class MemoryDumpManagerTest : public testing::Test {
return MemoryDumpManager::kMaxConsecutiveFailuresCount;
}
+ const MemoryDumpProvider::Options kDefaultOptions;
scoped_ptr<MemoryDumpManager> mdm_;
scoped_ptr<MemoryDumpManagerDelegateForTesting> delegate_;
bool last_callback_success_;
@@ -131,14 +191,14 @@ class MemoryDumpManagerTest : public testing::Test {
TEST_F(MemoryDumpManagerTest, SingleDumper) {
InitializeMemoryDumpManager(false /* is_coordinator */);
MockMemoryDumpProvider mdp;
- mdm_->RegisterDumpProvider(&mdp);
+ RegisterDumpProvider(&mdp);
// Check that the dumper is not called if the memory category is not enabled.
EnableTracingWithLegacyCategories("foobar-but-not-memory");
EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(0);
EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
- mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED);
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
DisableTracing();
// Now repeat enabling the memory category and check that the dumper is
@@ -147,8 +207,8 @@ TEST_F(MemoryDumpManagerTest, SingleDumper) {
EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(3);
EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(3).WillRepeatedly(Return(true));
for (int i = 0; i < 3; ++i)
- mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED);
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
DisableTracing();
mdm_->UnregisterDumpProvider(&mdp);
@@ -156,11 +216,14 @@ TEST_F(MemoryDumpManagerTest, SingleDumper) {
// Finally check the unregister logic: the delegate will be invoked but not
// the dump provider, as it has been unregistered.
EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
- EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+ EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(3);
EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
- mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED);
- TraceLog::GetInstance()->SetDisabled();
+
+ for (int i = 0; i < 3; ++i) {
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
+ }
+ DisableTracing();
}
// Checks that requesting dumps with high level of detail actually propagates
@@ -169,23 +232,23 @@ TEST_F(MemoryDumpManagerTest, CheckMemoryDumpArgs) {
InitializeMemoryDumpManager(false /* is_coordinator */);
MockMemoryDumpProvider mdp;
- mdm_->RegisterDumpProvider(&mdp);
+ RegisterDumpProvider(&mdp);
EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
EXPECT_CALL(mdp, OnMemoryDump(IsDetailedDump(), _)).WillOnce(Return(true));
- mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED);
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
DisableTracing();
mdm_->UnregisterDumpProvider(&mdp);
// Check that requesting dumps with low level of detail actually propagates to
// OnMemoryDump() call on dump providers.
- mdm_->RegisterDumpProvider(&mdp);
+ RegisterDumpProvider(&mdp);
EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
EXPECT_CALL(mdp, OnMemoryDump(IsLightDump(), _)).WillOnce(Return(true));
- mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::LIGHT);
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::LIGHT);
DisableTracing();
mdm_->UnregisterDumpProvider(&mdp);
}
@@ -195,8 +258,8 @@ TEST_F(MemoryDumpManagerTest, SharedSessionState) {
InitializeMemoryDumpManager(false /* is_coordinator */);
MockMemoryDumpProvider mdp1;
MockMemoryDumpProvider mdp2;
- mdm_->RegisterDumpProvider(&mdp1);
- mdm_->RegisterDumpProvider(&mdp2);
+ RegisterDumpProvider(&mdp1);
+ RegisterDumpProvider(&mdp2);
EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
const MemoryDumpSessionState* session_state = mdm_->session_state().get();
@@ -216,9 +279,10 @@ TEST_F(MemoryDumpManagerTest, SharedSessionState) {
return true;
}));
- for (int i = 0; i < 2; ++i)
- mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED);
+ for (int i = 0; i < 2; ++i) {
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
+ }
DisableTracing();
}
@@ -230,34 +294,34 @@ TEST_F(MemoryDumpManagerTest, MultipleDumpers) {
MockMemoryDumpProvider mdp2;
// Enable only mdp1.
- mdm_->RegisterDumpProvider(&mdp1);
+ RegisterDumpProvider(&mdp1);
EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
EXPECT_CALL(mdp1, OnMemoryDump(_, _)).WillOnce(Return(true));
EXPECT_CALL(mdp2, OnMemoryDump(_, _)).Times(0);
- mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED);
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
DisableTracing();
// Invert: enable mdp1 and disable mdp2.
mdm_->UnregisterDumpProvider(&mdp1);
- mdm_->RegisterDumpProvider(&mdp2);
+ RegisterDumpProvider(&mdp2);
EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(0);
EXPECT_CALL(mdp2, OnMemoryDump(_, _)).WillOnce(Return(true));
- mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED);
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
DisableTracing();
// Enable both mdp1 and mdp2.
- mdm_->RegisterDumpProvider(&mdp1);
+ RegisterDumpProvider(&mdp1);
EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
EXPECT_CALL(mdp1, OnMemoryDump(_, _)).WillOnce(Return(true));
EXPECT_CALL(mdp2, OnMemoryDump(_, _)).WillOnce(Return(true));
- mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED);
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
DisableTracing();
}
@@ -267,14 +331,14 @@ TEST_F(MemoryDumpManagerTest, RegistrationConsistency) {
InitializeMemoryDumpManager(false /* is_coordinator */);
MockMemoryDumpProvider mdp;
- mdm_->RegisterDumpProvider(&mdp);
+ RegisterDumpProvider(&mdp);
{
EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
EXPECT_CALL(mdp, OnMemoryDump(_, _)).WillOnce(Return(true));
EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
- mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED);
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
DisableTracing();
}
@@ -284,33 +348,33 @@ TEST_F(MemoryDumpManagerTest, RegistrationConsistency) {
EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
- mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED);
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
DisableTracing();
}
- mdm_->RegisterDumpProvider(&mdp);
+ RegisterDumpProvider(&mdp);
mdm_->UnregisterDumpProvider(&mdp);
{
EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
- mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED);
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
DisableTracing();
}
- mdm_->RegisterDumpProvider(&mdp);
+ RegisterDumpProvider(&mdp);
mdm_->UnregisterDumpProvider(&mdp);
- mdm_->RegisterDumpProvider(&mdp);
+ RegisterDumpProvider(&mdp);
{
EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
EXPECT_CALL(mdp, OnMemoryDump(_, _)).WillOnce(Return(true));
EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
- mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED);
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
DisableTracing();
}
}
@@ -321,22 +385,22 @@ TEST_F(MemoryDumpManagerTest, RegistrationConsistency) {
// iteration, one thread is removed, to check the live unregistration logic.
TEST_F(MemoryDumpManagerTest, RespectTaskRunnerAffinity) {
InitializeMemoryDumpManager(false /* is_coordinator */);
- const uint32 kNumInitialThreads = 8;
+ const uint32_t kNumInitialThreads = 8;
- ScopedVector<Thread> threads;
- ScopedVector<MockMemoryDumpProvider> mdps;
+ std::vector<scoped_ptr<Thread>> threads;
+ std::vector<scoped_ptr<MockMemoryDumpProvider>> 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) {
- Thread* thread = new Thread("test thread");
- threads.push_back(thread);
- threads.back()->Start();
+ for (uint32_t i = kNumInitialThreads; i > 0; --i) {
+ threads.push_back(make_scoped_ptr(new Thread("test thread")));
+ auto thread = threads.back().get();
+ thread->Start();
scoped_refptr<SingleThreadTaskRunner> task_runner = thread->task_runner();
- MockMemoryDumpProvider* mdp = new MockMemoryDumpProvider();
- mdps.push_back(mdp);
- mdm_->RegisterDumpProvider(mdp, task_runner);
+ mdps.push_back(make_scoped_ptr(new MockMemoryDumpProvider()));
+ auto mdp = mdps.back().get();
+ RegisterDumpProvider(mdp, task_runner, kDefaultOptions);
EXPECT_CALL(*mdp, OnMemoryDump(_, _))
.Times(i)
.WillRepeatedly(Invoke(
@@ -345,23 +409,13 @@ TEST_F(MemoryDumpManagerTest, RespectTaskRunnerAffinity) {
return true;
}));
}
-
EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
while (!threads.empty()) {
last_callback_success_ = false;
- {
- RunLoop run_loop;
- MemoryDumpCallback callback =
- Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this),
- MessageLoop::current()->task_runner(), run_loop.QuitClosure());
- EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
- mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED, callback);
- // This nested message loop (|run_loop|) will quit if and only if the
- // |callback| passed to RequestGlobalDump() is invoked.
- run_loop.Run();
- }
+ EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
EXPECT_TRUE(last_callback_success_);
// Unregister a MDP and destroy one thread at each iteration to check the
@@ -371,7 +425,7 @@ TEST_F(MemoryDumpManagerTest, RespectTaskRunnerAffinity) {
RunLoop run_loop;
Closure unregistration =
Bind(&MemoryDumpManager::UnregisterDumpProvider,
- Unretained(mdm_.get()), Unretained(mdps.back()));
+ Unretained(mdm_.get()), Unretained(mdps.back().get()));
threads.back()->task_runner()->PostTaskAndReply(FROM_HERE, unregistration,
run_loop.QuitClosure());
run_loop.Run();
@@ -391,8 +445,8 @@ TEST_F(MemoryDumpManagerTest, DisableFailingDumpers) {
MockMemoryDumpProvider mdp1;
MockMemoryDumpProvider mdp2;
- mdm_->RegisterDumpProvider(&mdp1);
- mdm_->RegisterDumpProvider(&mdp2);
+ RegisterDumpProvider(&mdp1);
+ RegisterDumpProvider(&mdp2);
EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
const int kNumDumps = 2 * GetMaxConsecutiveFailuresCount();
@@ -411,8 +465,8 @@ TEST_F(MemoryDumpManagerTest, DisableFailingDumpers) {
.WillOnce(Return(false));
for (int i = 0; i < kNumDumps; i++) {
- mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED);
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
}
DisableTracing();
@@ -425,7 +479,7 @@ TEST_F(MemoryDumpManagerTest, RegisterDumperWhileDumping) {
MockMemoryDumpProvider mdp1;
MockMemoryDumpProvider mdp2;
- mdm_->RegisterDumpProvider(&mdp1);
+ RegisterDumpProvider(&mdp1);
EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(4);
@@ -435,7 +489,7 @@ TEST_F(MemoryDumpManagerTest, RegisterDumperWhileDumping) {
.WillOnce(Return(true))
.WillOnce(
Invoke([&mdp2](const MemoryDumpArgs&, ProcessMemoryDump*) -> bool {
- MemoryDumpManager::GetInstance()->RegisterDumpProvider(&mdp2);
+ RegisterDumpProvider(&mdp2);
return true;
}))
.WillRepeatedly(Return(true));
@@ -447,8 +501,8 @@ TEST_F(MemoryDumpManagerTest, RegisterDumperWhileDumping) {
.WillRepeatedly(Return(true));
for (int i = 0; i < 4; i++) {
- mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED);
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
}
DisableTracing();
@@ -460,8 +514,8 @@ TEST_F(MemoryDumpManagerTest, UnregisterDumperWhileDumping) {
MockMemoryDumpProvider mdp1;
MockMemoryDumpProvider mdp2;
- mdm_->RegisterDumpProvider(&mdp1, ThreadTaskRunnerHandle::Get());
- mdm_->RegisterDumpProvider(&mdp2, ThreadTaskRunnerHandle::Get());
+ RegisterDumpProvider(&mdp1, ThreadTaskRunnerHandle::Get(), kDefaultOptions);
+ RegisterDumpProvider(&mdp2, ThreadTaskRunnerHandle::Get(), kDefaultOptions);
EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(4);
@@ -483,8 +537,8 @@ TEST_F(MemoryDumpManagerTest, UnregisterDumperWhileDumping) {
.WillRepeatedly(Return(true));
for (int i = 0; i < 4; i++) {
- mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED);
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
}
DisableTracing();
@@ -494,24 +548,25 @@ TEST_F(MemoryDumpManagerTest, UnregisterDumperWhileDumping) {
// dumping from a different thread than the dumping thread.
TEST_F(MemoryDumpManagerTest, UnregisterDumperFromThreadWhileDumping) {
InitializeMemoryDumpManager(false /* is_coordinator */);
- ScopedVector<TestIOThread> threads;
- ScopedVector<MockMemoryDumpProvider> mdps;
+ std::vector<scoped_ptr<TestIOThread>> threads;
+ std::vector<scoped_ptr<MockMemoryDumpProvider>> mdps;
for (int i = 0; i < 2; i++) {
- threads.push_back(new TestIOThread(TestIOThread::kAutoStart));
- mdps.push_back(new MockMemoryDumpProvider());
- mdm_->RegisterDumpProvider(mdps.back(), threads.back()->task_runner());
+ threads.push_back(
+ make_scoped_ptr(new TestIOThread(TestIOThread::kAutoStart)));
+ mdps.push_back(make_scoped_ptr(new MockMemoryDumpProvider()));
+ RegisterDumpProvider(mdps.back().get(), threads.back()->task_runner(),
+ kDefaultOptions);
}
int on_memory_dump_call_count = 0;
- RunLoop run_loop;
// When OnMemoryDump is called on either of the dump providers, it will
// unregister the other one.
- for (MockMemoryDumpProvider* mdp : mdps) {
+ for (const scoped_ptr<MockMemoryDumpProvider>& mdp : mdps) {
int other_idx = (mdps.front() == mdp);
- TestIOThread* other_thread = threads[other_idx];
- MockMemoryDumpProvider* other_mdp = mdps[other_idx];
+ TestIOThread* other_thread = threads[other_idx].get();
+ MockMemoryDumpProvider* other_mdp = mdps[other_idx].get();
auto on_dump = [this, other_thread, other_mdp, &on_memory_dump_call_count](
const MemoryDumpArgs& args, ProcessMemoryDump* pmd) {
other_thread->PostTaskAndWait(
@@ -529,20 +584,59 @@ TEST_F(MemoryDumpManagerTest, UnregisterDumperFromThreadWhileDumping) {
}
last_callback_success_ = false;
- MemoryDumpCallback callback =
- Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this),
- MessageLoop::current()->task_runner(), run_loop.QuitClosure());
-
EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
-
EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
- mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED, callback);
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
+ ASSERT_EQ(1, on_memory_dump_call_count);
+ ASSERT_TRUE(last_callback_success_);
- run_loop.Run();
+ DisableTracing();
+}
+
+// If a thread (with a dump provider living on it) is torn down during a dump
+// its dump provider should be skipped but the dump itself should succeed.
+TEST_F(MemoryDumpManagerTest, TearDownThreadWhileDumping) {
+ InitializeMemoryDumpManager(false /* is_coordinator */);
+ std::vector<scoped_ptr<TestIOThread>> threads;
+ std::vector<scoped_ptr<MockMemoryDumpProvider>> mdps;
+
+ for (int i = 0; i < 2; i++) {
+ threads.push_back(
+ make_scoped_ptr(new TestIOThread(TestIOThread::kAutoStart)));
+ mdps.push_back(make_scoped_ptr(new MockMemoryDumpProvider()));
+ RegisterDumpProvider(mdps.back().get(), threads.back()->task_runner(),
+ kDefaultOptions);
+ }
+ int on_memory_dump_call_count = 0;
+
+ // When OnMemoryDump is called on either of the dump providers, it will
+ // tear down the thread of the other one.
+ for (const scoped_ptr<MockMemoryDumpProvider>& mdp : mdps) {
+ int other_idx = (mdps.front() == mdp);
+ TestIOThread* other_thread = threads[other_idx].get();
+ auto on_dump = [other_thread, &on_memory_dump_call_count](
+ const MemoryDumpArgs& args, ProcessMemoryDump* pmd) {
+ other_thread->Stop();
+ on_memory_dump_call_count++;
+ return true;
+ };
+
+ // OnMemoryDump is called once for the provider that dumps first, and zero
+ // times for the other provider.
+ EXPECT_CALL(*mdp, OnMemoryDump(_, _))
+ .Times(AtMost(1))
+ .WillOnce(Invoke(on_dump));
+ }
+
+ last_callback_success_ = false;
+ EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+ EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
ASSERT_EQ(1, on_memory_dump_call_count);
- ASSERT_EQ(true, last_callback_success_);
+ ASSERT_TRUE(last_callback_success_);
DisableTracing();
}
@@ -552,21 +646,14 @@ TEST_F(MemoryDumpManagerTest, UnregisterDumperFromThreadWhileDumping) {
TEST_F(MemoryDumpManagerTest, CallbackCalledOnFailure) {
InitializeMemoryDumpManager(false /* is_coordinator */);
MockMemoryDumpProvider mdp1;
- mdm_->RegisterDumpProvider(&mdp1);
+ RegisterDumpProvider(&mdp1);
EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(0);
EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(0);
last_callback_success_ = true;
- {
- RunLoop run_loop;
- MemoryDumpCallback callback =
- Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this),
- MessageLoop::current()->task_runner(), run_loop.QuitClosure());
- mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED, callback);
- run_loop.Run();
- }
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
EXPECT_FALSE(last_callback_success_);
}
@@ -574,7 +661,7 @@ TEST_F(MemoryDumpManagerTest, CallbackCalledOnFailure) {
// began, it will still late-join the party (real use case: startup tracing).
TEST_F(MemoryDumpManagerTest, InitializedAfterStartOfTracing) {
MockMemoryDumpProvider mdp;
- mdm_->RegisterDumpProvider(&mdp);
+ RegisterDumpProvider(&mdp);
EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
// First check that a RequestGlobalDump() issued before the MemoryDumpManager
@@ -582,13 +669,8 @@ TEST_F(MemoryDumpManagerTest, InitializedAfterStartOfTracing) {
{
EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(0);
EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(0);
- RunLoop run_loop;
- MemoryDumpCallback callback =
- Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this),
- MessageLoop::current()->task_runner(), run_loop.QuitClosure());
- mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED, callback);
- run_loop.Run();
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
EXPECT_FALSE(last_callback_success_);
}
@@ -598,13 +680,8 @@ TEST_F(MemoryDumpManagerTest, InitializedAfterStartOfTracing) {
EXPECT_CALL(mdp, OnMemoryDump(_, _)).Times(1);
EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
InitializeMemoryDumpManager(false /* is_coordinator */);
- RunLoop run_loop;
- MemoryDumpCallback callback =
- Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this),
- MessageLoop::current()->task_runner(), run_loop.QuitClosure());
- mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::DETAILED, callback);
- run_loop.Run();
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
EXPECT_TRUE(last_callback_success_);
}
DisableTracing();
@@ -702,5 +779,180 @@ TEST_F(MemoryDumpManagerTest, TraceConfigExpectationsWhenIsCoordinator) {
DisableTracing();
}
+// Tests against race conditions that might arise when disabling tracing in the
+// middle of a global memory dump.
+TEST_F(MemoryDumpManagerTest, DisableTracingWhileDumping) {
+ base::WaitableEvent tracing_disabled_event(false, false);
+ InitializeMemoryDumpManager(false /* is_coordinator */);
+
+ // Register a bound dump provider.
+ scoped_ptr<Thread> mdp_thread(new Thread("test thread"));
+ mdp_thread->Start();
+ MockMemoryDumpProvider mdp_with_affinity;
+ RegisterDumpProvider(&mdp_with_affinity, mdp_thread->task_runner(),
+ kDefaultOptions);
+
+ // Register also an unbound dump provider. Unbound dump providers are always
+ // invoked after bound ones.
+ MockMemoryDumpProvider unbound_mdp;
+ RegisterDumpProvider(&unbound_mdp, nullptr, kDefaultOptions);
+
+ EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+ EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+ EXPECT_CALL(mdp_with_affinity, OnMemoryDump(_, _))
+ .Times(1)
+ .WillOnce(
+ Invoke([&tracing_disabled_event](const MemoryDumpArgs&,
+ ProcessMemoryDump* pmd) -> bool {
+ tracing_disabled_event.Wait();
+
+ // At this point tracing has been disabled and the
+ // MemoryDumpManager.dump_thread_ has been shut down.
+ return true;
+ }));
+
+ // |unbound_mdp| should never be invoked because the thread for unbound dump
+ // providers has been shutdown in the meanwhile.
+ EXPECT_CALL(unbound_mdp, OnMemoryDump(_, _)).Times(0);
+
+ last_callback_success_ = true;
+ RunLoop run_loop;
+ MemoryDumpCallback callback =
+ Bind(&MemoryDumpManagerTest::DumpCallbackAdapter, Unretained(this),
+ MessageLoop::current()->task_runner(), run_loop.QuitClosure());
+ mdm_->RequestGlobalDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED, callback);
+ DisableTracing();
+ tracing_disabled_event.Signal();
+ run_loop.Run();
+
+ // RequestGlobalMemoryDump() should still suceed even if some threads were
+ // torn down during the dump.
+ EXPECT_TRUE(last_callback_success_);
+}
+
+TEST_F(MemoryDumpManagerTest, DumpOnBehalfOfOtherProcess) {
+ using trace_analyzer::Query;
+
+ InitializeMemoryDumpManager(false /* is_coordinator */);
+
+ // Standard provider with default options (create dump for current process).
+ MemoryDumpProvider::Options options;
+ MockMemoryDumpProvider mdp1;
+ RegisterDumpProvider(&mdp1, nullptr, options);
+
+ // Provider with out-of-process dumping.
+ MockMemoryDumpProvider mdp2;
+ options.target_pid = 123;
+ RegisterDumpProvider(&mdp2, nullptr, options);
+
+ // Another provider with out-of-process dumping.
+ MockMemoryDumpProvider mdp3;
+ options.target_pid = 456;
+ RegisterDumpProvider(&mdp3, nullptr, options);
+
+ EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+ EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(1);
+ EXPECT_CALL(mdp1, OnMemoryDump(_, _)).Times(1).WillRepeatedly(Return(true));
+ EXPECT_CALL(mdp2, OnMemoryDump(_, _)).Times(1).WillRepeatedly(Return(true));
+ EXPECT_CALL(mdp3, OnMemoryDump(_, _)).Times(1).WillRepeatedly(Return(true));
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
+ DisableTracing();
+
+ // Flush the trace into JSON.
+ trace_event::TraceResultBuffer buffer;
+ TraceResultBuffer::SimpleOutput trace_output;
+ buffer.SetOutputCallback(trace_output.GetCallback());
+ RunLoop run_loop;
+ buffer.Start();
+ trace_event::TraceLog::GetInstance()->Flush(
+ Bind(&OnTraceDataCollected, run_loop.QuitClosure(), Unretained(&buffer)));
+ run_loop.Run();
+ buffer.Finish();
+
+ // Analyze the JSON.
+ scoped_ptr<trace_analyzer::TraceAnalyzer> analyzer = make_scoped_ptr(
+ trace_analyzer::TraceAnalyzer::Create(trace_output.json_output));
+ trace_analyzer::TraceEventVector events;
+ analyzer->FindEvents(Query::EventPhaseIs(TRACE_EVENT_PHASE_MEMORY_DUMP),
+ &events);
+
+ ASSERT_EQ(3u, events.size());
+ ASSERT_EQ(1u, trace_analyzer::CountMatches(events, Query::EventPidIs(123)));
+ ASSERT_EQ(1u, trace_analyzer::CountMatches(events, Query::EventPidIs(456)));
+ ASSERT_EQ(1u, trace_analyzer::CountMatches(
+ events, Query::EventPidIs(GetCurrentProcId())));
+ ASSERT_EQ(events[0]->id, events[1]->id);
+ ASSERT_EQ(events[0]->id, events[2]->id);
+}
+
+// Tests the basics of the UnregisterAndDeleteDumpProviderSoon(): the
+// unregistration should actually delete the providers and not leak them.
+TEST_F(MemoryDumpManagerTest, UnregisterAndDeleteDumpProviderSoon) {
+ InitializeMemoryDumpManager(false /* is_coordinator */);
+ static const int kNumProviders = 3;
+ int dtor_count = 0;
+ std::vector<scoped_ptr<MemoryDumpProvider>> mdps;
+ for (int i = 0; i < kNumProviders; ++i) {
+ scoped_ptr<MockMemoryDumpProvider> mdp(new MockMemoryDumpProvider);
+ mdp->enable_mock_destructor = true;
+ EXPECT_CALL(*mdp, Destructor())
+ .WillOnce(Invoke([&dtor_count]() { dtor_count++; }));
+ RegisterDumpProvider(mdp.get(), nullptr, kDefaultOptions);
+ mdps.push_back(std::move(mdp));
+ }
+
+ while (!mdps.empty()) {
+ mdm_->UnregisterAndDeleteDumpProviderSoon(std::move(mdps.back()));
+ mdps.pop_back();
+ }
+
+ ASSERT_EQ(kNumProviders, dtor_count);
+}
+
+// This test checks against races when unregistering an unbound dump provider
+// from another thread while dumping. It registers one MDP and, when
+// OnMemoryDump() is called, it invokes UnregisterAndDeleteDumpProviderSoon()
+// from another thread. The OnMemoryDump() and the dtor call are expected to
+// happen on the same thread (the MemoryDumpManager utility thread).
+TEST_F(MemoryDumpManagerTest, UnregisterAndDeleteDumpProviderSoonDuringDump) {
+ InitializeMemoryDumpManager(false /* is_coordinator */);
+ scoped_ptr<MockMemoryDumpProvider> mdp(new MockMemoryDumpProvider);
+ mdp->enable_mock_destructor = true;
+ RegisterDumpProvider(mdp.get(), nullptr, kDefaultOptions);
+
+ base::PlatformThreadRef thread_ref;
+ auto self_unregister_from_another_thread = [&mdp, &thread_ref](
+ const MemoryDumpArgs&, ProcessMemoryDump*) -> bool {
+ thread_ref = PlatformThread::CurrentRef();
+ TestIOThread thread_for_unregistration(TestIOThread::kAutoStart);
+ thread_for_unregistration.PostTaskAndWait(
+ FROM_HERE,
+ base::Bind(
+ &MemoryDumpManager::UnregisterAndDeleteDumpProviderSoon,
+ base::Unretained(MemoryDumpManager::GetInstance()),
+ base::Passed(scoped_ptr<MemoryDumpProvider>(std::move(mdp)))));
+ thread_for_unregistration.Stop();
+ return true;
+ };
+ EXPECT_CALL(*mdp, OnMemoryDump(_, _))
+ .Times(1)
+ .WillOnce(Invoke(self_unregister_from_another_thread));
+ EXPECT_CALL(*mdp, Destructor())
+ .Times(1)
+ .WillOnce(Invoke([&thread_ref]() {
+ EXPECT_EQ(thread_ref, PlatformThread::CurrentRef());
+ }));
+
+ EnableTracingWithLegacyCategories(MemoryDumpManager::kTraceCategory);
+ EXPECT_CALL(*delegate_, RequestGlobalMemoryDump(_, _)).Times(2);
+ for (int i = 0; i < 2; ++i) {
+ RequestGlobalDumpAndWait(MemoryDumpType::EXPLICITLY_TRIGGERED,
+ MemoryDumpLevelOfDetail::DETAILED);
+ }
+ 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
index 3b1f13623a7..f03fcbdf7e8 100644
--- a/chromium/base/trace_event/memory_dump_provider.h
+++ b/chromium/base/trace_event/memory_dump_provider.h
@@ -7,6 +7,7 @@
#include "base/base_export.h"
#include "base/macros.h"
+#include "base/process/process_handle.h"
#include "base/trace_event/memory_dump_request_args.h"
namespace base {
@@ -23,6 +24,20 @@ struct MemoryDumpArgs {
// The contract interface that memory dump providers must implement.
class BASE_EXPORT MemoryDumpProvider {
public:
+ // Optional arguments for MemoryDumpManager::RegisterDumpProvider().
+ struct Options {
+ Options() : target_pid(kNullProcessId) {}
+ explicit Options(ProcessId target_pid) : target_pid(target_pid) {}
+
+ // If the dump provider generates dumps on behalf of another process,
+ // |target_process| contains the pid of that process.
+ // The default value is kNullProcessId, which means that the dump provider
+ // generates dumps for the current process.
+ ProcessId target_pid;
+ };
+
+ virtual ~MemoryDumpProvider() {}
+
// Called by the MemoryDumpManager when generating memory dumps.
// The |args| specify if the embedder should generate light/heavy dumps on
// dump requests. The embedder should return true if the |pmd| was
@@ -33,9 +48,12 @@ class BASE_EXPORT MemoryDumpProvider {
virtual bool OnMemoryDump(const MemoryDumpArgs& args,
ProcessMemoryDump* pmd) = 0;
+ // Called by the MemoryDumpManager when an allocator should start or stop
+ // collecting extensive allocation data, if supported.
+ virtual void OnHeapProfilingEnabled(bool enabled) {}
+
protected:
MemoryDumpProvider() {}
- virtual ~MemoryDumpProvider() {}
DISALLOW_COPY_AND_ASSIGN(MemoryDumpProvider);
};
diff --git a/chromium/base/trace_event/memory_dump_request_args.h b/chromium/base/trace_event/memory_dump_request_args.h
index d1bb6c3c51b..00d560ec6ac 100644
--- a/chromium/base/trace_event/memory_dump_request_args.h
+++ b/chromium/base/trace_event/memory_dump_request_args.h
@@ -8,6 +8,7 @@
// 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 <stdint.h>
#include <string>
#include "base/base_export.h"
@@ -42,13 +43,13 @@ 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;
+ uint64_t dump_guid;
MemoryDumpType dump_type;
MemoryDumpLevelOfDetail level_of_detail;
};
-using MemoryDumpCallback = Callback<void(uint64 dump_guid, bool success)>;
+using MemoryDumpCallback = Callback<void(uint64_t dump_guid, bool success)>;
BASE_EXPORT const char* MemoryDumpTypeToString(const MemoryDumpType& dump_type);
diff --git a/chromium/base/trace_event/memory_dump_session_state.cc b/chromium/base/trace_event/memory_dump_session_state.cc
index 433ac14cbfa..5aa79b1c789 100644
--- a/chromium/base/trace_event/memory_dump_session_state.cc
+++ b/chromium/base/trace_event/memory_dump_session_state.cc
@@ -7,8 +7,11 @@
namespace base {
namespace trace_event {
-MemoryDumpSessionState::MemoryDumpSessionState() {
-}
+MemoryDumpSessionState::MemoryDumpSessionState(
+ const scoped_refptr<StackFrameDeduplicator>& stack_frame_deduplicator,
+ const scoped_refptr<TypeNameDeduplicator>& type_name_deduplicator)
+ : stack_frame_deduplicator_(stack_frame_deduplicator),
+ type_name_deduplicator_(type_name_deduplicator) {}
MemoryDumpSessionState::~MemoryDumpSessionState() {
}
diff --git a/chromium/base/trace_event/memory_dump_session_state.h b/chromium/base/trace_event/memory_dump_session_state.h
index cf29b85559c..6834471b9a7 100644
--- a/chromium/base/trace_event/memory_dump_session_state.h
+++ b/chromium/base/trace_event/memory_dump_session_state.h
@@ -5,10 +5,10 @@
#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"
+#include "base/trace_event/heap_profiler_stack_frame_deduplicator.h"
+#include "base/trace_event/heap_profiler_type_name_deduplicator.h"
namespace base {
namespace trace_event {
@@ -18,11 +18,33 @@ namespace trace_event {
class BASE_EXPORT MemoryDumpSessionState
: public RefCountedThreadSafe<MemoryDumpSessionState> {
public:
- MemoryDumpSessionState();
+ MemoryDumpSessionState(
+ const scoped_refptr<StackFrameDeduplicator>& stack_frame_deduplicator,
+ const scoped_refptr<TypeNameDeduplicator>& type_name_deduplicator);
+
+ // Returns the stack frame deduplicator that should be used by memory dump
+ // providers when doing a heap dump.
+ StackFrameDeduplicator* stack_frame_deduplicator() {
+ return stack_frame_deduplicator_.get();
+ }
+
+ // Returns the type name deduplicator that should be used by memory dump
+ // providers when doing a heap dump.
+ TypeNameDeduplicator* type_name_deduplicator() {
+ return type_name_deduplicator_.get();
+ }
private:
friend class RefCountedThreadSafe<MemoryDumpSessionState>;
~MemoryDumpSessionState();
+
+ // Deduplicates backtraces in heap dumps so they can be written once when the
+ // trace is finalized.
+ scoped_refptr<StackFrameDeduplicator> stack_frame_deduplicator_;
+
+ // Deduplicates type names in heap dumps so they can be written once when the
+ // trace is finalized.
+ scoped_refptr<TypeNameDeduplicator> type_name_deduplicator_;
};
} // namespace trace_event
diff --git a/chromium/base/trace_event/memory_profiler_allocation_context.cc b/chromium/base/trace_event/memory_profiler_allocation_context.cc
deleted file mode 100644
index 3aea93518c6..00000000000
--- a/chromium/base/trace_event/memory_profiler_allocation_context.cc
+++ /dev/null
@@ -1,91 +0,0 @@
-// 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_profiler_allocation_context.h"
-
-#include "base/threading/thread_local_storage.h"
-
-namespace base {
-namespace trace_event {
-
-subtle::Atomic32 AllocationContextTracker::capture_enabled_ = 0;
-
-namespace {
-ThreadLocalStorage::StaticSlot g_tls_alloc_ctx_tracker = TLS_INITIALIZER;
-}
-
-AllocationStack::AllocationStack() {}
-AllocationStack::~AllocationStack() {}
-
-// This function is added to the TLS slot to clean up the instance when the
-// thread exits.
-void DestructAllocationContextTracker(void* alloc_ctx_tracker) {
- delete static_cast<AllocationContextTracker*>(alloc_ctx_tracker);
-}
-
-AllocationContextTracker* AllocationContextTracker::GetThreadLocalTracker() {
- AllocationContextTracker* tracker;
-
- if (g_tls_alloc_ctx_tracker.initialized()) {
- tracker =
- static_cast<AllocationContextTracker*>(g_tls_alloc_ctx_tracker.Get());
- } else {
- tracker = new AllocationContextTracker();
- g_tls_alloc_ctx_tracker.Initialize(DestructAllocationContextTracker);
- g_tls_alloc_ctx_tracker.Set(tracker);
- }
-
- return tracker;
-}
-
-AllocationContextTracker::AllocationContextTracker() {}
-AllocationContextTracker::~AllocationContextTracker() {}
-
-// static
-void AllocationContextTracker::SetCaptureEnabled(bool enabled) {
- // There is no memory barrier here for performance reasons, a little lag is
- // not an issue.
- subtle::NoBarrier_Store(&capture_enabled_, enabled);
-}
-
-// static
-void AllocationContextTracker::PushPseudoStackFrame(StackFrame frame) {
- auto tracker = AllocationContextTracker::GetThreadLocalTracker();
- tracker->pseudo_stack_.push(frame);
-}
-
-// static
-void AllocationContextTracker::PopPseudoStackFrame(StackFrame frame) {
- auto tracker = AllocationContextTracker::GetThreadLocalTracker();
- DCHECK_EQ(frame, *tracker->pseudo_stack_.top());
- tracker->pseudo_stack_.pop();
-}
-
-// static
-void AllocationContextTracker::SetContextField(const char* key,
- const char* value) {
- auto tracker = AllocationContextTracker::GetThreadLocalTracker();
- tracker->context_[key] = value;
-}
-
-// static
-void AllocationContextTracker::UnsetContextField(const char* key) {
- auto tracker = AllocationContextTracker::GetThreadLocalTracker();
- tracker->context_.erase(key);
-}
-
-// static
-AllocationStack* AllocationContextTracker::GetPseudoStackForTesting() {
- auto tracker = AllocationContextTracker::GetThreadLocalTracker();
- return &tracker->pseudo_stack_;
-}
-
-// static
-AllocationContext AllocationContextTracker::GetContext() {
- // TODO(ruuda): Implement this in a follow-up CL.
- return AllocationContext();
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/chromium/base/trace_event/memory_profiler_allocation_context.h b/chromium/base/trace_event/memory_profiler_allocation_context.h
deleted file mode 100644
index 11ecc881baf..00000000000
--- a/chromium/base/trace_event/memory_profiler_allocation_context.h
+++ /dev/null
@@ -1,119 +0,0 @@
-// 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_PROFILER_ALLOCATION_CONTEXT_H_
-#define BASE_TRACE_EVENT_MEMORY_PROFILER_ALLOCATION_CONTEXT_H_
-
-#include <vector>
-
-#include "base/atomicops.h"
-#include "base/base_export.h"
-#include "base/containers/small_map.h"
-
-namespace base {
-namespace trace_event {
-
-// When heap profiling is enabled, tracing keeps track of the allocation
-// context for each allocation intercepted. It is generated by the
-// |AllocationContextTracker| which keeps stacks of context in TLS.
-// The tracker is initialized lazily.
-
-using StackFrame = const char*;
-
-// A simple stack of |StackFrame| that unlike |std::stack| allows iterating
-// the stack and guards for underflow.
-class BASE_EXPORT AllocationStack {
- public:
- // Incrementing the iterator iterates down the stack.
- using ConstIterator = std::vector<StackFrame>::const_reverse_iterator;
-
- AllocationStack();
- ~AllocationStack();
-
- inline ConstIterator top() const { return stack_.rbegin(); }
- inline ConstIterator bottom() const { return stack_.rend(); }
-
- inline void push(StackFrame frame) {
- // Impose a limit on the height to verify that every push is popped, because
- // in practice the pseudo stack never grows higher than ~20 frames.
- DCHECK_LT(stack_.size(), 128u);
- stack_.push_back(frame);
- }
-
- inline void pop() {
- if (!stack_.empty())
- stack_.pop_back();
- }
-
- private:
- std::vector<StackFrame> stack_;
-
- DISALLOW_COPY_AND_ASSIGN(AllocationStack);
-};
-
-class BASE_EXPORT AllocationContext {
- // TODO(ruuda): Fill this in a follow-up CL.
-};
-
-// The allocation context tracker keeps track of thread-local context for heap
-// profiling. It includes a pseudo stack of trace events, and it might contain
-// arbitrary (key, value) context. On every allocation the tracker provides a
-// snapshot of its context in the form of an |AllocationContext| that is to be
-// stored together with the allocation details.
-class BASE_EXPORT AllocationContextTracker {
- public:
- // Globally enables capturing allocation context.
- // TODO(ruuda): Should this be replaced by |EnableCapturing| in the future?
- // Or at least have something that guards agains enable -> disable -> enable?
- static void SetCaptureEnabled(bool enabled);
-
- // Returns whether capturing allocation context is enabled globally.
- inline static bool capture_enabled() {
- // A little lag after heap profiling is enabled or disabled is fine, it is
- // more important that the check is as cheap as possible when capturing is
- // not enabled, so do not issue a memory barrier.
- return subtle::NoBarrier_Load(&capture_enabled_) != 0;
- }
-
- // Pushes a frame onto the thread-local pseudo stack.
- static void PushPseudoStackFrame(StackFrame frame);
-
- // Pops a frame from the thread-local pseudo stack.
- static void PopPseudoStackFrame(StackFrame frame);
-
- // Sets a thread-local (key, value) pair.
- static void SetContextField(const char* key, const char* value);
-
- // Removes the (key, value) pair with the specified key from the thread-local
- // context.
- static void UnsetContextField(const char* key);
-
- // Returns a snapshot of the current thread-local context.
- static AllocationContext GetContext();
-
- // TODO(ruuda): Remove in a follow-up CL, this is only used for testing now.
- static AllocationStack* GetPseudoStackForTesting();
-
- ~AllocationContextTracker();
-
- private:
- AllocationContextTracker();
-
- static AllocationContextTracker* GetThreadLocalTracker();
-
- static subtle::Atomic32 capture_enabled_;
-
- // The pseudo stack where frames are |TRACE_EVENT| names.
- AllocationStack pseudo_stack_;
-
- // A dictionary of arbitrary context.
- SmallMap<std::map<const char*, const char*>> context_;
-
- DISALLOW_COPY_AND_ASSIGN(AllocationContextTracker);
-};
-
-} // namespace trace_event
-} // namespace base
-
-#endif // BASE_TRACE_EVENT_MEMORY_PROFILER_ALLOCATION_CONTEXT_H_
diff --git a/chromium/base/trace_event/memory_profiler_allocation_context_unittest.cc b/chromium/base/trace_event/memory_profiler_allocation_context_unittest.cc
deleted file mode 100644
index a5b7244717a..00000000000
--- a/chromium/base/trace_event/memory_profiler_allocation_context_unittest.cc
+++ /dev/null
@@ -1,210 +0,0 @@
-// 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_profiler_allocation_context.h"
-#include "base/trace_event/trace_event.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace base {
-namespace trace_event {
-
-// Define all strings once, because the pseudo stack requires pointer equality,
-// and string interning is unreliable.
-const char kCupcake[] = "Cupcake";
-const char kDonut[] = "Donut";
-const char kEclair[] = "Eclair";
-const char kFroyo[] = "Froyo";
-const char kGingerbread[] = "Gingerbread";
-const char kHoneycomb[] = "Honeycomb";
-
-// Asserts that the fixed-size array |expected_stack| matches the pseudo
-// stack. Syntax note: |const StackFrame (&expected_stack)[N]| is the syntax
-// for "expected_stack is a reference to a const fixed-size array of StackFrame
-// of length N".
-template <size_t N>
-void AssertPseudoStackEquals(const StackFrame(&expected_stack)[N]) {
- auto pseudo_stack = AllocationContextTracker::GetPseudoStackForTesting();
- auto actual = pseudo_stack->top();
- auto actual_bottom = pseudo_stack->bottom();
- auto expected = expected_stack;
- auto expected_bottom = expected_stack + N;
-
- // Note that this requires the pointers to be equal, this is not doing a deep
- // string comparison.
- for (; actual != actual_bottom && expected != expected_bottom;
- actual++, expected++)
- ASSERT_EQ(*expected, *actual);
-
- // Ensure that the height of the stacks is the same.
- ASSERT_EQ(actual, actual_bottom);
- ASSERT_EQ(expected, expected_bottom);
-}
-
-void AssertPseudoStackEmpty() {
- auto pseudo_stack = AllocationContextTracker::GetPseudoStackForTesting();
- ASSERT_EQ(pseudo_stack->top(), pseudo_stack->bottom());
-}
-
-class AllocationContextTest : public testing::Test {
- public:
- void EnableTracing() {
- TraceConfig config("");
- TraceLog::GetInstance()->SetEnabled(config, TraceLog::RECORDING_MODE);
- AllocationContextTracker::SetCaptureEnabled(true);
- }
-
- void DisableTracing() {
- AllocationContextTracker::SetCaptureEnabled(false);
- TraceLog::GetInstance()->SetDisabled();
- }
-};
-
-TEST_F(AllocationContextTest, PseudoStackScopedTrace) {
- StackFrame c = kCupcake;
- StackFrame d = kDonut;
- StackFrame e = kEclair;
- StackFrame f = kFroyo;
-
- EnableTracing();
- AssertPseudoStackEmpty();
-
- {
- TRACE_EVENT0("Testing", kCupcake);
- StackFrame frame_c[] = {c};
- AssertPseudoStackEquals(frame_c);
-
- {
- TRACE_EVENT0("Testing", kDonut);
- StackFrame frame_dc[] = {d, c};
- AssertPseudoStackEquals(frame_dc);
- }
-
- AssertPseudoStackEquals(frame_c);
-
- {
- TRACE_EVENT0("Testing", kEclair);
- StackFrame frame_ec[] = {e, c};
- AssertPseudoStackEquals(frame_ec);
- }
-
- AssertPseudoStackEquals(frame_c);
- }
-
- AssertPseudoStackEmpty();
-
- {
- TRACE_EVENT0("Testing", kFroyo);
- StackFrame frame_f[] = {f};
- AssertPseudoStackEquals(frame_f);
- }
-
- AssertPseudoStackEmpty();
- DisableTracing();
-}
-
-TEST_F(AllocationContextTest, PseudoStackBeginEndTrace) {
- StackFrame c = kCupcake;
- StackFrame d = kDonut;
- StackFrame e = kEclair;
- StackFrame f = kFroyo;
-
- StackFrame frame_c[] = {c};
- StackFrame frame_dc[] = {d, c};
- StackFrame frame_ec[] = {e, c};
- StackFrame frame_f[] = {f};
-
- EnableTracing();
- AssertPseudoStackEmpty();
-
- TRACE_EVENT_BEGIN0("Testing", kCupcake);
- AssertPseudoStackEquals(frame_c);
-
- TRACE_EVENT_BEGIN0("Testing", kDonut);
- AssertPseudoStackEquals(frame_dc);
- TRACE_EVENT_END0("Testing", kDonut);
-
- AssertPseudoStackEquals(frame_c);
-
- TRACE_EVENT_BEGIN0("Testing", kEclair);
- AssertPseudoStackEquals(frame_ec);
- TRACE_EVENT_END0("Testing", kEclair);
-
- AssertPseudoStackEquals(frame_c);
- TRACE_EVENT_END0("Testing", kCupcake);
-
- AssertPseudoStackEmpty();
-
- TRACE_EVENT_BEGIN0("Testing", kFroyo);
- AssertPseudoStackEquals(frame_f);
- TRACE_EVENT_END0("Testing", kFroyo);
-
- AssertPseudoStackEmpty();
- DisableTracing();
-}
-
-TEST_F(AllocationContextTest, PseudoStackMixedTrace) {
- StackFrame c = kCupcake;
- StackFrame d = kDonut;
- StackFrame e = kEclair;
- StackFrame f = kFroyo;
-
- StackFrame frame_c[] = {c};
- StackFrame frame_dc[] = {d, c};
- StackFrame frame_e[] = {e};
- StackFrame frame_fe[] = {f, e};
-
- EnableTracing();
- AssertPseudoStackEmpty();
-
- TRACE_EVENT_BEGIN0("Testing", kCupcake);
- AssertPseudoStackEquals(frame_c);
-
- {
- TRACE_EVENT0("Testing", kDonut);
- AssertPseudoStackEquals(frame_dc);
- }
-
- AssertPseudoStackEquals(frame_c);
- TRACE_EVENT_END0("Testing", kCupcake);
- AssertPseudoStackEmpty();
-
- {
- TRACE_EVENT0("Testing", kEclair);
- AssertPseudoStackEquals(frame_e);
-
- TRACE_EVENT_BEGIN0("Testing", kFroyo);
- AssertPseudoStackEquals(frame_fe);
- TRACE_EVENT_END0("Testing", kFroyo);
- AssertPseudoStackEquals(frame_e);
- }
-
- AssertPseudoStackEmpty();
- DisableTracing();
-}
-
-TEST_F(AllocationContextTest, PseudoStackEnableWithEventInScope) {
- StackFrame h = kHoneycomb;
-
- {
- TRACE_EVENT0("Testing", kGingerbread);
- EnableTracing();
- AssertPseudoStackEmpty();
-
- {
- TRACE_EVENT0("Testing", kHoneycomb);
- StackFrame frame_h[] = {h};
- AssertPseudoStackEquals(frame_h);
- }
-
- AssertPseudoStackEmpty();
-
- // The pop at the end of this scope for the 'Gingerbread' frame must not
- // cause a stack underflow.
- }
- AssertPseudoStackEmpty();
- DisableTracing();
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/chromium/base/trace_event/process_memory_dump.cc b/chromium/base/trace_event/process_memory_dump.cc
index 67118f10e8c..ae60bb06b15 100644
--- a/chromium/base/trace_event/process_memory_dump.cc
+++ b/chromium/base/trace_event/process_memory_dump.cc
@@ -4,21 +4,90 @@
#include "base/trace_event/process_memory_dump.h"
+#include <errno.h>
+#include <vector>
+
+#include "base/process/process_metrics.h"
#include "base/trace_event/process_memory_totals.h"
#include "base/trace_event/trace_event_argument.h"
+#include "build/build_config.h"
+
+#if defined(OS_POSIX)
+#include <sys/mman.h>
+#endif
namespace base {
namespace trace_event {
namespace {
+
const char kEdgeTypeOwnership[] = "ownership";
std::string GetSharedGlobalAllocatorDumpName(
const MemoryAllocatorDumpGuid& guid) {
return "global/" + guid.ToString();
}
+
} // namespace
+#if defined(COUNT_RESIDENT_BYTES_SUPPORTED)
+// static
+size_t ProcessMemoryDump::CountResidentBytes(void* start_address,
+ size_t mapped_size) {
+ const size_t page_size = GetPageSize();
+ const uintptr_t start_pointer = reinterpret_cast<uintptr_t>(start_address);
+ DCHECK_EQ(0u, start_pointer % page_size);
+
+ // This function allocates a char vector of size number of pages in the given
+ // mapped_size. To avoid allocating a large array, the memory is split into
+ // chunks. Maximum size of vector allocated, will be
+ // kPageChunkSize / page_size.
+ const size_t kMaxChunkSize = 32 * 1024 * 1024;
+ size_t offset = 0;
+ size_t total_resident_size = 0;
+ int result = 0;
+ while (offset < mapped_size) {
+ void* chunk_start = reinterpret_cast<void*>(start_pointer + offset);
+ const size_t chunk_size = std::min(mapped_size - offset, kMaxChunkSize);
+ const size_t page_count = (chunk_size + page_size - 1) / page_size;
+ size_t resident_page_count = 0;
+
+#if defined(OS_MACOSX) || defined(OS_IOS)
+ std::vector<char> vec(page_count + 1);
+ // mincore in MAC does not fail with EAGAIN.
+ result = mincore(chunk_start, chunk_size, vec.data());
+ if (result)
+ break;
+
+ for (size_t i = 0; i < page_count; i++)
+ resident_page_count += vec[i] & MINCORE_INCORE ? 1 : 0;
+#else // defined(OS_MACOSX) || defined(OS_IOS)
+ std::vector<unsigned char> vec(page_count + 1);
+ int error_counter = 0;
+ // HANDLE_EINTR tries for 100 times. So following the same pattern.
+ do {
+ result = mincore(chunk_start, chunk_size, vec.data());
+ } while (result == -1 && errno == EAGAIN && error_counter++ < 100);
+ if (result)
+ break;
+
+ for (size_t i = 0; i < page_count; i++)
+ resident_page_count += vec[i];
+#endif // defined(OS_MACOSX) || defined(OS_IOS)
+
+ total_resident_size += resident_page_count * page_size;
+ offset += kMaxChunkSize;
+ }
+
+ DCHECK_EQ(0, result);
+ if (result) {
+ total_resident_size = 0;
+ LOG(ERROR) << "mincore() call failed. The resident size is invalid";
+ }
+ return total_resident_size;
+}
+#endif // defined(COUNT_RESIDENT_BYTES_SUPPORTED)
+
ProcessMemoryDump::ProcessMemoryDump(
const scoped_refptr<MemoryDumpSessionState>& session_state)
: has_process_totals_(false),
@@ -56,6 +125,12 @@ MemoryAllocatorDump* ProcessMemoryDump::GetAllocatorDump(
return it == allocator_dumps_.end() ? nullptr : it->second;
}
+MemoryAllocatorDump* ProcessMemoryDump::GetOrCreateAllocatorDump(
+ const std::string& absolute_name) {
+ MemoryAllocatorDump* mad = GetAllocatorDump(absolute_name);
+ return mad ? mad : CreateAllocatorDump(absolute_name);
+}
+
MemoryAllocatorDump* ProcessMemoryDump::CreateSharedGlobalAllocatorDump(
const MemoryAllocatorDumpGuid& guid) {
// A shared allocator dump can be shared within a process and the guid could
@@ -71,6 +146,12 @@ MemoryAllocatorDump* ProcessMemoryDump::GetSharedGlobalAllocatorDump(
return GetAllocatorDump(GetSharedGlobalAllocatorDumpName(guid));
}
+void ProcessMemoryDump::AddHeapDump(const std::string& absolute_name,
+ scoped_refptr<TracedValue> heap_dump) {
+ DCHECK_EQ(0ul, heap_dumps_.count(absolute_name));
+ heap_dumps_[absolute_name] = heap_dump;
+}
+
void ProcessMemoryDump::Clear() {
if (has_process_totals_) {
process_totals_.Clear();
@@ -85,6 +166,7 @@ void ProcessMemoryDump::Clear() {
allocator_dumps_storage_.clear();
allocator_dumps_.clear();
allocator_dumps_edges_.clear();
+ heap_dumps_.clear();
}
void ProcessMemoryDump::TakeAllDumpsFrom(ProcessMemoryDump* other) {
@@ -106,6 +188,9 @@ void ProcessMemoryDump::TakeAllDumpsFrom(ProcessMemoryDump* other) {
other->allocator_dumps_edges_.begin(),
other->allocator_dumps_edges_.end());
other->allocator_dumps_edges_.clear();
+
+ heap_dumps_.insert(other->heap_dumps_.begin(), other->heap_dumps_.end());
+ other->heap_dumps_.clear();
}
void ProcessMemoryDump::AsValueInto(TracedValue* value) const {
@@ -128,6 +213,13 @@ void ProcessMemoryDump::AsValueInto(TracedValue* value) const {
value->EndDictionary();
}
+ if (heap_dumps_.size() > 0) {
+ value->BeginDictionary("heaps");
+ for (const auto& name_and_dump : heap_dumps_)
+ value->SetValueWithCopiedName(name_and_dump.first, *name_and_dump.second);
+ value->EndDictionary(); // "heaps"
+ }
+
value->BeginArray("allocators_graph");
for (const MemoryAllocatorDumpEdge& edge : allocator_dumps_edges_) {
value->BeginDictionary();
diff --git a/chromium/base/trace_event/process_memory_dump.h b/chromium/base/trace_event/process_memory_dump.h
index da18a14b1ca..5a664028817 100644
--- a/chromium/base/trace_event/process_memory_dump.h
+++ b/chromium/base/trace_event/process_memory_dump.h
@@ -5,11 +5,14 @@
#ifndef BASE_TRACE_EVENT_PROCESS_MEMORY_DUMP_H_
#define BASE_TRACE_EVENT_PROCESS_MEMORY_DUMP_H_
+#include <stddef.h>
+
#include <vector>
#include "base/base_export.h"
#include "base/containers/hash_tables.h"
#include "base/containers/small_map.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_vector.h"
#include "base/trace_event/memory_allocator_dump.h"
@@ -17,6 +20,15 @@
#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"
+#include "build/build_config.h"
+
+// Define COUNT_RESIDENT_BYTES_SUPPORTED if platform supports counting of the
+// resident memory.
+// TODO(crbug.com/542671): COUNT_RESIDENT_BYTES_SUPPORTED is disabled on iOS
+// as it cause memory corruption on iOS 9.0+ devices.
+#if defined(OS_POSIX) && !defined(OS_NACL) && !defined(OS_IOS)
+#define COUNT_RESIDENT_BYTES_SUPPORTED
+#endif
namespace base {
namespace trace_event {
@@ -24,6 +36,7 @@ namespace trace_event {
class ConvertableToTraceFormat;
class MemoryDumpManager;
class MemoryDumpSessionState;
+class TracedValue;
// ProcessMemoryDump is as a strongly typed container which holds the dumps
// produced by the MemoryDumpProvider(s) for a specific process.
@@ -41,6 +54,17 @@ class BASE_EXPORT ProcessMemoryDump {
using AllocatorDumpsMap =
SmallMap<hash_map<std::string, MemoryAllocatorDump*>>;
+ using HeapDumpsMap =
+ SmallMap<hash_map<std::string, scoped_refptr<TracedValue>>>;
+
+#if defined(COUNT_RESIDENT_BYTES_SUPPORTED)
+ // Returns the total bytes resident for a virtual address range, with given
+ // |start_address| and |mapped_size|. |mapped_size| is specified in bytes. The
+ // value returned is valid only if the given range is currently mmapped by the
+ // process. The |start_address| must be page-aligned.
+ static size_t CountResidentBytes(void* start_address, size_t mapped_size);
+#endif
+
ProcessMemoryDump(const scoped_refptr<MemoryDumpSessionState>& session_state);
~ProcessMemoryDump();
@@ -64,6 +88,9 @@ class BASE_EXPORT ProcessMemoryDump {
// nullptr if not found.
MemoryAllocatorDump* GetAllocatorDump(const std::string& absolute_name) const;
+ MemoryAllocatorDump* GetOrCreateAllocatorDump(
+ const std::string& absolute_name);
+
// Creates a shared MemoryAllocatorDump, to express cross-process sharing.
// Shared allocator dumps are allowed to have duplicate guids within the
// global scope, in order to reference the same dump from multiple processes.
@@ -78,6 +105,12 @@ class BASE_EXPORT ProcessMemoryDump {
// Returns the map of the MemoryAllocatorDumps added to this dump.
const AllocatorDumpsMap& allocator_dumps() const { return allocator_dumps_; }
+ // Adds a heap dump for the allocator with |absolute_name|. The |TracedValue|
+ // must have the correct format. |trace_event::HeapDumper| will generate such
+ // a value from a |trace_event::AllocationRegister|.
+ void AddHeapDump(const std::string& absolute_name,
+ scoped_refptr<TracedValue> heap_dump);
+
// Adds an ownership relationship between two MemoryAllocatorDump(s) with the
// semantics: |source| owns |target|, and has the effect of attributing
// the memory usage of |target| to |source|. |importance| is optional and
@@ -138,6 +171,7 @@ class BASE_EXPORT ProcessMemoryDump {
bool has_process_mmaps_;
AllocatorDumpsMap allocator_dumps_;
+ HeapDumpsMap heap_dumps_;
// ProcessMemoryDump handles the memory ownership of all its belongings.
ScopedVector<MemoryAllocatorDump> allocator_dumps_storage_;
diff --git a/chromium/base/trace_event/process_memory_dump_unittest.cc b/chromium/base/trace_event/process_memory_dump_unittest.cc
index 1e1fbc69cf9..88984abd34d 100644
--- a/chromium/base/trace_event/process_memory_dump_unittest.cc
+++ b/chromium/base/trace_event/process_memory_dump_unittest.cc
@@ -4,7 +4,10 @@
#include "base/trace_event/process_memory_dump.h"
-#include "base/memory/scoped_ptr.h"
+#include <stddef.h>
+
+#include "base/memory/aligned_memory.h"
+#include "base/process/process_metrics.h"
#include "base/trace_event/memory_allocator_dump_guid.h"
#include "base/trace_event/trace_event_argument.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -154,5 +157,28 @@ TEST(ProcessMemoryDumpTest, Suballocations) {
pmd.reset();
}
+#if defined(COUNT_RESIDENT_BYTES_SUPPORTED)
+TEST(ProcessMemoryDumpTest, CountResidentBytes) {
+ const size_t page_size = base::GetPageSize();
+
+ // Allocate few page of dirty memory and check if it is resident.
+ const size_t size1 = 5 * page_size;
+ scoped_ptr<char, base::AlignedFreeDeleter> memory1(
+ static_cast<char*>(base::AlignedAlloc(size1, page_size)));
+ memset(memory1.get(), 0, size1);
+ size_t res1 = ProcessMemoryDump::CountResidentBytes(memory1.get(), size1);
+ ASSERT_EQ(res1, size1);
+
+ // Allocate a large memory segment (>32Mib).
+ const size_t kVeryLargeMemorySize = 34 * 1024 * 1024;
+ scoped_ptr<char, base::AlignedFreeDeleter> memory2(
+ static_cast<char*>(base::AlignedAlloc(kVeryLargeMemorySize, page_size)));
+ memset(memory2.get(), 0, kVeryLargeMemorySize);
+ size_t res2 = ProcessMemoryDump::CountResidentBytes(memory2.get(),
+ kVeryLargeMemorySize);
+ ASSERT_EQ(res2, kVeryLargeMemorySize);
+}
+#endif // defined(COUNT_RESIDENT_BYTES_SUPPORTED)
+
} // namespace trace_event
} // namespace base
diff --git a/chromium/base/trace_event/process_memory_maps.cc b/chromium/base/trace_event/process_memory_maps.cc
index bb400de1743..31083a89277 100644
--- a/chromium/base/trace_event/process_memory_maps.cc
+++ b/chromium/base/trace_event/process_memory_maps.cc
@@ -12,9 +12,9 @@ namespace base {
namespace trace_event {
// static
-const uint32 ProcessMemoryMaps::VMRegion::kProtectionFlagsRead = 4;
-const uint32 ProcessMemoryMaps::VMRegion::kProtectionFlagsWrite = 2;
-const uint32 ProcessMemoryMaps::VMRegion::kProtectionFlagsExec = 1;
+const uint32_t ProcessMemoryMaps::VMRegion::kProtectionFlagsRead = 4;
+const uint32_t ProcessMemoryMaps::VMRegion::kProtectionFlagsWrite = 2;
+const uint32_t ProcessMemoryMaps::VMRegion::kProtectionFlagsExec = 1;
ProcessMemoryMaps::VMRegion::VMRegion()
: start_address(0),
diff --git a/chromium/base/trace_event/process_memory_maps.h b/chromium/base/trace_event/process_memory_maps.h
index b06a85037a5..3dfcc0c988b 100644
--- a/chromium/base/trace_event/process_memory_maps.h
+++ b/chromium/base/trace_event/process_memory_maps.h
@@ -5,11 +5,13 @@
#ifndef BASE_TRACE_EVENT_PROCESS_MEMORY_MAPS_H_
#define BASE_TRACE_EVENT_PROCESS_MEMORY_MAPS_H_
+#include <stdint.h>
+
#include <string>
#include <vector>
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
namespace base {
namespace trace_event {
@@ -20,28 +22,28 @@ class TracedValue;
class BASE_EXPORT ProcessMemoryMaps {
public:
struct BASE_EXPORT VMRegion {
- static const uint32 kProtectionFlagsRead;
- static const uint32 kProtectionFlagsWrite;
- static const uint32 kProtectionFlagsExec;
+ static const uint32_t kProtectionFlagsRead;
+ static const uint32_t kProtectionFlagsWrite;
+ static const uint32_t kProtectionFlagsExec;
VMRegion();
- uint64 start_address;
- uint64 size_in_bytes;
- uint32 protection_flags;
+ uint64_t start_address;
+ uint64_t size_in_bytes;
+ uint32_t protection_flags;
std::string mapped_file;
// private_dirty_resident + private_clean_resident + shared_dirty_resident +
// shared_clean_resident = resident set size.
- uint64 byte_stats_private_dirty_resident;
- uint64 byte_stats_private_clean_resident;
- uint64 byte_stats_shared_dirty_resident;
- uint64 byte_stats_shared_clean_resident;
+ uint64_t byte_stats_private_dirty_resident;
+ uint64_t byte_stats_private_clean_resident;
+ uint64_t byte_stats_shared_dirty_resident;
+ uint64_t byte_stats_shared_clean_resident;
- uint64 byte_stats_swapped;
+ uint64_t byte_stats_swapped;
// For multiprocess accounting.
- uint64 byte_stats_proportional_resident;
+ uint64_t byte_stats_proportional_resident;
};
ProcessMemoryMaps();
diff --git a/chromium/base/trace_event/process_memory_maps_dump_provider.cc b/chromium/base/trace_event/process_memory_maps_dump_provider.cc
index 38b2573e6b6..4c3959fe9be 100644
--- a/chromium/base/trace_event/process_memory_maps_dump_provider.cc
+++ b/chromium/base/trace_event/process_memory_maps_dump_provider.cc
@@ -4,35 +4,38 @@
#include "base/trace_event/process_memory_maps_dump_provider.h"
-#include <cctype>
-#include <fstream>
+#include <stdint.h>
+#include "base/files/scoped_file.h"
+#include "base/format_macros.h"
#include "base/logging.h"
-#include "base/process/process_metrics.h"
+#include "base/strings/string_util.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;
+FILE* ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = nullptr;
namespace {
-const uint32 kMaxLineSize = 4096;
+const uint32_t kMaxLineSize = 4096;
-bool ParseSmapsHeader(std::istream* smaps,
+bool ParseSmapsHeader(const char* header_line,
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;
+ uint64_t end_addr = 0;
+ char protection_flags[5] = {0};
+ char mapped_file[kMaxLineSize];
+
+ if (sscanf(header_line, "%" SCNx64 "-%" SCNx64 " %4c %*s %*s %*s%4095[^\n]\n",
+ &region->start_address, &end_addr, protection_flags,
+ mapped_file) != 4)
+ return false;
+
if (end_addr > region->start_address) {
region->size_in_bytes = end_addr - region->start_address;
} else {
@@ -42,8 +45,6 @@ bool ParseSmapsHeader(std::istream* smaps,
}
region->protection_flags = 0;
- *smaps >> protection_flags;
- CHECK_EQ(4UL, protection_flags.size());
if (protection_flags[0] == 'r') {
region->protection_flags |=
ProcessMemoryMaps::VMRegion::kProtectionFlagsRead;
@@ -56,84 +57,70 @@ bool ParseSmapsHeader(std::istream* smaps,
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;
+ TrimWhitespaceASCII(region->mapped_file, TRIM_ALL, &region->mapped_file);
return res;
}
-uint64 ReadCounterBytes(std::istream* smaps) {
- uint64 counter_value = 0;
- *smaps >> std::dec >> counter_value;
+uint64_t ReadCounterBytes(char* counter_line) {
+ uint64_t counter_value = 0;
+ int res = sscanf(counter_line, "%*s %" SCNu64 " kB", &counter_value);
+ DCHECK_EQ(1, res);
return counter_value * 1024;
}
-uint32 ParseSmapsCounter(std::istream* smaps,
- ProcessMemoryMaps::VMRegion* region) {
+uint32_t ParseSmapsCounter(char* counter_line,
+ ProcessMemoryMaps::VMRegion* region) {
// A smaps counter lines looks as follows: "RSS: 0 Kb\n"
- uint32 res = 1;
- 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);
- } else if (counter_name == "Private_Dirty:") {
- region->byte_stats_private_dirty_resident = ReadCounterBytes(smaps);
- } else if (counter_name == "Private_Clean:") {
- region->byte_stats_private_clean_resident = ReadCounterBytes(smaps);
- } else if (counter_name == "Shared_Dirty:") {
- region->byte_stats_shared_dirty_resident = ReadCounterBytes(smaps);
- } else if (counter_name == "Shared_Clean:") {
- region->byte_stats_shared_clean_resident = ReadCounterBytes(smaps);
- } else if (counter_name == "Swap:") {
- region->byte_stats_swapped = ReadCounterBytes(smaps);
+ uint32_t res = 1;
+ char counter_name[20];
+ int did_read = sscanf(counter_line, "%19[^\n ]", counter_name);
+ DCHECK_EQ(1, did_read);
+
+ if (strcmp(counter_name, "Pss:") == 0) {
+ region->byte_stats_proportional_resident = ReadCounterBytes(counter_line);
+ } else if (strcmp(counter_name, "Private_Dirty:") == 0) {
+ region->byte_stats_private_dirty_resident = ReadCounterBytes(counter_line);
+ } else if (strcmp(counter_name, "Private_Clean:") == 0) {
+ region->byte_stats_private_clean_resident = ReadCounterBytes(counter_line);
+ } else if (strcmp(counter_name, "Shared_Dirty:") == 0) {
+ region->byte_stats_shared_dirty_resident = ReadCounterBytes(counter_line);
+ } else if (strcmp(counter_name, "Shared_Clean:") == 0) {
+ region->byte_stats_shared_clean_resident = ReadCounterBytes(counter_line);
+ } else if (strcmp(counter_name, "Swap:") == 0) {
+ region->byte_stats_swapped = ReadCounterBytes(counter_line);
} else {
res = 0;
}
-#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())
+uint32_t ReadLinuxProcSmapsFile(FILE* smaps_file, ProcessMemoryMaps* pmm) {
+ if (!smaps_file)
return 0;
- const uint32 kNumExpectedCountersPerRegion = 6;
- uint32 counters_parsed_for_current_region = 0;
- uint32 num_valid_regions = 0;
+ fseek(smaps_file, 0, SEEK_SET);
+
+ char line[kMaxLineSize];
+ const uint32_t kNumExpectedCountersPerRegion = 6;
+ uint32_t counters_parsed_for_current_region = 0;
+ uint32_t 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')
+ line[0] = '\0';
+ if (fgets(line, kMaxLineSize, smaps_file) == nullptr)
break;
- if (isxdigit(next) && !isupper(next)) {
+ DCHECK_GT(strlen(line), 0u);
+ if (isxdigit(line[0]) && !isupper(line[0])) {
region = ProcessMemoryMaps::VMRegion();
counters_parsed_for_current_region = 0;
- should_add_current_region = ParseSmapsHeader(smaps, &region);
+ should_add_current_region = ParseSmapsHeader(line, &region);
} else {
- counters_parsed_for_current_region += ParseSmapsCounter(smaps, &region);
+ counters_parsed_for_current_region += ParseSmapsCounter(line, &region);
DCHECK_LE(counters_parsed_for_current_region,
kNumExpectedCountersPerRegion);
if (counters_parsed_for_current_region == kNumExpectedCountersPerRegion) {
@@ -149,7 +136,6 @@ uint32 ReadLinuxProcSmapsFile(std::istream* smaps, ProcessMemoryMaps* pmm) {
}
} // namespace
-#endif // defined(OS_LINUX) || defined(OS_ANDROID)
// static
ProcessMemoryMapsDumpProvider* ProcessMemoryMapsDumpProvider::GetInstance() {
@@ -171,24 +157,18 @@ bool ProcessMemoryMapsDumpProvider::OnMemoryDump(const MemoryDumpArgs& args,
if (args.level_of_detail == MemoryDumpLevelOfDetail::LIGHT)
return true;
- uint32 res = 0;
-
-#if defined(OS_LINUX) || defined(OS_ANDROID)
+ uint32_t res = 0;
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());
+ ScopedFILE smaps_file(fopen("/proc/self/smaps", "r"));
+ res = ReadLinuxProcSmapsFile(smaps_file.get(), 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;
}
diff --git a/chromium/base/trace_event/process_memory_maps_dump_provider.h b/chromium/base/trace_event/process_memory_maps_dump_provider.h
index 5a0f84cbb66..84badfe9a06 100644
--- a/chromium/base/trace_event/process_memory_maps_dump_provider.h
+++ b/chromium/base/trace_event/process_memory_maps_dump_provider.h
@@ -5,11 +5,11 @@
#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/macros.h"
#include "base/memory/singleton.h"
#include "base/trace_event/memory_dump_provider.h"
+#include "build/build_config.h"
namespace base {
namespace trace_event {
@@ -27,8 +27,8 @@ class BASE_EXPORT ProcessMemoryMapsDumpProvider : public MemoryDumpProvider {
friend struct DefaultSingletonTraits<ProcessMemoryMapsDumpProvider>;
FRIEND_TEST_ALL_PREFIXES(ProcessMemoryMapsDumpProviderTest, ParseProcSmaps);
-#if defined(OS_LINUX) || defined(OS_ANDROID)
- static std::istream* proc_smaps_for_testing;
+#if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_NACL)
+ static FILE* proc_smaps_for_testing;
#endif
ProcessMemoryMapsDumpProvider();
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
index a73a21c772e..624f96fcb0a 100644
--- a/chromium/base/trace_event/process_memory_maps_dump_provider_unittest.cc
+++ b/chromium/base/trace_event/process_memory_maps_dump_provider_unittest.cc
@@ -4,9 +4,9 @@
#include "base/trace_event/process_memory_maps_dump_provider.h"
-#include <fstream>
-#include <sstream>
+#include <stdint.h>
+#include "base/files/file_util.h"
#include "base/trace_event/process_memory_dump.h"
#include "base/trace_event/process_memory_maps.h"
#include "base/trace_event/trace_event_argument.h"
@@ -15,7 +15,6 @@
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"
@@ -104,35 +103,41 @@ const char kTestSmaps2[] =
"MMUPageSize: 4 kB\n"
"Locked: 0 kB\n"
"VmFlags: rd wr mr mw me ac sd\n";
+
+void CreateAndSetSmapsFileForTesting(const char* smaps_string,
+ ScopedFILE& file) {
+ FilePath temp_path;
+ FILE* temp_file = CreateAndOpenTemporaryFile(&temp_path);
+ file.reset(temp_file);
+ ASSERT_TRUE(temp_file);
+
+ ASSERT_TRUE(base::WriteFileDescriptor(fileno(temp_file), smaps_string,
+ strlen(smaps_string)));
+}
+
} // namespace
TEST(ProcessMemoryMapsDumpProviderTest, ParseProcSmaps) {
- const uint32 kProtR = ProcessMemoryMaps::VMRegion::kProtectionFlagsRead;
- const uint32 kProtW = ProcessMemoryMaps::VMRegion::kProtectionFlagsWrite;
- const uint32 kProtX = ProcessMemoryMaps::VMRegion::kProtectionFlagsExec;
+ const uint32_t kProtR = ProcessMemoryMaps::VMRegion::kProtectionFlagsRead;
+ const uint32_t kProtW = ProcessMemoryMaps::VMRegion::kProtectionFlagsWrite;
+ const uint32_t kProtX = ProcessMemoryMaps::VMRegion::kProtectionFlagsExec;
const MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::DETAILED};
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(dump_args, &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());
+ ProcessMemoryDump pmd_invalid(nullptr /* session_state */);
+ ScopedFILE empty_file(OpenFile(FilePath("/dev/null"), "r"));
+ ASSERT_TRUE(empty_file.get());
+ ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = empty_file.get();
pmmdp->OnMemoryDump(dump_args, &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;
+ ScopedFILE temp_file1;
+ CreateAndSetSmapsFileForTesting(kTestSmaps1, temp_file1);
+ ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = temp_file1.get();
pmmdp->OnMemoryDump(dump_args, &pmd_1);
ASSERT_TRUE(pmd_1.has_process_mmaps());
const auto& regions_1 = pmd_1.process_mmaps()->vm_regions();
@@ -162,8 +167,9 @@ TEST(ProcessMemoryMapsDumpProviderTest, ParseProcSmaps) {
// 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;
+ ScopedFILE temp_file2;
+ CreateAndSetSmapsFileForTesting(kTestSmaps2, temp_file2);
+ ProcessMemoryMapsDumpProvider::proc_smaps_for_testing = temp_file2.get();
pmmdp->OnMemoryDump(dump_args, &pmd_2);
ASSERT_TRUE(pmd_2.has_process_mmaps());
const auto& regions_2 = pmd_2.process_mmaps()->vm_regions();
@@ -179,7 +185,6 @@ TEST(ProcessMemoryMapsDumpProviderTest, ParseProcSmaps) {
EXPECT_EQ(4 * 1024UL, regions_2[0].byte_stats_private_dirty_resident);
EXPECT_EQ(0 * 1024UL, regions_2[0].byte_stats_swapped);
}
-#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
index 1270924fbfb..de27ab3d9d4 100644
--- a/chromium/base/trace_event/process_memory_totals.cc
+++ b/chromium/base/trace_event/process_memory_totals.cc
@@ -17,6 +17,8 @@ ProcessMemoryTotals::ProcessMemoryTotals()
is_peak_rss_resetable_(false) {
}
+ProcessMemoryTotals::~ProcessMemoryTotals() {}
+
void ProcessMemoryTotals::AsValueInto(TracedValue* value) const {
value->SetString("resident_set_bytes",
StringPrintf("%" PRIx64, resident_set_bytes_));
@@ -25,11 +27,21 @@ void ProcessMemoryTotals::AsValueInto(TracedValue* value) const {
StringPrintf("%" PRIx64, peak_resident_set_bytes_));
value->SetBoolean("is_peak_rss_resetable", is_peak_rss_resetable_);
}
+
+ for (const auto it : extra_fields_) {
+ value->SetString(it.first, StringPrintf("%" PRIx64, it.second));
+ }
}
void ProcessMemoryTotals::Clear() {
resident_set_bytes_ = 0;
}
+void ProcessMemoryTotals::SetExtraFieldInBytes(const char* name,
+ uint64_t value) {
+ DCHECK_EQ(0u, extra_fields_.count(name));
+ extra_fields_[name] = value;
+}
+
} // 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
index 1bf8bdcd7b4..329967a6ee7 100644
--- a/chromium/base/trace_event/process_memory_totals.h
+++ b/chromium/base/trace_event/process_memory_totals.h
@@ -5,8 +5,12 @@
#ifndef BASE_TRACE_EVENT_PROCESS_MEMORY_TOTALS_H_
#define BASE_TRACE_EVENT_PROCESS_MEMORY_TOTALS_H_
+#include <stdint.h>
+
+#include <map>
+
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
namespace base {
namespace trace_event {
@@ -17,6 +21,7 @@ class TracedValue;
class BASE_EXPORT ProcessMemoryTotals {
public:
ProcessMemoryTotals();
+ ~ProcessMemoryTotals();
// Called at trace generation time to populate the TracedValue.
void AsValueInto(TracedValue* value) const;
@@ -24,11 +29,11 @@ class BASE_EXPORT ProcessMemoryTotals {
// Clears up all the data collected.
void Clear();
- uint64 resident_set_bytes() const { return resident_set_bytes_; }
- void set_resident_set_bytes(uint64 value) { resident_set_bytes_ = value; }
+ uint64_t resident_set_bytes() const { return resident_set_bytes_; }
+ void set_resident_set_bytes(uint64_t value) { resident_set_bytes_ = value; }
- uint64 peak_resident_set_bytes() const { return peak_resident_set_bytes_; }
- void set_peak_resident_set_bytes(uint64 value) {
+ uint64_t peak_resident_set_bytes() const { return peak_resident_set_bytes_; }
+ void set_peak_resident_set_bytes(uint64_t value) {
peak_resident_set_bytes_ = value;
}
@@ -39,11 +44,16 @@ class BASE_EXPORT ProcessMemoryTotals {
bool is_peak_rss_resetable() const { return is_peak_rss_resetable_; }
void set_is_peak_rss_resetable(bool value) { is_peak_rss_resetable_ = value; }
+ void SetExtraFieldInBytes(const char* name, uint64_t value);
+
private:
- uint64 resident_set_bytes_;
- uint64 peak_resident_set_bytes_;
+ uint64_t resident_set_bytes_;
+ uint64_t peak_resident_set_bytes_;
bool is_peak_rss_resetable_;
+ // Extra metrics for OS-specific statistics.
+ std::map<const char*, uint64_t> extra_fields_;
+
DISALLOW_COPY_AND_ASSIGN(ProcessMemoryTotals);
};
diff --git a/chromium/base/trace_event/process_memory_totals_dump_provider.cc b/chromium/base/trace_event/process_memory_totals_dump_provider.cc
index a8617207dcf..1713ebf0bc9 100644
--- a/chromium/base/trace_event/process_memory_totals_dump_provider.cc
+++ b/chromium/base/trace_event/process_memory_totals_dump_provider.cc
@@ -4,9 +4,12 @@
#include "base/trace_event/process_memory_totals_dump_provider.h"
+#include <stddef.h>
+
#include "base/process/process_metrics.h"
#include "base/trace_event/process_memory_dump.h"
#include "base/trace_event/process_memory_totals.h"
+#include "build/build_config.h"
#if defined(OS_LINUX) || defined(OS_ANDROID)
#include <fcntl.h>
@@ -23,18 +26,7 @@ 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
+uint64_t ProcessMemoryTotalsDumpProvider::rss_bytes_for_testing = 0;
// static
ProcessMemoryTotalsDumpProvider*
@@ -45,8 +37,7 @@ ProcessMemoryTotalsDumpProvider::GetInstance() {
}
ProcessMemoryTotalsDumpProvider::ProcessMemoryTotalsDumpProvider()
- : process_metrics_(CreateProcessMetricsForCurrentProcess()) {
-}
+ : process_metrics_(ProcessMetrics::CreateCurrentProcessMetrics()) {}
ProcessMemoryTotalsDumpProvider::~ProcessMemoryTotalsDumpProvider() {
}
@@ -55,11 +46,11 @@ ProcessMemoryTotalsDumpProvider::~ProcessMemoryTotalsDumpProvider() {
// the current process.
bool ProcessMemoryTotalsDumpProvider::OnMemoryDump(const MemoryDumpArgs& args,
ProcessMemoryDump* pmd) {
- const uint64 rss_bytes = rss_bytes_for_testing
- ? rss_bytes_for_testing
- : process_metrics_->GetWorkingSetSize();
+ const uint64_t rss_bytes = rss_bytes_for_testing
+ ? rss_bytes_for_testing
+ : process_metrics_->GetWorkingSetSize();
- uint64 peak_rss_bytes = 0;
+ uint64_t peak_rss_bytes = 0;
#if !defined(OS_IOS)
peak_rss_bytes = process_metrics_->GetPeakWorkingSetSize();
@@ -77,6 +68,13 @@ bool ProcessMemoryTotalsDumpProvider::OnMemoryDump(const MemoryDumpArgs& args,
}
close(clear_refs_fd);
}
+#elif defined(OS_MACOSX)
+ size_t private_bytes;
+ bool res = process_metrics_->GetMemoryBytes(&private_bytes,
+ nullptr /* shared_bytes */);
+ if (res) {
+ pmd->process_totals()->SetExtraFieldInBytes("private_bytes", private_bytes);
+ }
#endif // defined(OS_LINUX) || defined(OS_ANDROID)
#endif // !defined(OS_IOS)
diff --git a/chromium/base/trace_event/process_memory_totals_dump_provider.h b/chromium/base/trace_event/process_memory_totals_dump_provider.h
index 66d4f9956dd..d9573d31e1b 100644
--- a/chromium/base/trace_event/process_memory_totals_dump_provider.h
+++ b/chromium/base/trace_event/process_memory_totals_dump_provider.h
@@ -5,7 +5,10 @@
#ifndef BASE_TRACE_EVENT_PROCESS_MEMORY_TOTALS_DUMP_PROVIDER_H_
#define BASE_TRACE_EVENT_PROCESS_MEMORY_TOTALS_DUMP_PROVIDER_H_
+#include <stdint.h>
+
#include "base/gtest_prod_util.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/singleton.h"
#include "base/trace_event/memory_dump_provider.h"
@@ -29,7 +32,7 @@ class BASE_EXPORT ProcessMemoryTotalsDumpProvider : public MemoryDumpProvider {
friend struct DefaultSingletonTraits<ProcessMemoryTotalsDumpProvider>;
FRIEND_TEST_ALL_PREFIXES(ProcessMemoryTotalsDumpProviderTest, DumpRSS);
- static uint64 rss_bytes_for_testing;
+ static uint64_t rss_bytes_for_testing;
ProcessMemoryTotalsDumpProvider();
~ProcessMemoryTotalsDumpProvider() override;
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
index 4ec37f57653..d3f517e2836 100644
--- a/chromium/base/trace_event/process_memory_totals_dump_provider_unittest.cc
+++ b/chromium/base/trace_event/process_memory_totals_dump_provider_unittest.cc
@@ -4,6 +4,9 @@
#include "base/trace_event/process_memory_totals_dump_provider.h"
+#include <stddef.h>
+#include <stdint.h>
+
#include "base/trace_event/process_memory_dump.h"
#include "base/trace_event/process_memory_totals.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -31,8 +34,9 @@ TEST(ProcessMemoryTotalsDumpProviderTest, DumpRSS) {
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();
+ const uint64_t rss_before =
+ pmd_before->process_totals()->resident_set_bytes();
+ const uint64_t rss_after = pmd_after->process_totals()->resident_set_bytes();
EXPECT_NE(0U, rss_before);
EXPECT_NE(0U, rss_after);
diff --git a/chromium/base/trace_event/trace_buffer.cc b/chromium/base/trace_event/trace_buffer.cc
index a2e4f141ef4..e96699f69df 100644
--- a/chromium/base/trace_event/trace_buffer.cc
+++ b/chromium/base/trace_event/trace_buffer.cc
@@ -4,7 +4,11 @@
#include "base/trace_event/trace_buffer.h"
-#include "base/memory/scoped_vector.h"
+#include <utility>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
#include "base/trace_event/trace_event_impl.h"
namespace base {
@@ -38,7 +42,7 @@ class TraceBufferRingBuffer : public TraceBuffer {
if (*index >= chunks_.size())
chunks_.resize(*index + 1);
- TraceBufferChunk* chunk = chunks_[*index];
+ TraceBufferChunk* chunk = chunks_[*index].release();
chunks_[*index] = NULL; // Put NULL in the slot of a in-flight chunk.
if (chunk)
chunk->Reset(current_chunk_seq_++);
@@ -55,7 +59,7 @@ class TraceBufferRingBuffer : public TraceBuffer {
DCHECK(chunk);
DCHECK_LT(index, chunks_.size());
DCHECK(!chunks_[index]);
- chunks_[index] = chunk.release();
+ chunks_[index] = std::move(chunk);
recyclable_chunks_queue_[queue_tail_] = index;
queue_tail_ = NextQueueIndex(queue_tail_);
}
@@ -74,7 +78,7 @@ class TraceBufferRingBuffer : public TraceBuffer {
TraceEvent* GetEventByHandle(TraceEventHandle handle) override {
if (handle.chunk_index >= chunks_.size())
return NULL;
- TraceBufferChunk* chunk = chunks_[handle.chunk_index];
+ TraceBufferChunk* chunk = chunks_[handle.chunk_index].get();
if (!chunk || chunk->seq() != handle.chunk_seq)
return NULL;
return chunk->GetEventAt(handle.event_index);
@@ -90,7 +94,7 @@ class TraceBufferRingBuffer : public TraceBuffer {
if (chunk_index >= chunks_.size()) // Skip uninitialized chunks.
continue;
DCHECK(chunks_[chunk_index]);
- return chunks_[chunk_index];
+ return chunks_[chunk_index].get();
}
return NULL;
}
@@ -102,10 +106,10 @@ class TraceBufferRingBuffer : public TraceBuffer {
size_t chunk_index = recyclable_chunks_queue_[queue_index];
if (chunk_index >= chunks_.size()) // Skip uninitialized chunks.
continue;
- TraceBufferChunk* chunk = chunks_[chunk_index];
- cloned_buffer->chunks_.push_back(chunk ? chunk->Clone().release() : NULL);
+ TraceBufferChunk* chunk = chunks_[chunk_index].get();
+ cloned_buffer->chunks_.push_back(chunk ? chunk->Clone() : NULL);
}
- return cloned_buffer.Pass();
+ return std::move(cloned_buffer);
}
void EstimateTraceMemoryOverhead(
@@ -128,7 +132,7 @@ class TraceBufferRingBuffer : public TraceBuffer {
// The only implemented method.
const TraceBufferChunk* NextChunk() override {
return current_iteration_index_ < chunks_.size()
- ? chunks_[current_iteration_index_++]
+ ? chunks_[current_iteration_index_++].get()
: NULL;
}
@@ -155,7 +159,7 @@ class TraceBufferRingBuffer : public TraceBuffer {
}
size_t current_iteration_index_;
- ScopedVector<TraceBufferChunk> chunks_;
+ std::vector<scoped_ptr<TraceBufferChunk>> chunks_;
};
bool QueueIsEmpty() const { return queue_head_ == queue_tail_; }
@@ -181,14 +185,14 @@ class TraceBufferRingBuffer : public TraceBuffer {
}
size_t max_chunks_;
- ScopedVector<TraceBufferChunk> chunks_;
+ std::vector<scoped_ptr<TraceBufferChunk>> chunks_;
scoped_ptr<size_t[]> recyclable_chunks_queue_;
size_t queue_head_;
size_t queue_tail_;
size_t current_iteration_index_;
- uint32 current_chunk_seq_;
+ uint32_t current_chunk_seq_;
DISALLOW_COPY_AND_ASSIGN(TraceBufferRingBuffer);
};
@@ -212,7 +216,7 @@ class TraceBufferVector : public TraceBuffer {
++in_flight_chunk_count_;
// + 1 because zero chunk_seq is not allowed.
return scoped_ptr<TraceBufferChunk>(
- new TraceBufferChunk(static_cast<uint32>(*index) + 1));
+ new TraceBufferChunk(static_cast<uint32_t>(*index) + 1));
}
void ReturnChunk(size_t index, scoped_ptr<TraceBufferChunk> chunk) override {
@@ -286,11 +290,11 @@ class TraceBufferVector : public TraceBuffer {
} // namespace
-TraceBufferChunk::TraceBufferChunk(uint32 seq) : next_free_(0), seq_(seq) {}
+TraceBufferChunk::TraceBufferChunk(uint32_t seq) : next_free_(0), seq_(seq) {}
TraceBufferChunk::~TraceBufferChunk() {}
-void TraceBufferChunk::Reset(uint32 new_seq) {
+void TraceBufferChunk::Reset(uint32_t new_seq) {
for (size_t i = 0; i < next_free_; ++i)
chunk_[i].Reset();
next_free_ = 0;
@@ -309,7 +313,7 @@ scoped_ptr<TraceBufferChunk> TraceBufferChunk::Clone() const {
cloned_chunk->next_free_ = next_free_;
for (size_t i = 0; i < next_free_; ++i)
cloned_chunk->chunk_[i].CopyFrom(chunk_[i]);
- return cloned_chunk.Pass();
+ return cloned_chunk;
}
void TraceBufferChunk::EstimateTraceMemoryOverhead(
diff --git a/chromium/base/trace_event/trace_buffer.h b/chromium/base/trace_event/trace_buffer.h
index d54bd74bec5..a7b80595b54 100644
--- a/chromium/base/trace_event/trace_buffer.h
+++ b/chromium/base/trace_event/trace_buffer.h
@@ -5,6 +5,9 @@
#ifndef BASE_TRACE_EVENT_TRACE_BUFFER_H_
#define BASE_TRACE_EVENT_TRACE_BUFFER_H_
+#include <stddef.h>
+#include <stdint.h>
+
#include "base/base_export.h"
#include "base/trace_event/trace_event.h"
#include "base/trace_event/trace_event_impl.h"
@@ -16,14 +19,14 @@ namespace trace_event {
// TraceBufferChunk is the basic unit of TraceBuffer.
class BASE_EXPORT TraceBufferChunk {
public:
- explicit TraceBufferChunk(uint32 seq);
+ explicit TraceBufferChunk(uint32_t seq);
~TraceBufferChunk();
- void Reset(uint32 new_seq);
+ void Reset(uint32_t new_seq);
TraceEvent* AddTraceEvent(size_t* event_index);
bool IsFull() const { return next_free_ == kTraceBufferChunkSize; }
- uint32 seq() const { return seq_; }
+ uint32_t seq() const { return seq_; }
size_t capacity() const { return kTraceBufferChunkSize; }
size_t size() const { return next_free_; }
@@ -50,7 +53,7 @@ class BASE_EXPORT TraceBufferChunk {
size_t next_free_;
scoped_ptr<TraceEventMemoryOverhead> cached_overhead_estimate_;
TraceEvent chunk_[kTraceBufferChunkSize];
- uint32 seq_;
+ uint32_t seq_;
};
// TraceBuffer holds the events as they are collected.
diff --git a/chromium/base/trace_event/trace_config.cc b/chromium/base/trace_event/trace_config.cc
index 9f0367bd2a2..8e11078ebc7 100644
--- a/chromium/base/trace_event/trace_config.cc
+++ b/chromium/base/trace_event/trace_config.cc
@@ -4,6 +4,10 @@
#include "base/trace_event/trace_config.h"
+#include <stddef.h>
+
+#include <utility>
+
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/strings/pattern.h"
@@ -54,6 +58,22 @@ const TraceConfig::MemoryDumpTriggerConfig kDefaultLightMemoryDumpTrigger = {
250, // periodic_interval_ms
MemoryDumpLevelOfDetail::LIGHT};
+class ConvertableTraceConfigToTraceFormat
+ : public base::trace_event::ConvertableToTraceFormat {
+ public:
+ explicit ConvertableTraceConfigToTraceFormat(const TraceConfig& trace_config)
+ : trace_config_(trace_config) {}
+ void AppendAsTraceFormat(std::string* out) const override {
+ out->append(trace_config_.ToString());
+ }
+
+ protected:
+ ~ConvertableTraceConfigToTraceFormat() override {}
+
+ private:
+ const TraceConfig trace_config_;
+};
+
} // namespace
TraceConfig::TraceConfig() {
@@ -138,6 +158,11 @@ std::string TraceConfig::ToString() const {
return json;
}
+scoped_refptr<ConvertableToTraceFormat>
+TraceConfig::AsConvertableToTraceFormat() const {
+ return new ConvertableTraceConfigToTraceFormat(*this);
+}
+
std::string TraceConfig::ToCategoryFilterString() const {
std::string filter_string;
WriteCategoryFilterString(included_categories_, &filter_string, true);
@@ -188,9 +213,13 @@ bool TraceConfig::IsCategoryGroupEnabled(
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;
+ // excluded_ list. So, if it's not a disabled-by-default category,
+ // it has to be included_ list. Enable the category_group_name
+ // for recording.
+ if (!base::MatchPattern(category_group_token.c_str(),
+ TRACE_DISABLED_BY_DEFAULT("*"))) {
+ 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
@@ -445,7 +474,7 @@ void TraceConfig::AddCategoryToDict(base::DictionaryValue& dict,
list->AppendString(*ci);
}
- dict.Set(param, list.Pass());
+ dict.Set(param, std::move(list));
}
void TraceConfig::SetMemoryDumpConfig(
@@ -470,7 +499,7 @@ void TraceConfig::SetMemoryDumpConfig(
continue;
}
DCHECK_GT(interval, 0);
- dump_config.periodic_interval_ms = static_cast<uint32>(interval);
+ dump_config.periodic_interval_ms = static_cast<uint32_t>(interval);
std::string level_of_detail_str;
trigger->GetString(kModeParam, &level_of_detail_str);
dump_config.level_of_detail =
@@ -537,13 +566,13 @@ void TraceConfig::ToDict(base::DictionaryValue& dict) const {
static_cast<int>(config.periodic_interval_ms));
trigger_dict->SetString(
kModeParam, MemoryDumpLevelOfDetailToString(config.level_of_detail));
- triggers_list->Append(trigger_dict.Pass());
+ triggers_list->Append(std::move(trigger_dict));
}
// Empty triggers will still be specified explicitly since it means that
// the periodic dumps are not enabled.
- memory_dump_config->Set(kTriggersParam, triggers_list.Pass());
- dict.Set(kMemoryDumpConfigParam, memory_dump_config.Pass());
+ memory_dump_config->Set(kTriggersParam, std::move(triggers_list));
+ dict.Set(kMemoryDumpConfigParam, std::move(memory_dump_config));
}
}
diff --git a/chromium/base/trace_event/trace_config.h b/chromium/base/trace_event/trace_config.h
index 44cf16df878..c7d3f4b379b 100644
--- a/chromium/base/trace_event/trace_config.h
+++ b/chromium/base/trace_event/trace_config.h
@@ -5,6 +5,8 @@
#ifndef BASE_TRACE_EVENT_TRACE_CONFIG_H_
#define BASE_TRACE_EVENT_TRACE_CONFIG_H_
+#include <stdint.h>
+
#include <string>
#include <vector>
@@ -16,6 +18,8 @@
namespace base {
namespace trace_event {
+class ConvertableToTraceFormat;
+
// Options determines how the trace buffer stores data.
enum TraceRecordMode {
// Record until the trace buffer is full.
@@ -39,7 +43,7 @@ class BASE_EXPORT TraceConfig {
// Specifies the memory dump config for tracing. Used only when
// "memory-infra" category is enabled.
struct MemoryDumpTriggerConfig {
- uint32 periodic_interval_ms;
+ uint32_t periodic_interval_ms;
MemoryDumpLevelOfDetail level_of_detail;
};
@@ -149,6 +153,9 @@ class BASE_EXPORT TraceConfig {
// formatted.
std::string ToString() const;
+ // Returns a scoped_refptr and wrap TraceConfig in ConvertableToTraceFormat
+ scoped_refptr<ConvertableToTraceFormat> AsConvertableToTraceFormat() const;
+
// Write the string representation of the CategoryFilter part.
std::string ToCategoryFilterString() const;
diff --git a/chromium/base/trace_event/trace_config_unittest.cc b/chromium/base/trace_event/trace_config_unittest.cc
index 84da739b547..bd378803292 100644
--- a/chromium/base/trace_event/trace_config_unittest.cc
+++ b/chromium/base/trace_event/trace_config_unittest.cc
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
+
+#include "base/macros.h"
#include "base/trace_event/memory_dump_manager.h"
#include "base/trace_event/trace_config.h"
#include "base/trace_event/trace_config_memory_test_util.h"
@@ -448,6 +451,12 @@ TEST(TraceConfigTest, IsCategoryGroupEnabled) {
EXPECT_TRUE(tc.IsCategoryGroupEnabled("disabled-by-default-cc"));
EXPECT_TRUE(tc.IsCategoryGroupEnabled("included"));
EXPECT_FALSE(tc.IsCategoryGroupEnabled("other_included"));
+
+ // Excluding categories won't enable disabled-by-default ones with the
+ // excluded category is also present in the group.
+ tc = TraceConfig("-excluded", "");
+ EXPECT_STREQ("-excluded", tc.ToCategoryFilterString().c_str());
+ EXPECT_FALSE(tc.IsCategoryGroupEnabled("excluded,disabled-by-default-cc"));
}
TEST(TraceConfigTest, IsEmptyOrContainsLeadingOrTrailingWhitespace) {
diff --git a/chromium/base/trace_event/trace_event.gypi b/chromium/base/trace_event/trace_event.gypi
index d7ec3915e3f..6948d7cfe02 100644
--- a/chromium/base/trace_event/trace_event.gypi
+++ b/chromium/base/trace_event/trace_event.gypi
@@ -4,6 +4,21 @@
{
'variables': {
'trace_event_sources' : [
+ 'trace_event/common/trace_event_common.h',
+ 'trace_event/heap_profiler_allocation_context.cc',
+ 'trace_event/heap_profiler_allocation_context.h',
+ 'trace_event/heap_profiler_allocation_context_tracker.cc',
+ 'trace_event/heap_profiler_allocation_context_tracker.h',
+ 'trace_event/heap_profiler_allocation_register.cc',
+ 'trace_event/heap_profiler_allocation_register_posix.cc',
+ 'trace_event/heap_profiler_allocation_register_win.cc',
+ 'trace_event/heap_profiler_allocation_register.h',
+ 'trace_event/heap_profiler_heap_dump_writer.cc',
+ 'trace_event/heap_profiler_heap_dump_writer.h',
+ 'trace_event/heap_profiler_stack_frame_deduplicator.cc',
+ 'trace_event/heap_profiler_stack_frame_deduplicator.h',
+ 'trace_event/heap_profiler_type_name_deduplicator.cc',
+ 'trace_event/heap_profiler_type_name_deduplicator.h',
'trace_event/java_heap_dump_provider_android.cc',
'trace_event/java_heap_dump_provider_android.h',
'trace_event/memory_allocator_dump.cc',
@@ -17,13 +32,10 @@
'trace_event/memory_dump_request_args.h',
'trace_event/memory_dump_session_state.cc',
'trace_event/memory_dump_session_state.h',
- 'trace_event/memory_profiler_allocation_context.cc',
- 'trace_event/memory_profiler_allocation_context.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',
@@ -37,54 +49,65 @@
'trace_event/trace_event_android.cc',
'trace_event/trace_event_argument.cc',
'trace_event/trace_event_argument.h',
- 'trace_event/trace_event_common.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_memory.cc',
- 'trace_event/trace_event_memory.h',
'trace_event/trace_event_memory_overhead.cc',
'trace_event/trace_event_memory_overhead.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/trace_log.cc',
'trace_event/trace_log.h',
'trace_event/trace_log_constants.cc',
'trace_event/trace_sampling_thread.cc',
'trace_event/trace_sampling_thread.h',
+ 'trace_event/tracing_agent.cc',
+ 'trace_event/tracing_agent.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/heap_profiler_allocation_context_tracker_unittest.cc',
+ 'trace_event/heap_profiler_allocation_register_unittest.cc',
+ 'trace_event/heap_profiler_heap_dump_writer_unittest.cc',
+ 'trace_event/heap_profiler_stack_frame_deduplicator_unittest.cc',
+ 'trace_event/heap_profiler_type_name_deduplicator_unittest.cc',
'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/memory_profiler_allocation_context_unittest.cc',
'trace_event/process_memory_dump_unittest.cc',
- 'trace_event/process_memory_maps_dump_provider_unittest.cc',
'trace_event/process_memory_totals_dump_provider_unittest.cc',
'trace_event/trace_config_memory_test_util.h',
'trace_event/trace_config_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',
],
+ 'conditions': [
+ ['OS == "linux" or OS=="android" or OS=="mac"', {
+ 'trace_event_sources': [
+ 'trace_event/malloc_dump_provider.cc',
+ 'trace_event/malloc_dump_provider.h',
+ ],
+ }],
+ ['OS == "linux" or OS == "android"', {
+ 'trace_event_sources': [
+ 'trace_event/process_memory_maps_dump_provider.cc',
+ ],
+ 'trace_event_test_sources' : [
+ 'trace_event/process_memory_maps_dump_provider_unittest.cc',
+ ],
+ }],
+ ['OS == "android"', {
+ 'trace_event_test_sources' : [
+ 'trace_event/trace_event_android_unittest.cc',
+ ],
+ }],
+ ],
},
}
diff --git a/chromium/base/trace_event/trace_event.h b/chromium/base/trace_event/trace_event.h
index c3b20fc58d0..cb3f36a589c 100644
--- a/chromium/base/trace_event/trace_event.h
+++ b/chromium/base/trace_event/trace_event.h
@@ -9,12 +9,15 @@
// trace_event_common.h collect and store trace events. Anything not
// implementation-specific should go in trace_macros_common.h instead of here.
+#include <stddef.h>
+#include <stdint.h>
+
#include <string>
#include "base/atomicops.h"
+#include "base/macros.h"
#include "base/time/time.h"
-#include "base/trace_event/trace_event_common.h"
-#include "base/trace_event/trace_event_memory.h"
+#include "base/trace_event/common/trace_event_common.h"
#include "base/trace_event/trace_event_system_stats_monitor.h"
#include "base/trace_event/trace_log.h"
#include "build/build_config.h"
@@ -24,8 +27,8 @@
#define TRACE_STR_COPY(str) \
trace_event_internal::TraceStringWithCopy(str)
-// By default, uint64 ID argument values are not mangled with the Process ID in
-// TRACE_EVENT_ASYNC macros. Use this macro to force Process ID mangling.
+// By default, uint64_t ID argument values are not mangled with the Process ID
+// in TRACE_EVENT_ASYNC macros. Use this macro to force Process ID mangling.
#define TRACE_ID_MANGLE(id) \
trace_event_internal::TraceID::ForceMangle(id)
@@ -109,12 +112,31 @@
// Add a trace event to the platform tracing system.
// base::trace_event::TraceEventHandle
-// TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_CONTEXT_ID(
+// TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_BIND_ID(
+// char phase,
+// const unsigned char* category_group_enabled,
+// const char* name,
+// unsigned long long id,
+// unsigned long long bind_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,
+// unsigned int flags)
+#define TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_BIND_ID \
+ base::trace_event::TraceLog::GetInstance()->AddTraceEventWithBindId
+
+// Add a trace event to the platform tracing system overriding the pid.
+// The resulting event will have tid = pid == (process_id passed here).
+// base::trace_event::TraceEventHandle
+// TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_PROCESS_ID(
// char phase,
// const unsigned char* category_group_enabled,
// const char* name,
// unsigned long long id,
-// unsigned long long context_id,
+// int process_id,
// int num_args,
// const char** arg_names,
// const unsigned char* arg_types,
@@ -122,8 +144,8 @@
// const scoped_refptr<ConvertableToTraceFormat>*
// convertable_values,
// unsigned int flags)
-#define TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_CONTEXT_ID \
- base::trace_event::TraceLog::GetInstance()->AddTraceEventWithContextId
+#define TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_PROCESS_ID \
+ base::trace_event::TraceLog::GetInstance()->AddTraceEventWithProcessId
// Add a trace event to the platform tracing system.
// base::trace_event::TraceEventHandle
@@ -132,9 +154,8 @@
// const unsigned char* category_group_enabled,
// const char* name,
// unsigned long long id,
-// unsigned long long context_id,
// int thread_id,
-// const TraceTicks& timestamp,
+// const TimeTicks& timestamp,
// int num_args,
// const char** arg_names,
// const unsigned char* arg_types,
@@ -154,6 +175,15 @@
#define TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION \
base::trace_event::TraceLog::GetInstance()->UpdateTraceEventDuration
+// Adds a metadata event to the trace log. The |AppendValueAsTraceFormat| method
+// on the convertable value will be called at flush time.
+// TRACE_EVENT_API_ADD_METADATA_EVENT(
+// const char* event_name,
+// const char* arg_name,
+// scoped_refptr<ConvertableToTraceFormat> arg_value)
+#define TRACE_EVENT_API_ADD_METADATA_EVENT \
+ trace_event_internal::AddMetadataEvent
+
// Defines atomic operations used internally by the tracing system.
#define TRACE_EVENT_API_ATOMIC_WORD base::subtle::AtomicWord
#define TRACE_EVENT_API_ATOMIC_LOAD(var) base::subtle::NoBarrier_Load(&(var))
@@ -273,23 +303,38 @@ TRACE_EVENT_API_CLASS_EXPORT extern \
// Implementation detail: internal macro to create static category and add
// event if the category is enabled.
-#define INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP(phase, \
- category_group, name, id, thread_id, timestamp, flags, ...) \
- do { \
- INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
- if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
- unsigned int trace_event_flags = flags | TRACE_EVENT_FLAG_HAS_ID; \
- trace_event_internal::TraceID trace_event_trace_id( \
- id, &trace_event_flags); \
- trace_event_internal::AddTraceEventWithThreadIdAndTimestamp( \
- phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), \
- name, trace_event_trace_id.data(), trace_event_internal::kNoId, \
- thread_id, base::TraceTicks::FromInternalValue(timestamp), \
- trace_event_flags | TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP, \
- trace_event_internal::kNoId, ##__VA_ARGS__); \
- } \
- } while (0)
+#define INTERNAL_TRACE_EVENT_ADD_WITH_TIMESTAMP(phase, category_group, name, \
+ timestamp, flags, ...) \
+ do { \
+ INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
+ if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
+ trace_event_internal::AddTraceEventWithThreadIdAndTimestamp( \
+ phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, \
+ trace_event_internal::kNoId, TRACE_EVENT_API_CURRENT_THREAD_ID, \
+ base::TimeTicks::FromInternalValue(timestamp), \
+ flags | TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP, \
+ trace_event_internal::kNoId, ##__VA_ARGS__); \
+ } \
+ } while (0)
+// Implementation detail: internal macro to create static category and add
+// event if the category is enabled.
+#define INTERNAL_TRACE_EVENT_ADD_WITH_ID_TID_AND_TIMESTAMP( \
+ phase, category_group, name, id, thread_id, timestamp, flags, ...) \
+ do { \
+ INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group); \
+ if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
+ unsigned int trace_event_flags = flags | TRACE_EVENT_FLAG_HAS_ID; \
+ trace_event_internal::TraceID trace_event_trace_id(id, \
+ &trace_event_flags); \
+ trace_event_internal::AddTraceEventWithThreadIdAndTimestamp( \
+ phase, INTERNAL_TRACE_EVENT_UID(category_group_enabled), name, \
+ trace_event_trace_id.data(), thread_id, \
+ base::TimeTicks::FromInternalValue(timestamp), \
+ trace_event_flags | TRACE_EVENT_FLAG_EXPLICIT_TIMESTAMP, \
+ trace_event_internal::kNoId, ##__VA_ARGS__); \
+ } \
+ } while (0)
namespace trace_event_internal {
@@ -488,13 +533,6 @@ static inline void SetTraceValue(const base::ThreadTicks arg,
*value = arg.ToInternalValue();
}
-static inline void SetTraceValue(const base::TraceTicks arg,
- unsigned char* type,
- unsigned long long* value) {
- *type = TRACE_VALUE_TYPE_INT;
- *value = arg.ToInternalValue();
-}
-
// These AddTraceEvent and AddTraceEventWithThreadIdAndTimestamp template
// functions are defined here instead of in the macro, because the arg_values
// could be temporary objects, such as std::string. In order to store
@@ -507,9 +545,8 @@ AddTraceEventWithThreadIdAndTimestamp(
const unsigned char* category_group_enabled,
const char* name,
unsigned long long id,
- unsigned long long context_id,
int thread_id,
- const base::TraceTicks& timestamp,
+ const base::TimeTicks& timestamp,
unsigned int flags,
unsigned long long bind_id,
const char* arg1_name,
@@ -518,8 +555,8 @@ AddTraceEventWithThreadIdAndTimestamp(
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(
- phase, category_group_enabled, name, id, context_id, bind_id, thread_id,
- timestamp, num_args, &arg1_name, arg_types, NULL, &arg1_val, flags);
+ phase, category_group_enabled, name, id, bind_id, thread_id, timestamp,
+ num_args, &arg1_name, arg_types, NULL, &arg1_val, flags);
}
template<class ARG1_TYPE>
@@ -529,9 +566,8 @@ AddTraceEventWithThreadIdAndTimestamp(
const unsigned char* category_group_enabled,
const char* name,
unsigned long long id,
- unsigned long long context_id,
int thread_id,
- const base::TraceTicks& timestamp,
+ const base::TimeTicks& timestamp,
unsigned int flags,
unsigned long long bind_id,
const char* arg1_name,
@@ -552,9 +588,8 @@ AddTraceEventWithThreadIdAndTimestamp(
convertable_values[1] = arg2_val;
return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
- phase, category_group_enabled, name, id, context_id, bind_id, thread_id,
- timestamp, num_args, arg_names, arg_types, arg_values,
- convertable_values, flags);
+ phase, category_group_enabled, name, id, bind_id, thread_id, timestamp,
+ num_args, arg_names, arg_types, arg_values, convertable_values, flags);
}
template<class ARG2_TYPE>
@@ -564,9 +599,8 @@ AddTraceEventWithThreadIdAndTimestamp(
const unsigned char* category_group_enabled,
const char* name,
unsigned long long id,
- unsigned long long context_id,
int thread_id,
- const base::TraceTicks& timestamp,
+ const base::TimeTicks& timestamp,
unsigned int flags,
unsigned long long bind_id,
const char* arg1_name,
@@ -587,9 +621,8 @@ AddTraceEventWithThreadIdAndTimestamp(
convertable_values[0] = arg1_val;
return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
- phase, category_group_enabled, name, id, context_id, bind_id, thread_id,
- timestamp, num_args, arg_names, arg_types, arg_values,
- convertable_values, flags);
+ phase, category_group_enabled, name, id, bind_id, thread_id, timestamp,
+ num_args, arg_names, arg_types, arg_values, convertable_values, flags);
}
static inline base::trace_event::TraceEventHandle
@@ -598,9 +631,8 @@ AddTraceEventWithThreadIdAndTimestamp(
const unsigned char* category_group_enabled,
const char* name,
unsigned long long id,
- unsigned long long context_id,
int thread_id,
- const base::TraceTicks& timestamp,
+ const base::TimeTicks& timestamp,
unsigned int flags,
unsigned long long bind_id,
const char* arg1_name,
@@ -616,9 +648,8 @@ AddTraceEventWithThreadIdAndTimestamp(
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, context_id, bind_id, thread_id,
- timestamp, num_args, arg_names, arg_types, NULL, convertable_values,
- flags);
+ phase, category_group_enabled, name, id, bind_id, thread_id, timestamp,
+ num_args, arg_names, arg_types, NULL, convertable_values, flags);
}
static inline base::trace_event::TraceEventHandle
@@ -627,14 +658,13 @@ AddTraceEventWithThreadIdAndTimestamp(
const unsigned char* category_group_enabled,
const char* name,
unsigned long long id,
- unsigned long long context_id,
int thread_id,
- const base::TraceTicks& timestamp,
+ const base::TimeTicks& timestamp,
unsigned int flags,
unsigned long long bind_id) {
return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
- phase, category_group_enabled, name, id, context_id, bind_id, thread_id,
- timestamp, kZeroNumArgs, NULL, NULL, NULL, NULL, flags);
+ phase, category_group_enabled, name, id, bind_id, thread_id, timestamp,
+ kZeroNumArgs, NULL, NULL, NULL, NULL, flags);
}
static inline base::trace_event::TraceEventHandle AddTraceEvent(
@@ -645,10 +675,9 @@ static inline base::trace_event::TraceEventHandle AddTraceEvent(
unsigned int flags,
unsigned long long bind_id) {
const int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
- const base::TraceTicks now = base::TraceTicks::Now();
- return AddTraceEventWithThreadIdAndTimestamp(phase, category_group_enabled,
- name, id, kNoId, thread_id, now,
- flags, bind_id);
+ const base::TimeTicks now = base::TimeTicks::Now();
+ return AddTraceEventWithThreadIdAndTimestamp(
+ phase, category_group_enabled, name, id, thread_id, now, flags, bind_id);
}
template<class ARG1_TYPE>
@@ -658,9 +687,8 @@ AddTraceEventWithThreadIdAndTimestamp(
const unsigned char* category_group_enabled,
const char* name,
unsigned long long id,
- unsigned long long context_id,
int thread_id,
- const base::TraceTicks& timestamp,
+ const base::TimeTicks& timestamp,
unsigned int flags,
unsigned long long bind_id,
const char* arg1_name,
@@ -670,8 +698,8 @@ AddTraceEventWithThreadIdAndTimestamp(
unsigned long long arg_values[1];
SetTraceValue(arg1_val, &arg_types[0], &arg_values[0]);
return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
- phase, category_group_enabled, name, id, context_id, bind_id, thread_id,
- timestamp, num_args, &arg1_name, arg_types, arg_values, NULL, flags);
+ phase, category_group_enabled, name, id, bind_id, thread_id, timestamp,
+ num_args, &arg1_name, arg_types, arg_values, NULL, flags);
}
template<class ARG1_TYPE>
@@ -685,11 +713,10 @@ static inline base::trace_event::TraceEventHandle AddTraceEvent(
const char* arg1_name,
const ARG1_TYPE& arg1_val) {
int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
- base::TraceTicks now = base::TraceTicks::Now();
+ base::TimeTicks now = base::TimeTicks::Now();
return AddTraceEventWithThreadIdAndTimestamp(phase, category_group_enabled,
- name, id, kNoId, thread_id, now,
- flags, bind_id,
- arg1_name, arg1_val);
+ name, id, thread_id, now, flags,
+ bind_id, arg1_name, arg1_val);
}
template<class ARG1_TYPE, class ARG2_TYPE>
@@ -699,9 +726,8 @@ AddTraceEventWithThreadIdAndTimestamp(
const unsigned char* category_group_enabled,
const char* name,
unsigned long long id,
- unsigned long long context_id,
int thread_id,
- const base::TraceTicks& timestamp,
+ const base::TimeTicks& timestamp,
unsigned int flags,
unsigned long long bind_id,
const char* arg1_name,
@@ -715,8 +741,8 @@ AddTraceEventWithThreadIdAndTimestamp(
SetTraceValue(arg1_val, &arg_types[0], &arg_values[0]);
SetTraceValue(arg2_val, &arg_types[1], &arg_values[1]);
return TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
- phase, category_group_enabled, name, id, context_id, bind_id, thread_id,
- timestamp, num_args, arg_names, arg_types, arg_values, NULL, flags);
+ phase, category_group_enabled, name, id, bind_id, thread_id, timestamp,
+ num_args, arg_names, arg_types, arg_values, NULL, flags);
}
template<class ARG1_TYPE, class ARG2_TYPE>
@@ -732,12 +758,41 @@ static inline base::trace_event::TraceEventHandle AddTraceEvent(
const char* arg2_name,
const ARG2_TYPE& arg2_val) {
int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
- base::TraceTicks now = base::TraceTicks::Now();
- return AddTraceEventWithThreadIdAndTimestamp(phase, category_group_enabled,
- name, id, kNoId, thread_id, now,
- flags, bind_id,
- arg1_name, arg1_val,
- arg2_name, arg2_val);
+ base::TimeTicks now = base::TimeTicks::Now();
+ return AddTraceEventWithThreadIdAndTimestamp(
+ phase, category_group_enabled, name, id, thread_id, now, flags, bind_id,
+ arg1_name, arg1_val, arg2_name, arg2_val);
+}
+
+static inline void AddMetadataEvent(
+ const char* event_name,
+ const char* arg_name,
+ scoped_refptr<base::trace_event::ConvertableToTraceFormat> arg_value) {
+ const char* arg_names[1] = {arg_name};
+ scoped_refptr<base::trace_event::ConvertableToTraceFormat>
+ convertable_values[1] = {arg_value};
+ unsigned char arg_types[1] = {TRACE_VALUE_TYPE_CONVERTABLE};
+ base::trace_event::TraceLog::GetInstance()->AddMetadataEvent(
+ event_name,
+ 1, // num_args
+ arg_names, arg_types,
+ nullptr, // arg_values
+ convertable_values, TRACE_EVENT_FLAG_NONE);
+}
+
+template <class ARG1_TYPE>
+static void AddMetadataEvent(const char* event_name,
+ const char* arg_name,
+ const ARG1_TYPE& arg_val) {
+ const int num_args = 1;
+ const char* arg_names[1] = {arg_name};
+ unsigned char arg_types[1];
+ unsigned long long arg_values[1];
+ SetTraceValue(arg_val, &arg_types[0], &arg_values[0]);
+
+ base::trace_event::TraceLog::GetInstance()->AddMetadataEvent(
+ event_name, num_args, arg_names, arg_types, arg_values, nullptr,
+ TRACE_EVENT_FLAG_NONE);
}
// Used by TRACE_EVENTx macros. Do not use directly.
diff --git a/chromium/base/trace_event/trace_event_android.cc b/chromium/base/trace_event/trace_event_android.cc
index 7815107b76e..83cac1c921c 100644
--- a/chromium/base/trace_event/trace_event_android.cc
+++ b/chromium/base/trace_event/trace_event_android.cc
@@ -5,9 +5,12 @@
#include "base/trace_event/trace_event_impl.h"
#include <fcntl.h>
+#include <stddef.h>
+#include <stdint.h>
#include "base/format_macros.h"
#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
#include "base/strings/stringprintf.h"
#include "base/synchronization/waitable_event.h"
#include "base/trace_event/trace_event.h"
@@ -20,6 +23,21 @@ namespace {
int g_atrace_fd = -1;
const char kATraceMarkerFile[] = "/sys/kernel/debug/tracing/trace_marker";
+void WriteToATrace(int fd, const char* buffer, size_t size) {
+ size_t total_written = 0;
+ while (total_written < size) {
+ ssize_t written = HANDLE_EINTR(write(
+ fd, buffer + total_written, size - total_written));
+ if (written <= 0)
+ break;
+ total_written += written;
+ }
+ if (total_written < size) {
+ PLOG(WARNING) << "Failed to write buffer '" << std::string(buffer, size)
+ << "' to " << kATraceMarkerFile;
+ }
+}
+
void WriteEvent(
char phase,
const char* category_group,
@@ -32,7 +50,7 @@ void WriteEvent(
unsigned int flags) {
std::string out = StringPrintf("%c|%d|%s", phase, getpid(), name);
if (flags & TRACE_EVENT_FLAG_HAS_ID)
- StringAppendF(&out, "-%" PRIx64, static_cast<uint64>(id));
+ StringAppendF(&out, "-%" PRIx64, static_cast<uint64_t>(id));
out += '|';
for (int i = 0; i < kTraceMaxNumArgs && arg_names[i];
@@ -57,7 +75,7 @@ void WriteEvent(
out += '|';
out += category_group;
- write(g_atrace_fd, out.c_str(), out.size());
+ WriteToATrace(g_atrace_fd, out.c_str(), out.size());
}
void NoOpOutputCallback(WaitableEvent* complete_event,
@@ -90,7 +108,7 @@ void TraceLog::StartATrace() {
if (g_atrace_fd != -1)
return;
- g_atrace_fd = open(kATraceMarkerFile, O_WRONLY);
+ g_atrace_fd = HANDLE_EINTR(open(kATraceMarkerFile, O_WRONLY));
if (g_atrace_fd == -1) {
PLOG(WARNING) << "Couldn't open " << kATraceMarkerFile;
return;
@@ -152,7 +170,7 @@ void TraceEvent::SendToATrace() {
WriteEvent('B', category_group, name_, id_,
arg_names_, arg_types_, arg_values_, convertable_values_,
flags_);
- write(g_atrace_fd, "E", 1);
+ WriteToATrace(g_atrace_fd, "E", 1);
break;
case TRACE_EVENT_PHASE_COUNTER:
@@ -161,10 +179,10 @@ void TraceEvent::SendToATrace() {
std::string out = base::StringPrintf(
"C|%d|%s-%s", getpid(), name_, arg_names_[i]);
if (flags_ & TRACE_EVENT_FLAG_HAS_ID)
- StringAppendF(&out, "-%" PRIx64, static_cast<uint64>(id_));
+ StringAppendF(&out, "-%" PRIx64, static_cast<uint64_t>(id_));
StringAppendF(&out, "|%d|%s",
static_cast<int>(arg_values_[i].as_int), category_group);
- write(g_atrace_fd, out.c_str(), out.size());
+ WriteToATrace(g_atrace_fd, out.c_str(), out.size());
}
break;
@@ -175,7 +193,7 @@ void TraceEvent::SendToATrace() {
}
void TraceLog::AddClockSyncMetadataEvent() {
- int atrace_fd = open(kATraceMarkerFile, O_WRONLY | O_APPEND);
+ int atrace_fd = HANDLE_EINTR(open(kATraceMarkerFile, O_WRONLY | O_APPEND));
if (atrace_fd == -1) {
PLOG(WARNING) << "Couldn't open " << kATraceMarkerFile;
return;
@@ -185,11 +203,10 @@ void TraceLog::AddClockSyncMetadataEvent() {
// debugfs that takes the written data and pushes it onto the trace
// buffer. So, to establish clock sync, we write our monotonic clock into that
// trace buffer.
- double now_in_seconds = (TraceTicks::Now() - TraceTicks()).InSecondsF();
+ double now_in_seconds = (TimeTicks::Now() - TimeTicks()).InSecondsF();
std::string marker = StringPrintf(
"trace_event_clock_sync: parent_ts=%f\n", now_in_seconds);
- if (write(atrace_fd, marker.c_str(), marker.size()) == -1)
- PLOG(WARNING) << "Couldn't write to " << kATraceMarkerFile;
+ WriteToATrace(atrace_fd, marker.c_str(), marker.size());
close(atrace_fd);
}
diff --git a/chromium/base/trace_event/trace_event_android_unittest.cc b/chromium/base/trace_event/trace_event_android_unittest.cc
new file mode 100644
index 00000000000..58bd77ed93f
--- /dev/null
+++ b/chromium/base/trace_event/trace_event_android_unittest.cc
@@ -0,0 +1,22 @@
+// 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/trace_event/trace_event.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+TEST(TraceEventAndroidTest, WriteToATrace) {
+ // Just a smoke test to ensure no crash.
+ TraceLog* trace_log = TraceLog::GetInstance();
+ trace_log->StartATrace();
+ TRACE_EVENT0("test", "test-event");
+ trace_log->StopATrace();
+ trace_log->AddClockSyncMetadataEvent();
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/chromium/base/trace_event/trace_event_argument.cc b/chromium/base/trace_event/trace_event_argument.cc
index 81b6ce039f5..6d787c80dad 100644
--- a/chromium/base/trace_event/trace_event_argument.cc
+++ b/chromium/base/trace_event/trace_event_argument.cc
@@ -4,6 +4,10 @@
#include "base/trace_event/trace_event_argument.h"
+#include <stdint.h>
+
+#include <utility>
+
#include "base/bits.h"
#include "base/json/json_writer.h"
#include "base/trace_event/trace_event_memory_overhead.h"
@@ -39,10 +43,10 @@ const bool kStackTypeArray = true;
inline void WriteKeyNameAsRawPtr(Pickle& pickle, const char* ptr) {
pickle.WriteBytes(&kTypeCStr, 1);
- pickle.WriteUInt64(static_cast<uint64>(reinterpret_cast<uintptr_t>(ptr)));
+ pickle.WriteUInt64(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(ptr)));
}
-inline void WriteKeyNameAsStdString(Pickle& pickle, const std::string& str) {
+inline void WriteKeyNameWithCopy(Pickle& pickle, base::StringPiece str) {
pickle.WriteBytes(&kTypeString, 1);
pickle.WriteString(str);
}
@@ -52,7 +56,7 @@ std::string ReadKeyName(PickleIterator& pickle_iterator) {
bool res = pickle_iterator.ReadBytes(&type, 1);
std::string key_name;
if (res && *type == kTypeCStr) {
- uint64 ptr_value = 0;
+ uint64_t ptr_value = 0;
res = pickle_iterator.ReadUInt64(&ptr_value);
key_name = reinterpret_cast<const char*>(static_cast<uintptr_t>(ptr_value));
} else if (res && *type == kTypeString) {
@@ -85,11 +89,11 @@ void TracedValue::SetInteger(const char* name, int value) {
WriteKeyNameAsRawPtr(pickle_, name);
}
-void TracedValue::SetIntegerWithCopiedName(const std::string& name, int value) {
+void TracedValue::SetIntegerWithCopiedName(base::StringPiece name, int value) {
DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
pickle_.WriteBytes(&kTypeInt, 1);
pickle_.WriteInt(value);
- WriteKeyNameAsStdString(pickle_, name);
+ WriteKeyNameWithCopy(pickle_, name);
}
void TracedValue::SetDouble(const char* name, double value) {
@@ -99,12 +103,12 @@ void TracedValue::SetDouble(const char* name, double value) {
WriteKeyNameAsRawPtr(pickle_, name);
}
-void TracedValue::SetDoubleWithCopiedName(const std::string& name,
+void TracedValue::SetDoubleWithCopiedName(base::StringPiece name,
double value) {
DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
pickle_.WriteBytes(&kTypeDouble, 1);
pickle_.WriteDouble(value);
- WriteKeyNameAsStdString(pickle_, name);
+ WriteKeyNameWithCopy(pickle_, name);
}
void TracedValue::SetBoolean(const char* name, bool value) {
@@ -114,27 +118,27 @@ void TracedValue::SetBoolean(const char* name, bool value) {
WriteKeyNameAsRawPtr(pickle_, name);
}
-void TracedValue::SetBooleanWithCopiedName(const std::string& name,
+void TracedValue::SetBooleanWithCopiedName(base::StringPiece name,
bool value) {
DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
pickle_.WriteBytes(&kTypeBool, 1);
pickle_.WriteBool(value);
- WriteKeyNameAsStdString(pickle_, name);
+ WriteKeyNameWithCopy(pickle_, name);
}
-void TracedValue::SetString(const char* name, const std::string& value) {
+void TracedValue::SetString(const char* name, base::StringPiece value) {
DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
pickle_.WriteBytes(&kTypeString, 1);
pickle_.WriteString(value);
WriteKeyNameAsRawPtr(pickle_, name);
}
-void TracedValue::SetStringWithCopiedName(const std::string& name,
- const std::string& value) {
+void TracedValue::SetStringWithCopiedName(base::StringPiece name,
+ base::StringPiece value) {
DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
pickle_.WriteBytes(&kTypeString, 1);
pickle_.WriteString(value);
- WriteKeyNameAsStdString(pickle_, name);
+ WriteKeyNameWithCopy(pickle_, name);
}
void TracedValue::SetValue(const char* name, const TracedValue& value) {
@@ -145,7 +149,7 @@ void TracedValue::SetValue(const char* name, const TracedValue& value) {
EndDictionary();
}
-void TracedValue::SetValueWithCopiedName(const std::string& name,
+void TracedValue::SetValueWithCopiedName(base::StringPiece name,
const TracedValue& value) {
DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
BeginDictionaryWithCopiedName(name);
@@ -161,11 +165,11 @@ void TracedValue::BeginDictionary(const char* name) {
WriteKeyNameAsRawPtr(pickle_, name);
}
-void TracedValue::BeginDictionaryWithCopiedName(const std::string& name) {
+void TracedValue::BeginDictionaryWithCopiedName(base::StringPiece name) {
DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
DEBUG_PUSH_CONTAINER(kStackTypeDict);
pickle_.WriteBytes(&kTypeStartDict, 1);
- WriteKeyNameAsStdString(pickle_, name);
+ WriteKeyNameWithCopy(pickle_, name);
}
void TracedValue::BeginArray(const char* name) {
@@ -175,11 +179,11 @@ void TracedValue::BeginArray(const char* name) {
WriteKeyNameAsRawPtr(pickle_, name);
}
-void TracedValue::BeginArrayWithCopiedName(const std::string& name) {
+void TracedValue::BeginArrayWithCopiedName(base::StringPiece name) {
DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
DEBUG_PUSH_CONTAINER(kStackTypeArray);
pickle_.WriteBytes(&kTypeStartArray, 1);
- WriteKeyNameAsStdString(pickle_, name);
+ WriteKeyNameWithCopy(pickle_, name);
}
void TracedValue::EndDictionary() {
@@ -206,7 +210,7 @@ void TracedValue::AppendBoolean(bool value) {
pickle_.WriteBool(value);
}
-void TracedValue::AppendString(const std::string& value) {
+void TracedValue::AppendString(base::StringPiece value) {
DCHECK_CURRENT_CONTAINER_IS(kStackTypeArray);
pickle_.WriteBytes(&kTypeString, 1);
pickle_.WriteString(value);
@@ -234,7 +238,7 @@ void TracedValue::SetValue(const char* name, scoped_ptr<base::Value> value) {
SetBaseValueWithCopiedName(name, *value);
}
-void TracedValue::SetBaseValueWithCopiedName(const std::string& name,
+void TracedValue::SetBaseValueWithCopiedName(base::StringPiece name,
const base::Value& value) {
DCHECK_CURRENT_CONTAINER_IS(kStackTypeDict);
switch (value.GetType()) {
@@ -439,7 +443,7 @@ scoped_ptr<base::Value> TracedValue::ToBaseValue() const {
}
}
DCHECK(stack.empty());
- return root.Pass();
+ return std::move(root);
}
void TracedValue::AppendAsTraceFormat(std::string* out) const {
diff --git a/chromium/base/trace_event/trace_event_argument.h b/chromium/base/trace_event/trace_event_argument.h
index aab58bc5ba7..a127b0d66d5 100644
--- a/chromium/base/trace_event/trace_event_argument.h
+++ b/chromium/base/trace_event/trace_event_argument.h
@@ -5,12 +5,16 @@
#ifndef BASE_TRACE_EVENT_TRACE_EVENT_ARGUMENT_H_
#define BASE_TRACE_EVENT_TRACE_EVENT_ARGUMENT_H_
+#include <stddef.h>
+
#include <string>
#include <vector>
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/pickle.h"
-#include "base/trace_event/trace_event.h"
+#include "base/strings/string_piece.h"
+#include "base/trace_event/trace_event_impl.h"
namespace base {
@@ -30,26 +34,26 @@ class BASE_EXPORT TracedValue : public ConvertableToTraceFormat {
void SetInteger(const char* name, int value);
void SetDouble(const char* name, double value);
void SetBoolean(const char* name, bool value);
- void SetString(const char* name, const std::string& value);
+ void SetString(const char* name, base::StringPiece value);
void SetValue(const char* name, const TracedValue& value);
void BeginDictionary(const char* name);
void BeginArray(const char* name);
// These, instead, can be safely passed a temporary string.
- void SetIntegerWithCopiedName(const std::string& name, int value);
- void SetDoubleWithCopiedName(const std::string& name, double value);
- void SetBooleanWithCopiedName(const std::string& name, bool value);
- void SetStringWithCopiedName(const std::string& name,
- const std::string& value);
- void SetValueWithCopiedName(const std::string& name,
+ void SetIntegerWithCopiedName(base::StringPiece name, int value);
+ void SetDoubleWithCopiedName(base::StringPiece name, double value);
+ void SetBooleanWithCopiedName(base::StringPiece name, bool value);
+ void SetStringWithCopiedName(base::StringPiece name,
+ base::StringPiece value);
+ void SetValueWithCopiedName(base::StringPiece name,
const TracedValue& value);
- void BeginDictionaryWithCopiedName(const std::string& name);
- void BeginArrayWithCopiedName(const std::string& name);
+ void BeginDictionaryWithCopiedName(base::StringPiece name);
+ void BeginArrayWithCopiedName(base::StringPiece name);
void AppendInteger(int);
void AppendDouble(double);
void AppendBoolean(bool);
- void AppendString(const std::string&);
+ void AppendString(base::StringPiece);
void BeginArray();
void BeginDictionary();
@@ -63,7 +67,7 @@ class BASE_EXPORT TracedValue : public ConvertableToTraceFormat {
// TODO(primiano): migrate the (three) existing clients to the cheaper
// SetValue(TracedValue) API. crbug.com/495628.
void SetValue(const char* name, scoped_ptr<base::Value> value);
- void SetBaseValueWithCopiedName(const std::string& name,
+ void SetBaseValueWithCopiedName(base::StringPiece name,
const base::Value& value);
void AppendBaseValue(const base::Value& value);
diff --git a/chromium/base/trace_event/trace_event_argument_unittest.cc b/chromium/base/trace_event/trace_event_argument_unittest.cc
index c1233ac3a3c..82436ba1994 100644
--- a/chromium/base/trace_event/trace_event_argument_unittest.cc
+++ b/chromium/base/trace_event/trace_event_argument_unittest.cc
@@ -3,6 +3,11 @@
// found in the LICENSE file.
#include "base/trace_event/trace_event_argument.h"
+
+#include <stddef.h>
+
+#include <utility>
+
#include "base/values.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -106,11 +111,11 @@ TEST(TraceEventArgumentTest, PassBaseValue) {
list_value->AppendBoolean(false);
list_value->AppendInteger(1);
list_value->AppendString("in_list");
- list_value->Append(dict_value.Pass());
+ list_value->Append(std::move(dict_value));
scoped_refptr<TracedValue> value = new TracedValue();
value->BeginDictionary("outer_dict");
- value->SetValue("inner_list", list_value.Pass());
+ value->SetValue("inner_list", std::move(list_value));
value->EndDictionary();
dict_value.reset();
diff --git a/chromium/base/trace_event/trace_event_etw_export_win.cc b/chromium/base/trace_event/trace_event_etw_export_win.cc
index 1e05e68adfb..c7de890756b 100644
--- a/chromium/base/trace_event/trace_event_etw_export_win.cc
+++ b/chromium/base/trace_event/trace_event_etw_export_win.cc
@@ -4,6 +4,8 @@
#include "base/trace_event/trace_event_etw_export_win.h"
+#include <stddef.h>
+
#include "base/command_line.h"
#include "base/logging.h"
#include "base/memory/singleton.h"
@@ -85,12 +87,13 @@ const char* const kFilteredEventGroupNames[] = {
"v8", // 0x400
"disabled-by-default-cc.debug", // 0x800
"disabled-by-default-cc.debug.picture", // 0x1000
- "disabled-by-default-toplevel.flow"}; // 0x2000
+ "disabled-by-default-toplevel.flow", // 0x2000
+ "startup"}; // 0x4000
const char kOtherEventsGroupName[] = "__OTHER_EVENTS"; // 0x2000000000000000
const char kDisabledOtherEventsGroupName[] =
"__DISABLED_OTHER_EVENTS"; // 0x4000000000000000
-const uint64 kOtherEventsKeywordBit = 1ULL << 61;
-const uint64 kDisabledOtherEventsKeywordBit = 1ULL << 62;
+const uint64_t kOtherEventsKeywordBit = 1ULL << 61;
+const uint64_t kDisabledOtherEventsKeywordBit = 1ULL << 62;
const size_t kNumberOfCategories = ARRAYSIZE(kFilteredEventGroupNames) + 2U;
} // namespace
@@ -176,7 +179,7 @@ TraceEventETWExport::TraceEventETWExport()
// modifications will be made by the background thread and only affect the
// values of the keys (no key addition/deletion). Therefore, the map does not
// require a lock for access.
- for (int i = 0; i < ARRAYSIZE(kFilteredEventGroupNames); i++)
+ for (size_t i = 0; i < ARRAYSIZE(kFilteredEventGroupNames); i++)
categories_status_[kFilteredEventGroupNames[i]] = false;
categories_status_[kOtherEventsGroupName] = false;
categories_status_[kDisabledOtherEventsGroupName] = false;
@@ -335,20 +338,12 @@ void TraceEventETWExport::AddEvent(
}
// 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) {
+void TraceEventETWExport::AddCompleteEndEvent(const char* name) {
auto* instance = GetInstance();
if (!instance || !instance->etw_export_enabled_ || !EventEnabledChromeEvent())
return;
- EventWriteChromeEvent(name, phase, arg_name_1, arg_value_1, arg_name_2,
- arg_value_2, arg_name_3, arg_value_3);
+ EventWriteChromeEvent(name, "Complete End", "", "", "", "", "", "");
}
// static
@@ -383,7 +378,7 @@ bool TraceEventETWExport::UpdateEnabledCategories() {
// recording tools) using the ETW infrastructure. This value will be set in
// all Chrome processes that have registered their ETW provider.
etw_match_any_keyword_ = CHROME_Context.MatchAnyKeyword;
- for (int i = 0; i < ARRAYSIZE(kFilteredEventGroupNames); i++) {
+ for (size_t i = 0; i < ARRAYSIZE(kFilteredEventGroupNames); i++) {
if (etw_match_any_keyword_ & (1ULL << i)) {
categories_status_[kFilteredEventGroupNames[i]] = true;
} else {
diff --git a/chromium/base/trace_event/trace_event_etw_export_win.h b/chromium/base/trace_event/trace_event_etw_export_win.h
index 7a1c02965d5..9201622a9c6 100644
--- a/chromium/base/trace_event/trace_event_etw_export_win.h
+++ b/chromium/base/trace_event/trace_event_etw_export_win.h
@@ -6,9 +6,12 @@
#ifndef BASE_TRACE_EVENT_TRACE_EVENT_ETW_EXPORT_WIN_H_
#define BASE_TRACE_EVENT_TRACE_EVENT_ETW_EXPORT_WIN_H_
+#include <stdint.h>
+
#include <map>
#include "base/base_export.h"
+#include "base/macros.h"
#include "base/strings/string_piece.h"
#include "base/trace_event/trace_event_impl.h"
@@ -49,17 +52,8 @@ class BASE_EXPORT TraceEventETWExport {
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,
- const char* 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);
+ // Exports an ETW event that marks the end of a complete event.
+ static void AddCompleteEndEvent(const char* name);
// Returns true if any category in the group is enabled.
static bool IsCategoryGroupEnabled(const char* category_group_name);
@@ -89,7 +83,7 @@ class BASE_EXPORT TraceEventETWExport {
std::map<StringPiece, bool> categories_status_;
// Local copy of the ETW keyword.
- uint64 etw_match_any_keyword_;
+ uint64_t etw_match_any_keyword_;
// Background thread that monitors changes to the ETW keyword and updates
// the enabled categories when a change occurs.
diff --git a/chromium/base/trace_event/trace_event_impl.cc b/chromium/base/trace_event/trace_event_impl.cc
index e78ee61b121..24d6568f90d 100644
--- a/chromium/base/trace_event/trace_event_impl.cc
+++ b/chromium/base/trace_event/trace_event_impl.cc
@@ -4,8 +4,11 @@
#include "base/trace_event/trace_event_impl.h"
+#include <stddef.h>
+
#include "base/format_macros.h"
#include "base/json/string_escape.h"
+#include "base/process/process_handle.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
@@ -42,8 +45,8 @@ TraceEvent::TraceEvent()
category_group_enabled_(NULL),
name_(NULL),
thread_id_(0),
- phase_(TRACE_EVENT_PHASE_BEGIN),
- flags_(0) {
+ flags_(0),
+ phase_(TRACE_EVENT_PHASE_BEGIN) {
for (int i = 0; i < kTraceMaxNumArgs; ++i)
arg_names_[i] = NULL;
memset(arg_values_, 0, sizeof(arg_values_));
@@ -57,10 +60,12 @@ void TraceEvent::CopyFrom(const TraceEvent& other) {
thread_timestamp_ = other.thread_timestamp_;
duration_ = other.duration_;
id_ = other.id_;
- context_id_ = other.context_id_;
category_group_enabled_ = other.category_group_enabled_;
name_ = other.name_;
- thread_id_ = other.thread_id_;
+ if (other.flags_ & TRACE_EVENT_FLAG_HAS_PROCESS_ID)
+ process_id_ = other.process_id_;
+ else
+ thread_id_ = other.thread_id_;
phase_ = other.phase_;
flags_ = other.flags_;
parameter_copy_storage_ = other.parameter_copy_storage_;
@@ -75,13 +80,12 @@ void TraceEvent::CopyFrom(const TraceEvent& other) {
void TraceEvent::Initialize(
int thread_id,
- TraceTicks timestamp,
+ TimeTicks timestamp,
ThreadTicks thread_timestamp,
char phase,
const unsigned char* category_group_enabled,
const char* name,
unsigned long long id,
- unsigned long long context_id,
unsigned long long bind_id,
int num_args,
const char** arg_names,
@@ -93,7 +97,6 @@ void TraceEvent::Initialize(
thread_timestamp_ = thread_timestamp;
duration_ = TimeDelta::FromInternalValue(-1);
id_ = id;
- context_id_ = context_id;
category_group_enabled_ = category_group_enabled;
name_ = name;
thread_id_ = thread_id;
@@ -173,11 +176,15 @@ void TraceEvent::Reset() {
convertable_values_[i] = NULL;
}
-void TraceEvent::UpdateDuration(const TraceTicks& now,
+void TraceEvent::UpdateDuration(const TimeTicks& now,
const ThreadTicks& thread_now) {
DCHECK_EQ(duration_.ToInternalValue(), -1);
duration_ = now - timestamp_;
- thread_duration_ = thread_now - thread_timestamp_;
+
+ // |thread_timestamp_| can be empty if the thread ticks clock wasn't
+ // initialized when it was recorded.
+ if (thread_timestamp_ != ThreadTicks())
+ thread_duration_ = thread_now - thread_timestamp_;
}
void TraceEvent::EstimateTraceMemoryOverhead(
@@ -205,10 +212,10 @@ void TraceEvent::AppendValueAsJSON(unsigned char type,
*out += value.as_bool ? "true" : "false";
break;
case TRACE_VALUE_TYPE_UINT:
- StringAppendF(out, "%" PRIu64, static_cast<uint64>(value.as_uint));
+ StringAppendF(out, "%" PRIu64, static_cast<uint64_t>(value.as_uint));
break;
case TRACE_VALUE_TYPE_INT:
- StringAppendF(out, "%" PRId64, static_cast<int64>(value.as_int));
+ StringAppendF(out, "%" PRId64, static_cast<int64_t>(value.as_int));
break;
case TRACE_VALUE_TYPE_DOUBLE: {
// FIXME: base/json/json_writer.cc is using the same code,
@@ -248,9 +255,9 @@ void TraceEvent::AppendValueAsJSON(unsigned char type,
case TRACE_VALUE_TYPE_POINTER:
// JSON only supports double and int numbers.
// So as not to lose bits from a 64-bit pointer, output as a hex string.
- StringAppendF(out, "\"0x%" PRIx64 "\"", static_cast<uint64>(
- reinterpret_cast<intptr_t>(
- value.as_pointer)));
+ StringAppendF(
+ out, "\"0x%" PRIx64 "\"",
+ static_cast<uint64_t>(reinterpret_cast<intptr_t>(value.as_pointer)));
break;
case TRACE_VALUE_TYPE_STRING:
case TRACE_VALUE_TYPE_COPY_STRING:
@@ -265,8 +272,17 @@ void TraceEvent::AppendValueAsJSON(unsigned char type,
void TraceEvent::AppendAsJSON(
std::string* out,
const ArgumentFilterPredicate& argument_filter_predicate) const {
- int64 time_int64 = timestamp_.ToInternalValue();
- int process_id = TraceLog::GetInstance()->process_id();
+ int64_t time_int64 = timestamp_.ToInternalValue();
+ int process_id;
+ int thread_id;
+ if ((flags_ & TRACE_EVENT_FLAG_HAS_PROCESS_ID) &&
+ process_id_ != kNullProcessId) {
+ process_id = process_id_;
+ thread_id = -1;
+ } else {
+ process_id = TraceLog::GetInstance()->process_id();
+ thread_id = thread_id_;
+ }
const char* category_group_name =
TraceLog::GetCategoryGroupName(category_group_enabled_);
@@ -275,12 +291,18 @@ void TraceEvent::AppendAsJSON(
StringAppendF(out, "{\"pid\":%i,\"tid\":%i,\"ts\":%" PRId64
","
"\"ph\":\"%c\",\"cat\":\"%s\",\"name\":\"%s\",\"args\":",
- process_id, thread_id_, time_int64, phase_, category_group_name,
+ process_id, thread_id, time_int64, phase_, category_group_name,
name_);
// Output argument names and values, stop at first NULL argument name.
- bool strip_args = arg_names_[0] && !argument_filter_predicate.is_null() &&
- !argument_filter_predicate.Run(category_group_name, name_);
+ // TODO(oysteine): The dual predicates here is a bit ugly; if the filtering
+ // capabilities need to grow even more precise we should rethink this
+ // approach
+ ArgumentNameFilterPredicate argument_name_filter_predicate;
+ bool strip_args =
+ arg_names_[0] && !argument_filter_predicate.is_null() &&
+ !argument_filter_predicate.Run(category_group_name, name_,
+ &argument_name_filter_predicate);
if (strip_args) {
*out += "\"__stripped__\"";
@@ -294,21 +316,26 @@ void TraceEvent::AppendAsJSON(
*out += arg_names_[i];
*out += "\":";
- if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE)
- convertable_values_[i]->AppendAsTraceFormat(out);
- else
- AppendValueAsJSON(arg_types_[i], arg_values_[i], out);
+ if (argument_name_filter_predicate.is_null() ||
+ argument_name_filter_predicate.Run(arg_names_[i])) {
+ if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE)
+ convertable_values_[i]->AppendAsTraceFormat(out);
+ else
+ AppendValueAsJSON(arg_types_[i], arg_values_[i], out);
+ } else {
+ *out += "\"__stripped__\"";
+ }
}
*out += "}";
}
if (phase_ == TRACE_EVENT_PHASE_COMPLETE) {
- int64 duration = duration_.ToInternalValue();
+ int64_t duration = duration_.ToInternalValue();
if (duration != -1)
StringAppendF(out, ",\"dur\":%" PRId64, duration);
if (!thread_timestamp_.is_null()) {
- int64 thread_duration = thread_duration_.ToInternalValue();
+ int64_t thread_duration = thread_duration_.ToInternalValue();
if (thread_duration != -1)
StringAppendF(out, ",\"tdur\":%" PRId64, thread_duration);
}
@@ -316,7 +343,7 @@ void TraceEvent::AppendAsJSON(
// Output tts if thread_timestamp is valid.
if (!thread_timestamp_.is_null()) {
- int64 thread_time_int64 = thread_timestamp_.ToInternalValue();
+ int64_t thread_time_int64 = thread_timestamp_.ToInternalValue();
StringAppendF(out, ",\"tts\":%" PRId64, thread_time_int64);
}
@@ -328,7 +355,7 @@ void TraceEvent::AppendAsJSON(
// 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)
- StringAppendF(out, ",\"id\":\"0x%" PRIx64 "\"", static_cast<uint64>(id_));
+ StringAppendF(out, ",\"id\":\"0x%" PRIx64 "\"", static_cast<uint64_t>(id_));
if (flags_ & TRACE_EVENT_FLAG_BIND_TO_ENCLOSING)
StringAppendF(out, ",\"bp\":\"e\"");
@@ -336,18 +363,13 @@ void TraceEvent::AppendAsJSON(
if ((flags_ & TRACE_EVENT_FLAG_FLOW_OUT) ||
(flags_ & TRACE_EVENT_FLAG_FLOW_IN)) {
StringAppendF(out, ",\"bind_id\":\"0x%" PRIx64 "\"",
- static_cast<uint64>(bind_id_));
+ static_cast<uint64_t>(bind_id_));
}
if (flags_ & TRACE_EVENT_FLAG_FLOW_IN)
StringAppendF(out, ",\"flow_in\":true");
if (flags_ & TRACE_EVENT_FLAG_FLOW_OUT)
StringAppendF(out, ",\"flow_out\":true");
- // Similar to id_, print the context_id as hex if present.
- if (flags_ & TRACE_EVENT_FLAG_HAS_CONTEXT_ID)
- StringAppendF(out, ",\"cid\":\"0x%" PRIx64 "\"",
- static_cast<uint64>(context_id_));
-
// Instant events also output their scope.
if (phase_ == TRACE_EVENT_PHASE_INSTANT) {
char scope = '?';
diff --git a/chromium/base/trace_event/trace_event_impl.h b/chromium/base/trace_event/trace_event_impl.h
index f26e13f14b0..36461e2b52f 100644
--- a/chromium/base/trace_event/trace_event_impl.h
+++ b/chromium/base/trace_event/trace_event_impl.h
@@ -6,6 +6,8 @@
#ifndef BASE_TRACE_EVENT_TRACE_EVENT_IMPL_H_
#define BASE_TRACE_EVENT_TRACE_EVENT_IMPL_H_
+#include <stdint.h>
+
#include <stack>
#include <string>
#include <vector>
@@ -14,6 +16,7 @@
#include "base/base_export.h"
#include "base/callback.h"
#include "base/containers/hash_tables.h"
+#include "base/macros.h"
#include "base/memory/ref_counted_memory.h"
#include "base/observer_list.h"
#include "base/single_thread_task_runner.h"
@@ -23,6 +26,7 @@
#include "base/threading/thread.h"
#include "base/threading/thread_local.h"
#include "base/trace_event/trace_event_memory_overhead.h"
+#include "build/build_config.h"
namespace base {
@@ -31,8 +35,12 @@ class MessageLoop;
namespace trace_event {
+typedef base::Callback<bool(const char* arg_name)> ArgumentNameFilterPredicate;
+
typedef base::Callback<bool(const char* category_group_name,
- const char* event_name)> ArgumentFilterPredicate;
+ const char* event_name,
+ ArgumentNameFilterPredicate*)>
+ ArgumentFilterPredicate;
// For any argument of type TRACE_VALUE_TYPE_CONVERTABLE the provided
// class must implement this interface.
@@ -63,7 +71,7 @@ class BASE_EXPORT ConvertableToTraceFormat
const int kTraceMaxNumArgs = 2;
struct TraceEventHandle {
- uint32 chunk_seq;
+ uint32_t chunk_seq;
// These numbers of bits must be kept consistent with
// TraceBufferChunk::kMaxTrunkIndex and
// TraceBufferChunk::kTraceBufferChunkSize (in trace_buffer.h).
@@ -91,13 +99,12 @@ class BASE_EXPORT TraceEvent {
void Initialize(
int thread_id,
- TraceTicks timestamp,
+ TimeTicks timestamp,
ThreadTicks thread_timestamp,
char phase,
const unsigned char* category_group_enabled,
const char* name,
unsigned long long id,
- unsigned long long context_id,
unsigned long long bind_id,
int num_args,
const char** arg_names,
@@ -108,7 +115,7 @@ class BASE_EXPORT TraceEvent {
void Reset();
- void UpdateDuration(const TraceTicks& now, const ThreadTicks& thread_now);
+ void UpdateDuration(const TimeTicks& now, const ThreadTicks& thread_now);
void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead);
@@ -122,14 +129,13 @@ class BASE_EXPORT TraceEvent {
TraceValue value,
std::string* out);
- TraceTicks timestamp() const { return timestamp_; }
+ TimeTicks timestamp() const { return timestamp_; }
ThreadTicks thread_timestamp() const { return thread_timestamp_; }
char phase() const { return phase_; }
int thread_id() const { return thread_id_; }
TimeDelta duration() const { return duration_; }
TimeDelta thread_duration() const { return thread_duration_; }
unsigned long long id() const { return id_; }
- unsigned long long context_id() const { return context_id_; }
unsigned int flags() const { return flags_; }
// Exposed for unittesting:
@@ -150,25 +156,29 @@ class BASE_EXPORT TraceEvent {
private:
// Note: these are ordered by size (largest first) for optimal packing.
- TraceTicks timestamp_;
+ TimeTicks timestamp_;
ThreadTicks thread_timestamp_;
TimeDelta duration_;
TimeDelta thread_duration_;
// id_ can be used to store phase-specific data.
unsigned long long id_;
- // context_id_ is used to store context information.
- unsigned long long context_id_;
TraceValue arg_values_[kTraceMaxNumArgs];
const char* arg_names_[kTraceMaxNumArgs];
scoped_refptr<ConvertableToTraceFormat> convertable_values_[kTraceMaxNumArgs];
const unsigned char* category_group_enabled_;
const char* name_;
scoped_refptr<base::RefCountedString> parameter_copy_storage_;
- int thread_id_;
- char phase_;
+ // Depending on TRACE_EVENT_FLAG_HAS_PROCESS_ID the event will have either:
+ // tid: thread_id_, pid: current_process_id (default case).
+ // tid: -1, pid: process_id_ (when flags_ & TRACE_EVENT_FLAG_HAS_PROCESS_ID).
+ union {
+ int thread_id_;
+ int process_id_;
+ };
unsigned int flags_;
unsigned long long bind_id_;
unsigned char arg_types_[kTraceMaxNumArgs];
+ char phase_;
DISALLOW_COPY_AND_ASSIGN(TraceEvent);
};
diff --git a/chromium/base/trace_event/trace_event_memory.cc b/chromium/base/trace_event/trace_event_memory.cc
deleted file mode 100644
index 73c8536cac2..00000000000
--- a/chromium/base/trace_event/trace_event_memory.cc
+++ /dev/null
@@ -1,436 +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/trace_event/trace_event_memory.h"
-
-#include "base/debug/leak_annotations.h"
-#include "base/lazy_instance.h"
-#include "base/location.h"
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/single_thread_task_runner.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_split.h"
-#include "base/strings/string_util.h"
-#include "base/threading/thread_local_storage.h"
-#include "base/trace_event/trace_event.h"
-
-namespace base {
-namespace trace_event {
-
-namespace {
-
-// Maximum number of nested TRACE_EVENT scopes to record. Must be less than
-// or equal to HeapProfileTable::kMaxStackDepth / 2 because we record two
-// entries on the pseudo-stack per scope.
-const size_t kMaxScopeDepth = 16;
-
-/////////////////////////////////////////////////////////////////////////////
-// Holds a memory dump until the tracing system needs to serialize it.
-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::trace_event::ConvertableToTraceFormat overrides:
- void AppendAsTraceFormat(std::string* out) const override {
- AppendHeapProfileAsTraceFormat(dump_, out);
- }
-
- private:
- ~MemoryDumpHolder() override { free(dump_); }
-
- char* dump_;
-
- DISALLOW_COPY_AND_ASSIGN(MemoryDumpHolder);
-};
-
-/////////////////////////////////////////////////////////////////////////////
-// Records a stack of TRACE_MEMORY events. One per thread is required.
-struct TraceMemoryStack {
- TraceMemoryStack() : scope_depth(0) {
- memset(scope_data, 0, kMaxScopeDepth * sizeof(scope_data[0]));
- }
-
- // Depth of the currently nested TRACE_EVENT scopes. Allowed to be greater
- // than kMaxScopeDepth so we can match scope pushes and pops even if we don't
- // have enough space to store the EventData.
- size_t scope_depth;
-
- // Stack of categories and names.
- ScopedTraceMemory::ScopeData scope_data[kMaxScopeDepth];
-};
-
-// Pointer to a TraceMemoryStack per thread.
-base::ThreadLocalStorage::StaticSlot tls_trace_memory_stack = TLS_INITIALIZER;
-
-// Clean up memory pointed to by our thread-local storage.
-void DeleteStackOnThreadCleanup(void* value) {
- TraceMemoryStack* stack = static_cast<TraceMemoryStack*>(value);
- delete stack;
-}
-
-// Initializes the thread-local TraceMemoryStack pointer.
-void InitThreadLocalStorage() {
- if (tls_trace_memory_stack.initialized())
- return;
- // Initialize the thread-local storage key.
- tls_trace_memory_stack.Initialize(&DeleteStackOnThreadCleanup);
-}
-
-// Clean up thread-local-storage in the main thread.
-void CleanupThreadLocalStorage() {
- if (!tls_trace_memory_stack.initialized())
- return;
- TraceMemoryStack* stack =
- static_cast<TraceMemoryStack*>(tls_trace_memory_stack.Get());
- delete stack;
- tls_trace_memory_stack.Set(NULL);
- // Intentionally do not release the thread-local-storage key here, that is,
- // do not call tls_trace_memory_stack.Free(). Other threads have lazily
- // created pointers in thread-local-storage via GetTraceMemoryStack() below.
- // Those threads need to run the DeleteStack() destructor function when they
- // exit. If we release the key the destructor will not be called and those
- // threads will not clean up their memory.
-}
-
-// Returns the thread-local trace memory stack for the current thread, creating
-// one if needed. Returns NULL if the thread-local storage key isn't
-// initialized, which indicates that heap profiling isn't running.
-TraceMemoryStack* GetTraceMemoryStack() {
- TraceMemoryStack* stack =
- static_cast<TraceMemoryStack*>(tls_trace_memory_stack.Get());
- // Lazily initialize TraceMemoryStack objects for new threads.
- if (!stack) {
- stack = new TraceMemoryStack;
- tls_trace_memory_stack.Set(stack);
- }
- return stack;
-}
-
-// Returns a "pseudo-stack" of pointers to trace event categories and names.
-// Because tcmalloc stores one pointer per stack frame this converts N nested
-// trace events into N * 2 pseudo-stack entries. Thus this macro invocation:
-// TRACE_EVENT0("category1", "name1");
-// TRACE_EVENT0("category2", "name2");
-// becomes this pseudo-stack:
-// stack_out[0] = "category1"
-// stack_out[1] = "name1"
-// stack_out[2] = "category2"
-// stack_out[3] = "name2"
-// Returns int instead of size_t to match the signature required by tcmalloc.
-int GetPseudoStack(int skip_count_ignored, void** stack_out) {
- // If the tracing system isn't fully initialized, just skip this allocation.
- // Attempting to initialize will allocate memory, causing this function to
- // be called recursively from inside the allocator.
- if (!tls_trace_memory_stack.initialized() || !tls_trace_memory_stack.Get())
- return 0;
- TraceMemoryStack* stack =
- static_cast<TraceMemoryStack*>(tls_trace_memory_stack.Get());
- // Copy at most kMaxScopeDepth scope entries.
- const size_t count = std::min(stack->scope_depth, kMaxScopeDepth);
- // Notes that memcpy() works for zero bytes.
- memcpy(stack_out,
- stack->scope_data,
- count * sizeof(stack->scope_data[0]));
- // Each item in the trace event stack contains both name and category so tell
- // tcmalloc that we have returned |count| * 2 stack frames.
- return static_cast<int>(count * 2);
-}
-
-} // namespace
-
-//////////////////////////////////////////////////////////////////////////////
-
-TraceMemoryController::TraceMemoryController(
- scoped_refptr<SingleThreadTaskRunner> task_runner,
- HeapProfilerStartFunction heap_profiler_start_function,
- HeapProfilerStopFunction heap_profiler_stop_function,
- GetHeapProfileFunction get_heap_profile_function)
- : 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),
- weak_factory_(this) {
- // Force the "memory" category to show up in the trace viewer.
- TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("memory"), "init");
- // Watch for the tracing system being enabled.
- TraceLog::GetInstance()->AddEnabledStateObserver(this);
-}
-
-TraceMemoryController::~TraceMemoryController() {
- if (dump_timer_.IsRunning())
- StopProfiling();
- TraceLog::GetInstance()->RemoveEnabledStateObserver(this);
-}
-
-// base::trace_event::TraceLog::EnabledStateChangedObserver overrides:
-void TraceMemoryController::OnTraceLogEnabled() {
- // Check to see if tracing is enabled for the memory category.
- bool enabled;
- TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("memory"),
- &enabled);
- if (!enabled)
- return;
- DVLOG(1) << "OnTraceLogEnabled";
- task_runner_->PostTask(FROM_HERE,
- base::Bind(&TraceMemoryController::StartProfiling,
- weak_factory_.GetWeakPtr()));
-}
-
-void TraceMemoryController::OnTraceLogDisabled() {
- // The memory category is always disabled before OnTraceLogDisabled() is
- // called, so we cannot tell if it was enabled before. Always try to turn
- // off profiling.
- DVLOG(1) << "OnTraceLogDisabled";
- task_runner_->PostTask(FROM_HERE,
- base::Bind(&TraceMemoryController::StopProfiling,
- weak_factory_.GetWeakPtr()));
-}
-
-void TraceMemoryController::StartProfiling() {
- // Watch for the tracing framework sending enabling more than once.
- if (dump_timer_.IsRunning())
- return;
- DVLOG(1) << "Starting trace memory";
- InitThreadLocalStorage();
- ScopedTraceMemory::set_enabled(true);
- // Call ::HeapProfilerWithPseudoStackStart().
- heap_profiler_start_function_(&GetPseudoStack);
- const int kDumpIntervalSeconds = 5;
- dump_timer_.Start(FROM_HERE,
- TimeDelta::FromSeconds(kDumpIntervalSeconds),
- base::Bind(&TraceMemoryController::DumpMemoryProfile,
- weak_factory_.GetWeakPtr()));
-}
-
-void TraceMemoryController::DumpMemoryProfile() {
- // Don't trace allocations here in the memory tracing system.
- INTERNAL_TRACE_MEMORY(TRACE_DISABLED_BY_DEFAULT("memory"),
- TRACE_MEMORY_IGNORE);
-
- DVLOG(1) << "DumpMemoryProfile";
- // MemoryDumpHolder takes ownership of this string. See GetHeapProfile() in
- // tcmalloc for details.
- char* dump = get_heap_profile_function_();
- const int kSnapshotId = 1;
- TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
- TRACE_DISABLED_BY_DEFAULT("memory"),
- "memory::Heap",
- kSnapshotId,
- scoped_refptr<ConvertableToTraceFormat>(new MemoryDumpHolder(dump)));
-}
-
-void TraceMemoryController::StopProfiling() {
- // Watch for the tracing framework sending disabled more than once.
- if (!dump_timer_.IsRunning())
- return;
- DVLOG(1) << "Stopping trace memory";
- dump_timer_.Stop();
- ScopedTraceMemory::set_enabled(false);
- CleanupThreadLocalStorage();
- // Call ::HeapProfilerStop().
- heap_profiler_stop_function_();
-}
-
-bool TraceMemoryController::IsTimerRunningForTest() const {
- return dump_timer_.IsRunning();
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-// static
-bool ScopedTraceMemory::enabled_ = false;
-
-void ScopedTraceMemory::Initialize(const char* category, const char* name) {
- DCHECK(enabled_);
- // Get our thread's copy of the stack.
- TraceMemoryStack* trace_memory_stack = GetTraceMemoryStack();
- const size_t index = trace_memory_stack->scope_depth;
- // Don't record data for deeply nested scopes, but continue to increment
- // |stack_depth| so we can match pushes and pops.
- if (index < kMaxScopeDepth) {
- ScopeData& event = trace_memory_stack->scope_data[index];
- event.category = category;
- event.name = name;
- }
- trace_memory_stack->scope_depth++;
-}
-
-void ScopedTraceMemory::Destroy() {
- DCHECK(enabled_);
- // Get our thread's copy of the stack.
- TraceMemoryStack* trace_memory_stack = GetTraceMemoryStack();
- // The tracing system can be turned on with ScopedTraceMemory objects
- // allocated on the stack, so avoid potential underflow as they are destroyed.
- if (trace_memory_stack->scope_depth > 0)
- trace_memory_stack->scope_depth--;
-}
-
-// static
-void ScopedTraceMemory::InitForTest() {
- InitThreadLocalStorage();
- enabled_ = true;
-}
-
-// static
-void ScopedTraceMemory::CleanupForTest() {
- enabled_ = false;
- CleanupThreadLocalStorage();
-}
-
-// static
-int ScopedTraceMemory::GetStackDepthForTest() {
- TraceMemoryStack* stack = GetTraceMemoryStack();
- return static_cast<int>(stack->scope_depth);
-}
-
-// static
-ScopedTraceMemory::ScopeData ScopedTraceMemory::GetScopeDataForTest(
- int stack_index) {
- TraceMemoryStack* stack = GetTraceMemoryStack();
- return stack->scope_data[stack_index];
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-void AppendHeapProfileAsTraceFormat(const char* input, std::string* output) {
- // Heap profile output has a header total line, then a list of stacks with
- // memory totals, like this:
- //
- // heap profile: 357: 55227 [ 14653: 2624014] @ heapprofile
- // 95: 40940 [ 649: 114260] @ 0x7fa7f4b3be13
- // 77: 32546 [ 742: 106234] @
- // 68: 4195 [ 1087: 98009] @ 0x7fa7fa9b9ba0 0x7fa7f4b3be13
- //
- // MAPPED_LIBRARIES:
- // 1be411fc1000-1be4139e4000 rw-p 00000000 00:00 0
- // 1be4139e4000-1be4139e5000 ---p 00000000 00:00 0
- // ...
- //
- // Skip input after MAPPED_LIBRARIES.
- std::string input_string;
- const char* mapped_libraries = strstr(input, "MAPPED_LIBRARIES");
- if (mapped_libraries) {
- input_string.assign(input, mapped_libraries - input);
- } else {
- input_string.assign(input);
- }
-
- std::vector<std::string> lines = base::SplitString(
- input_string, "\n", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
- if (lines.empty()) {
- DLOG(WARNING) << "No lines found";
- return;
- }
-
- // Handle the initial summary line.
- output->append("[");
- AppendHeapProfileTotalsAsTraceFormat(lines[0], output);
-
- // Handle the following stack trace lines.
- for (size_t i = 1; i < lines.size(); i++)
- AppendHeapProfileLineAsTraceFormat(lines[i], output);
- output->append("]\n");
-}
-
-void AppendHeapProfileTotalsAsTraceFormat(const std::string& line,
- std::string* output) {
- // This is what a line looks like:
- // heap profile: 357: 55227 [ 14653: 2624014] @ heapprofile
- //
- // The numbers represent total allocations since profiling was enabled.
- // From the example above:
- // 357 = Outstanding allocations (mallocs - frees)
- // 55227 = Outstanding bytes (malloc bytes - free bytes)
- // 14653 = Total allocations (mallocs)
- // 2624014 = Total bytes (malloc bytes)
- std::vector<std::string> tokens = base::SplitString(
- line, " :[]@", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
- if (tokens.size() < 4) {
- DLOG(WARNING) << "Invalid totals line " << line;
- return;
- }
- DCHECK_EQ(tokens[0], "heap");
- DCHECK_EQ(tokens[1], "profile");
- output->append("{\"current_allocs\": ");
- output->append(tokens[2]);
- output->append(", \"current_bytes\": ");
- output->append(tokens[3]);
- output->append(", \"trace\": \"\"}");
-}
-
-bool AppendHeapProfileLineAsTraceFormat(const std::string& line,
- std::string* output) {
- // This is what a line looks like:
- // 68: 4195 [ 1087: 98009] @ 0x7fa7fa9b9ba0 0x7fa7f4b3be13
- //
- // The numbers represent allocations for a particular stack trace since
- // profiling was enabled. From the example above:
- // 68 = Outstanding allocations (mallocs - frees)
- // 4195 = Outstanding bytes (malloc bytes - free bytes)
- // 1087 = Total allocations (mallocs)
- // 98009 = Total bytes (malloc bytes)
- //
- // 0x7fa7fa9b9ba0 0x7fa7f4b3be13 = Stack trace represented as pointers to
- // static strings from trace event categories
- // and names.
- std::vector<std::string> tokens = base::SplitString(
- line, " :[]@", base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
- // It's valid to have no stack addresses, so only require 4 tokens.
- if (tokens.size() < 4) {
- DLOG(WARNING) << "Invalid line " << line;
- return false;
- }
- // Don't bother with stacks that have no current allocations.
- if (tokens[0] == "0")
- return false;
- output->append(",\n");
- output->append("{\"current_allocs\": ");
- output->append(tokens[0]);
- output->append(", \"current_bytes\": ");
- output->append(tokens[1]);
- output->append(", \"trace\": \"");
-
- // Convert pairs of "stack addresses" into category and name strings.
- const std::string kSingleQuote = "'";
- for (size_t t = 4; t < tokens.size(); t += 2) {
- // Casting strings into pointers is ugly but otherwise tcmalloc would need
- // to gain a special output serializer just for pseudo-stacks.
- const char* trace_category = StringFromHexAddress(tokens[t]);
- DCHECK_LT(t + 1, tokens.size());
- const char* trace_name = StringFromHexAddress(tokens[t + 1]);
-
- // TODO(jamescook): Report the trace category and name separately to the
- // trace viewer and allow it to decide what decorations to apply. For now
- // just hard-code a decoration for posted tasks (toplevel).
- std::string trace_string(trace_name);
- if (!strcmp(trace_category, "toplevel"))
- trace_string.append("->PostTask");
-
- // Some trace name strings have double quotes, convert them to single.
- ReplaceChars(trace_string, "\"", kSingleQuote, &trace_string);
-
- output->append(trace_string);
-
- // Trace viewer expects a trailing space.
- output->append(" ");
- }
- output->append("\"}");
- return true;
-}
-
-const char* StringFromHexAddress(const std::string& hex_address) {
- uint64 address = 0;
- if (!base::HexStringToUInt64(hex_address, &address))
- return "error";
- if (!address)
- return "null";
- // Note that this cast handles 64-bit to 32-bit conversion if necessary.
- return reinterpret_cast<const char*>(address);
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/chromium/base/trace_event/trace_event_memory.h b/chromium/base/trace_event/trace_event_memory.h
deleted file mode 100644
index 7088080de9b..00000000000
--- a/chromium/base/trace_event/trace_event_memory.h
+++ /dev/null
@@ -1,171 +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_TRACE_EVENT_TRACE_EVENT_MEMORY_H_
-#define BASE_TRACE_EVENT_TRACE_EVENT_MEMORY_H_
-
-#include "base/base_export.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_log.h"
-
-// TODO(jamescook): Windows support for memory tracing.
-#if !defined(NO_TCMALLOC) && !defined(OS_NACL) && \
- (defined(OS_LINUX) || defined(OS_ANDROID))
-#define TCMALLOC_TRACE_MEMORY_SUPPORTED 1
-#endif
-
-namespace base {
-
-class SingleThreadTaskRunner;
-
-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
-// way to turn trace-base heap memory profiling on and off.
-class BASE_EXPORT TraceMemoryController
- : public TraceLog::EnabledStateObserver {
- public:
- typedef int (*StackGeneratorFunction)(int skip_count, void** stack);
- typedef void (*HeapProfilerStartFunction)(StackGeneratorFunction callback);
- typedef void (*HeapProfilerStopFunction)();
- typedef char* (*GetHeapProfileFunction)();
-
- // |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<SingleThreadTaskRunner> task_runner,
- HeapProfilerStartFunction heap_profiler_start_function,
- HeapProfilerStopFunction heap_profiler_stop_function,
- GetHeapProfileFunction get_heap_profile_function);
- ~TraceMemoryController() override;
-
- // base::trace_event::TraceLog::EnabledStateChangedObserver overrides:
- void OnTraceLogEnabled() override;
- void OnTraceLogDisabled() override;
-
- // Starts heap memory profiling.
- void StartProfiling();
-
- // Captures a heap profile.
- void DumpMemoryProfile();
-
- // If memory tracing is enabled, dumps a memory profile to the tracing system.
- void StopProfiling();
-
- private:
- FRIEND_TEST_ALL_PREFIXES(TraceMemoryTest, TraceMemoryController);
-
- bool IsTimerRunningForTest() const;
-
- // Ensures the observer starts and stops tracing on the primary thread.
- 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.
- HeapProfilerStartFunction heap_profiler_start_function_;
- HeapProfilerStopFunction heap_profiler_stop_function_;
- GetHeapProfileFunction get_heap_profile_function_;
-
- // Timer to schedule memory profile dumps.
- RepeatingTimer dump_timer_;
-
- WeakPtrFactory<TraceMemoryController> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(TraceMemoryController);
-};
-
-//////////////////////////////////////////////////////////////////////////////
-
-// A scoped context for memory tracing. Pushes the name onto a stack for
-// recording by tcmalloc heap profiling.
-class BASE_EXPORT ScopedTraceMemory {
- public:
- struct ScopeData {
- const char* category;
- const char* name;
- };
-
- // Memory for |category| and |name| must be static, for example, literal
- // strings in a TRACE_EVENT macro.
- ScopedTraceMemory(const char* category, const char* name) {
- if (!enabled_)
- return;
- Initialize(category, name);
- }
- ~ScopedTraceMemory() {
- if (!enabled_)
- return;
- Destroy();
- }
-
- // Enables the storing of trace names on a per-thread stack.
- static void set_enabled(bool enabled) { enabled_ = enabled; }
-
- // Testing interface:
- static void InitForTest();
- static void CleanupForTest();
- static int GetStackDepthForTest();
- static ScopeData GetScopeDataForTest(int stack_index);
-
- private:
- void Initialize(const char* category, const char* name);
- void Destroy();
-
- static bool enabled_;
- DISALLOW_COPY_AND_ASSIGN(ScopedTraceMemory);
-};
-
-//////////////////////////////////////////////////////////////////////////////
-
-// Converts tcmalloc's heap profiler data with pseudo-stacks in |input| to
-// trace event compatible JSON and appends to |output|. Visible for testing.
-BASE_EXPORT void AppendHeapProfileAsTraceFormat(const char* input,
- std::string* output);
-
-// Converts the first |line| of heap profiler data, which contains totals for
-// all allocations in a special format, into trace event compatible JSON and
-// appends to |output|. Visible for testing.
-BASE_EXPORT void AppendHeapProfileTotalsAsTraceFormat(const std::string& line,
- std::string* output);
-
-// Converts a single |line| of heap profiler data into trace event compatible
-// JSON and appends to |output|. Returns true if the line was valid and has a
-// non-zero number of current allocations. Visible for testing.
-BASE_EXPORT bool AppendHeapProfileLineAsTraceFormat(const std::string& line,
- std::string* output);
-
-// Returns a pointer to a string given its hexadecimal address in |hex_address|.
-// Handles both 32-bit and 64-bit addresses. Returns "null" for null pointers
-// and "error" if |address| could not be parsed. Visible for testing.
-BASE_EXPORT const char* StringFromHexAddress(const std::string& hex_address);
-
-} // namespace trace_event
-} // namespace base
-
-// Make local variables with unique names based on the line number. Note that
-// the extra level of redirection is needed.
-#define INTERNAL_TRACE_MEMORY_ID3(line) trace_memory_unique_##line
-#define INTERNAL_TRACE_MEMORY_ID2(line) INTERNAL_TRACE_MEMORY_ID3(line)
-#define INTERNAL_TRACE_MEMORY_ID INTERNAL_TRACE_MEMORY_ID2(__LINE__)
-
-// This is the core macro that adds a scope to each TRACE_EVENT location.
-// It generates a unique local variable name using the macros above.
-#if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED)
-#define INTERNAL_TRACE_MEMORY(category, name) \
- base::trace_event::ScopedTraceMemory INTERNAL_TRACE_MEMORY_ID(category, name);
-#else
-#define INTERNAL_TRACE_MEMORY(category, name)
-#endif // defined(TRACE_MEMORY_SUPPORTED)
-
-// A special trace name that allows us to ignore memory allocations inside
-// the memory dump system itself. The allocations are recorded, but the
-// visualizer skips them. Must match the value in heap.js.
-#define TRACE_MEMORY_IGNORE "trace-memory-ignore"
-
-#endif // BASE_TRACE_EVENT_TRACE_EVENT_MEMORY_H_
diff --git a/chromium/base/trace_event/trace_event_memory_overhead.h b/chromium/base/trace_event/trace_event_memory_overhead.h
index 25853d11d12..a69c93fed20 100644
--- a/chromium/base/trace_event/trace_event_memory_overhead.h
+++ b/chromium/base/trace_event/trace_event_memory_overhead.h
@@ -5,9 +5,12 @@
#ifndef BASE_TRACE_EVENT_TRACE_EVENT_MEMORY_OVERHEAD_H_
#define BASE_TRACE_EVENT_TRACE_EVENT_MEMORY_OVERHEAD_H_
+#include <stddef.h>
+
#include "base/base_export.h"
#include "base/containers/hash_tables.h"
#include "base/containers/small_map.h"
+#include "base/macros.h"
namespace base {
diff --git a/chromium/base/trace_event/trace_event_memory_unittest.cc b/chromium/base/trace_event/trace_event_memory_unittest.cc
deleted file mode 100644
index 781a0544c45..00000000000
--- a/chromium/base/trace_event/trace_event_memory_unittest.cc
+++ /dev/null
@@ -1,236 +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/trace_event/trace_event_memory.h"
-
-#include <sstream>
-#include <string>
-
-#include "base/trace_event/trace_event_impl.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-#if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED)
-#include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h"
-#endif
-
-namespace base {
-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() {}
- ~TraceMemoryTest() override {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(TraceMemoryTest);
-};
-
-//////////////////////////////////////////////////////////////////////////////
-
-#if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED)
-
-TEST_F(TraceMemoryTest, TraceMemoryController) {
- MessageLoop message_loop;
-
- // Start with no observers of the TraceLog.
- EXPECT_EQ(0u, TraceLog::GetInstance()->GetObserverCountForTest());
-
- // Creating a controller adds it to the TraceLog observer list.
- 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()));
-
- // By default the observer isn't dumping memory profiles.
- EXPECT_FALSE(controller->IsTimerRunningForTest());
-
- // Simulate enabling tracing.
- controller->StartProfiling();
- message_loop.RunUntilIdle();
- EXPECT_TRUE(controller->IsTimerRunningForTest());
-
- // Simulate disabling tracing.
- controller->StopProfiling();
- message_loop.RunUntilIdle();
- EXPECT_FALSE(controller->IsTimerRunningForTest());
-
- // Deleting the observer removes it from the TraceLog observer list.
- controller.reset();
- EXPECT_EQ(0u, TraceLog::GetInstance()->GetObserverCountForTest());
-}
-
-TEST_F(TraceMemoryTest, ScopedTraceMemory) {
- ScopedTraceMemory::InitForTest();
-
- // Start with an empty stack.
- EXPECT_EQ(0, ScopedTraceMemory::GetStackDepthForTest());
-
- {
- // Push an item.
- ScopedTraceMemory scope1("cat1", "name1");
- EXPECT_EQ(1, ScopedTraceMemory::GetStackDepthForTest());
- EXPECT_EQ("cat1", ScopedTraceMemory::GetScopeDataForTest(0).category);
- EXPECT_EQ("name1", ScopedTraceMemory::GetScopeDataForTest(0).name);
-
- {
- // One more item.
- ScopedTraceMemory scope2("cat2", "name2");
- EXPECT_EQ(2, ScopedTraceMemory::GetStackDepthForTest());
- EXPECT_EQ("cat2", ScopedTraceMemory::GetScopeDataForTest(1).category);
- EXPECT_EQ("name2", ScopedTraceMemory::GetScopeDataForTest(1).name);
- }
-
- // Ended scope 2.
- EXPECT_EQ(1, ScopedTraceMemory::GetStackDepthForTest());
- }
-
- // Ended scope 1.
- EXPECT_EQ(0, ScopedTraceMemory::GetStackDepthForTest());
-
- ScopedTraceMemory::CleanupForTest();
-}
-
-void TestDeepScopeNesting(int current, int depth) {
- EXPECT_EQ(current, ScopedTraceMemory::GetStackDepthForTest());
- ScopedTraceMemory scope("category", "name");
- if (current < depth)
- TestDeepScopeNesting(current + 1, depth);
- EXPECT_EQ(current + 1, ScopedTraceMemory::GetStackDepthForTest());
-}
-
-TEST_F(TraceMemoryTest, DeepScopeNesting) {
- ScopedTraceMemory::InitForTest();
-
- // Ensure really deep scopes don't crash.
- TestDeepScopeNesting(0, 100);
-
- ScopedTraceMemory::CleanupForTest();
-}
-
-#endif // defined(TRACE_MEMORY_SUPPORTED)
-
-/////////////////////////////////////////////////////////////////////////////
-
-TEST_F(TraceMemoryTest, AppendHeapProfileTotalsAsTraceFormat) {
- // Empty input gives empty output.
- std::string empty_output;
- AppendHeapProfileTotalsAsTraceFormat("", &empty_output);
- EXPECT_EQ("", empty_output);
-
- // Typical case.
- const char input[] =
- "heap profile: 357: 55227 [ 14653: 2624014] @ heapprofile";
- const std::string kExpectedOutput =
- "{\"current_allocs\": 357, \"current_bytes\": 55227, \"trace\": \"\"}";
- std::string output;
- AppendHeapProfileTotalsAsTraceFormat(input, &output);
- EXPECT_EQ(kExpectedOutput, output);
-}
-
-TEST_F(TraceMemoryTest, AppendHeapProfileLineAsTraceFormat) {
- // Empty input gives empty output.
- std::string empty_output;
- EXPECT_FALSE(AppendHeapProfileLineAsTraceFormat("", &empty_output));
- EXPECT_EQ("", empty_output);
-
- // Invalid input returns false.
- std::string junk_output;
- EXPECT_FALSE(AppendHeapProfileLineAsTraceFormat("junk", &junk_output));
-
- // Input with normal category and name entries.
- const char kCategory[] = "category";
- const char kName[] = "name";
- std::ostringstream input;
- input << " 68: 4195 [ 1087: 98009] @ " << &kCategory << " "
- << &kName;
- const std::string kExpectedOutput =
- ",\n"
- "{"
- "\"current_allocs\": 68, "
- "\"current_bytes\": 4195, "
- "\"trace\": \"name \""
- "}";
- std::string output;
- EXPECT_TRUE(
- AppendHeapProfileLineAsTraceFormat(input.str().c_str(), &output));
- EXPECT_EQ(kExpectedOutput, output);
-
- // Input with with the category "toplevel".
- // TODO(jamescook): Eliminate this special case and move the logic to the
- // trace viewer code.
- const char kTaskCategory[] = "toplevel";
- const char kTaskName[] = "TaskName";
- std::ostringstream input2;
- input2 << " 68: 4195 [ 1087: 98009] @ " << &kTaskCategory << " "
- << &kTaskName;
- const std::string kExpectedOutput2 =
- ",\n"
- "{"
- "\"current_allocs\": 68, "
- "\"current_bytes\": 4195, "
- "\"trace\": \"TaskName->PostTask \""
- "}";
- std::string output2;
- EXPECT_TRUE(
- AppendHeapProfileLineAsTraceFormat(input2.str().c_str(), &output2));
- EXPECT_EQ(kExpectedOutput2, output2);
-
- // Zero current allocations is skipped.
- std::ostringstream zero_input;
- zero_input << " 0: 0 [ 1087: 98009] @ " << &kCategory << " "
- << &kName;
- std::string zero_output;
- EXPECT_FALSE(AppendHeapProfileLineAsTraceFormat(zero_input.str().c_str(),
- &zero_output));
- EXPECT_EQ("", zero_output);
-}
-
-TEST_F(TraceMemoryTest, AppendHeapProfileAsTraceFormat) {
- // Empty input gives empty output.
- std::string empty_output;
- AppendHeapProfileAsTraceFormat("", &empty_output);
- EXPECT_EQ("", empty_output);
-
- // Typical case.
- const char input[] =
- "heap profile: 357: 55227 [ 14653: 2624014] @ heapprofile\n"
- " 95: 40940 [ 649: 114260] @\n"
- " 77: 32546 [ 742: 106234] @ 0x0 0x0\n"
- " 0: 0 [ 132: 4236] @ 0x0\n"
- "\n"
- "MAPPED_LIBRARIES:\n"
- "1be411fc1000-1be4139e4000 rw-p 00000000 00:00 0\n"
- "1be4139e4000-1be4139e5000 ---p 00000000 00:00 0\n";
- const std::string kExpectedOutput =
- "[{"
- "\"current_allocs\": 357, "
- "\"current_bytes\": 55227, "
- "\"trace\": \"\"},\n"
- "{\"current_allocs\": 95, "
- "\"current_bytes\": 40940, "
- "\"trace\": \"\"},\n"
- "{\"current_allocs\": 77, "
- "\"current_bytes\": 32546, "
- "\"trace\": \"null \""
- "}]\n";
- std::string output;
- AppendHeapProfileAsTraceFormat(input, &output);
- EXPECT_EQ(kExpectedOutput, output);
-}
-
-TEST_F(TraceMemoryTest, StringFromHexAddress) {
- EXPECT_STREQ("null", StringFromHexAddress("0x0"));
- EXPECT_STREQ("error", StringFromHexAddress("not an address"));
- const char kHello[] = "hello";
- std::ostringstream hex_address;
- hex_address << &kHello;
- EXPECT_STREQ(kHello, StringFromHexAddress(hex_address.str()));
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/chromium/base/trace_event/trace_event_synthetic_delay.cc b/chromium/base/trace_event/trace_event_synthetic_delay.cc
index cd0c364d5bf..cfae7435e9b 100644
--- a/chromium/base/trace_event/trace_event_synthetic_delay.cc
+++ b/chromium/base/trace_event/trace_event_synthetic_delay.cc
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/macros.h"
#include "base/memory/singleton.h"
#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
#include "base/trace_event/trace_event_synthetic_delay.h"
diff --git a/chromium/base/trace_event/trace_event_synthetic_delay.h b/chromium/base/trace_event/trace_event_synthetic_delay.h
index 0df794b46c2..59e2842f71a 100644
--- a/chromium/base/trace_event/trace_event_synthetic_delay.h
+++ b/chromium/base/trace_event/trace_event_synthetic_delay.h
@@ -33,6 +33,7 @@
#define BASE_TRACE_EVENT_TRACE_EVENT_SYNTHETIC_DELAY_H_
#include "base/atomicops.h"
+#include "base/macros.h"
#include "base/synchronization/lock.h"
#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
diff --git a/chromium/base/trace_event/trace_event_synthetic_delay_unittest.cc b/chromium/base/trace_event/trace_event_synthetic_delay_unittest.cc
index 1dc0fc26f5c..97a4580b3bb 100644
--- a/chromium/base/trace_event/trace_event_synthetic_delay_unittest.cc
+++ b/chromium/base/trace_event/trace_event_synthetic_delay_unittest.cc
@@ -4,6 +4,9 @@
#include "base/trace_event/trace_event_synthetic_delay.h"
+#include <stdint.h>
+
+#include "base/macros.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
@@ -39,19 +42,19 @@ class TraceEventSyntheticDelayTest : public testing::Test,
void AdvanceTime(base::TimeDelta delta) { now_ += delta; }
- int64 TestFunction() {
+ int64_t TestFunction() {
base::TimeTicks start = Now();
{ TRACE_EVENT_SYNTHETIC_DELAY("test.Delay"); }
return (Now() - start).InMilliseconds();
}
- int64 AsyncTestFunctionBegin() {
+ int64_t AsyncTestFunctionBegin() {
base::TimeTicks start = Now();
{ TRACE_EVENT_SYNTHETIC_DELAY_BEGIN("test.AsyncDelay"); }
return (Now() - start).InMilliseconds();
}
- int64 AsyncTestFunctionEnd() {
+ int64_t AsyncTestFunctionEnd() {
base::TimeTicks start = Now();
{ TRACE_EVENT_SYNTHETIC_DELAY_END("test.AsyncDelay"); }
return (Now() - start).InMilliseconds();
diff --git a/chromium/base/trace_event/trace_event_system_stats_monitor.cc b/chromium/base/trace_event/trace_event_system_stats_monitor.cc
index c08d9b9477a..057967bfd90 100644
--- a/chromium/base/trace_event/trace_event_system_stats_monitor.cc
+++ b/chromium/base/trace_event/trace_event_system_stats_monitor.cc
@@ -8,6 +8,7 @@
#include "base/json/json_writer.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
diff --git a/chromium/base/trace_event/trace_event_system_stats_monitor.h b/chromium/base/trace_event/trace_event_system_stats_monitor.h
index 0ae1f487a39..14aa5681fe4 100644
--- a/chromium/base/trace_event/trace_event_system_stats_monitor.h
+++ b/chromium/base/trace_event/trace_event_system_stats_monitor.h
@@ -7,6 +7,7 @@
#include "base/base_export.h"
#include "base/gtest_prod_util.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/process/process_metrics.h"
diff --git a/chromium/base/trace_event/trace_event_system_stats_monitor_unittest.cc b/chromium/base/trace_event/trace_event_system_stats_monitor_unittest.cc
index 03dff591cfa..a90e74d1309 100644
--- a/chromium/base/trace_event/trace_event_system_stats_monitor_unittest.cc
+++ b/chromium/base/trace_event/trace_event_system_stats_monitor_unittest.cc
@@ -7,7 +7,9 @@
#include <sstream>
#include <string>
+#include "base/macros.h"
#include "base/trace_event/trace_event_impl.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
diff --git a/chromium/base/trace_event/trace_event_unittest.cc b/chromium/base/trace_event/trace_event_unittest.cc
index 5020eec4ae7..09f2a916c32 100644
--- a/chromium/base/trace_event/trace_event_unittest.cc
+++ b/chromium/base/trace_event/trace_event_unittest.cc
@@ -3,6 +3,9 @@
// found in the LICENSE file.
#include <math.h>
+#include <stddef.h>
+#include <stdint.h>
+
#include <cstdlib>
#include "base/bind.h"
@@ -10,11 +13,13 @@
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/location.h"
+#include "base/macros.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/stl_util.h"
#include "base/strings/pattern.h"
#include "base/strings/stringprintf.h"
#include "base/synchronization/waitable_event.h"
@@ -191,9 +196,8 @@ void TraceEventTestFixture::OnTraceDataCollected(
trace_buffer_.AddFragment(events_str->data());
trace_buffer_.Finish();
- scoped_ptr<Value> root;
- root.reset(base::JSONReader::DeprecatedRead(
- json_output_.json_output, JSON_PARSE_RFC | JSON_DETACHABLE_CHILDREN));
+ scoped_ptr<Value> root = base::JSONReader::Read(
+ json_output_.json_output, JSON_PARSE_RFC | JSON_DETACHABLE_CHILDREN);
if (!root.get()) {
LOG(ERROR) << json_output_.json_output;
@@ -403,11 +407,6 @@ const char kControlCharacters[] = "\001\002\003\n\r";
void TraceWithAllMacroVariants(WaitableEvent* task_complete_event) {
{
- TRACE_EVENT_BEGIN_ETW("TRACE_EVENT_BEGIN_ETW call", 0x1122, "extrastring1");
- TRACE_EVENT_END_ETW("TRACE_EVENT_END_ETW call", 0x3344, "extrastring2");
- TRACE_EVENT_INSTANT_ETW("TRACE_EVENT_INSTANT_ETW call",
- 0x5566, "extrastring3");
-
TRACE_EVENT0("all", "TRACE_EVENT0 call");
TRACE_EVENT1("all", "TRACE_EVENT1 call", "name1", "value1");
TRACE_EVENT2("all", "TRACE_EVENT2 call",
@@ -460,18 +459,16 @@ void TraceWithAllMacroVariants(WaitableEvent* task_complete_event) {
TRACE_EVENT_FLOW_END_BIND_TO_ENCLOSING0("all",
"TRACE_EVENT_FLOW_END_BIND_TO_ENCLOSING0 call", kFlowId);
- TRACE_EVENT_BEGIN_ETW("TRACE_EVENT_BEGIN_ETW0 call", kAsyncId, NULL);
- TRACE_EVENT_BEGIN_ETW("TRACE_EVENT_BEGIN_ETW1 call", kAsyncId, "value");
- TRACE_EVENT_END_ETW("TRACE_EVENT_END_ETW0 call", kAsyncId, NULL);
- TRACE_EVENT_END_ETW("TRACE_EVENT_END_ETW1 call", kAsyncId, "value");
- TRACE_EVENT_INSTANT_ETW("TRACE_EVENT_INSTANT_ETW0 call", kAsyncId, NULL);
- TRACE_EVENT_INSTANT_ETW("TRACE_EVENT_INSTANT_ETW1 call", kAsyncId, "value");
-
TRACE_COUNTER1("all", "TRACE_COUNTER1 call", 31415);
TRACE_COUNTER2("all", "TRACE_COUNTER2 call",
"a", 30000,
"b", 1415);
+ TRACE_COUNTER_WITH_TIMESTAMP1("all", "TRACE_COUNTER_WITH_TIMESTAMP1 call",
+ 42, 31415);
+ TRACE_COUNTER_WITH_TIMESTAMP2("all", "TRACE_COUNTER_WITH_TIMESTAMP2 call",
+ 42, "a", 30000, "b", 1415);
+
TRACE_COUNTER_ID1("all", "TRACE_COUNTER_ID1 call", 0x319009, 31415);
TRACE_COUNTER_ID2("all", "TRACE_COUNTER_ID2 call", 0x319009,
"a", 30000, "b", 1415);
@@ -525,17 +522,6 @@ void ValidateAllTraceMacrosCreatedData(const ListValue& trace_parsed) {
if (item) \
EXPECT_TRUE(IsStringInDict(string, item));
- EXPECT_FIND_("ETW Trace Event");
- EXPECT_FIND_("all");
- EXPECT_FIND_("TRACE_EVENT_BEGIN_ETW call");
- {
- std::string str_val;
- EXPECT_TRUE(item && item->GetString("args.id", &str_val));
- EXPECT_STREQ("0x1122", str_val.c_str());
- }
- EXPECT_SUB_FIND_("extrastring1");
- EXPECT_FIND_("TRACE_EVENT_END_ETW call");
- EXPECT_FIND_("TRACE_EVENT_INSTANT_ETW call");
EXPECT_FIND_("TRACE_EVENT0 call");
{
std::string ph;
@@ -654,37 +640,6 @@ void ValidateAllTraceMacrosCreatedData(const ListValue& trace_parsed) {
EXPECT_SUB_FIND_("id");
EXPECT_SUB_FIND_(kFlowIdStr);
- EXPECT_FIND_("TRACE_EVENT_BEGIN_ETW0 call");
- EXPECT_SUB_FIND_("id");
- EXPECT_SUB_FIND_(kAsyncIdStr);
- EXPECT_SUB_FIND_("extra");
- EXPECT_SUB_FIND_("NULL");
- EXPECT_FIND_("TRACE_EVENT_BEGIN_ETW1 call");
- EXPECT_SUB_FIND_("id");
- EXPECT_SUB_FIND_(kAsyncIdStr);
- EXPECT_SUB_FIND_("extra");
- EXPECT_SUB_FIND_("value");
- EXPECT_FIND_("TRACE_EVENT_END_ETW0 call");
- EXPECT_SUB_FIND_("id");
- EXPECT_SUB_FIND_(kAsyncIdStr);
- EXPECT_SUB_FIND_("extra");
- EXPECT_SUB_FIND_("NULL");
- EXPECT_FIND_("TRACE_EVENT_END_ETW1 call");
- EXPECT_SUB_FIND_("id");
- EXPECT_SUB_FIND_(kAsyncIdStr);
- EXPECT_SUB_FIND_("extra");
- EXPECT_SUB_FIND_("value");
- EXPECT_FIND_("TRACE_EVENT_INSTANT_ETW0 call");
- EXPECT_SUB_FIND_("id");
- EXPECT_SUB_FIND_(kAsyncIdStr);
- EXPECT_SUB_FIND_("extra");
- EXPECT_SUB_FIND_("NULL");
- EXPECT_FIND_("TRACE_EVENT_INSTANT_ETW1 call");
- EXPECT_SUB_FIND_("id");
- EXPECT_SUB_FIND_(kAsyncIdStr);
- EXPECT_SUB_FIND_("extra");
- EXPECT_SUB_FIND_("value");
-
EXPECT_FIND_("TRACE_COUNTER1 call");
{
std::string ph;
@@ -710,6 +665,39 @@ void ValidateAllTraceMacrosCreatedData(const ListValue& trace_parsed) {
EXPECT_EQ(1415, value);
}
+ EXPECT_FIND_("TRACE_COUNTER_WITH_TIMESTAMP1 call");
+ {
+ std::string ph;
+ EXPECT_TRUE((item && item->GetString("ph", &ph)));
+ EXPECT_EQ("C", ph);
+
+ int value;
+ EXPECT_TRUE((item && item->GetInteger("args.value", &value)));
+ EXPECT_EQ(31415, value);
+
+ int ts;
+ EXPECT_TRUE((item && item->GetInteger("ts", &ts)));
+ EXPECT_EQ(42, ts);
+ }
+
+ EXPECT_FIND_("TRACE_COUNTER_WITH_TIMESTAMP2 call");
+ {
+ std::string ph;
+ EXPECT_TRUE((item && item->GetString("ph", &ph)));
+ EXPECT_EQ("C", ph);
+
+ int value;
+ EXPECT_TRUE((item && item->GetInteger("args.a", &value)));
+ EXPECT_EQ(30000, value);
+
+ EXPECT_TRUE((item && item->GetInteger("args.b", &value)));
+ EXPECT_EQ(1415, value);
+
+ int ts;
+ EXPECT_TRUE((item && item->GetInteger("ts", &ts)));
+ EXPECT_EQ(42, ts);
+ }
+
EXPECT_FIND_("TRACE_COUNTER_ID1 call");
{
std::string id;
@@ -1144,6 +1132,63 @@ TEST_F(TraceEventTestFixture, TestTraceFlush) {
}
}
+TEST_F(TraceEventTestFixture, AddMetadataEvent) {
+ int num_calls = 0;
+
+ class Convertable : public ConvertableToTraceFormat {
+ public:
+ explicit Convertable(int* num_calls) : num_calls_(num_calls) {}
+ void AppendAsTraceFormat(std::string* out) const override {
+ (*num_calls_)++;
+ out->append("\"metadata_value\"");
+ }
+
+ private:
+ ~Convertable() override {}
+ int* num_calls_;
+ };
+
+ scoped_refptr<ConvertableToTraceFormat> convertable =
+ new Convertable(&num_calls);
+
+ BeginTrace();
+ TRACE_EVENT_API_ADD_METADATA_EVENT("metadata_event_name", "metadata_arg_name",
+ convertable);
+
+ // |AppendAsTraceFormat| should only be called on flush, not when the event
+ // is added.
+ ASSERT_EQ(0, num_calls);
+ EndTraceAndFlush();
+ ASSERT_EQ(1, num_calls);
+ EXPECT_TRUE(FindNamePhaseKeyValue("metadata_event_name", "M",
+ "metadata_arg_name", "metadata_value"));
+
+ // The metadata event should only be adde to the current trace. In this new
+ // trace, the event should not appear.
+ BeginTrace();
+ EndTraceAndFlush();
+ ASSERT_EQ(1, num_calls);
+
+ // Flushing should cause |AppendAsTraceFormat| to be called, but if the buffer
+ // is left intact, it the flush at the end of the trace should still call it;
+ // the metadata event should not be removed.
+ TraceLog::GetInstance()->SetEnabled(
+ TraceConfig(kRecordAllCategoryFilter,
+ "record-until-full,enable-sampling"),
+ TraceLog::MONITORING_MODE);
+ TRACE_EVENT_API_ADD_METADATA_EVENT("metadata_event_name", "metadata_arg_name",
+ convertable);
+ FlushMonitoring();
+ ASSERT_EQ(2, num_calls);
+
+ // Flushing the trace at this point will case |AppendAsTraceFormat| to be
+ // called twice: once for the event that was added by the monitoring flush,
+ // and once for the end trace flush; the metadata event will be duplicated.
+ // This is consistent with the other metadata events.
+ EndTraceAndFlush();
+ ASSERT_EQ(4, num_calls);
+}
+
// Test that categories work.
TEST_F(TraceEventTestFixture, Categories) {
// Test that categories that are used can be retrieved whether trace was
@@ -1162,24 +1207,15 @@ TEST_F(TraceEventTestFixture, Categories) {
EndTraceAndFlush();
std::vector<std::string> cat_groups;
TraceLog::GetInstance()->GetKnownCategoryGroups(&cat_groups);
- EXPECT_TRUE(std::find(cat_groups.begin(),
- cat_groups.end(), "c1") != cat_groups.end());
- EXPECT_TRUE(std::find(cat_groups.begin(),
- cat_groups.end(), "c2") != cat_groups.end());
- EXPECT_TRUE(std::find(cat_groups.begin(),
- cat_groups.end(), "c3") != cat_groups.end());
- EXPECT_TRUE(std::find(cat_groups.begin(),
- cat_groups.end(), "c4") != cat_groups.end());
- EXPECT_TRUE(std::find(cat_groups.begin(),
- cat_groups.end(), "c5,c6") != cat_groups.end());
- EXPECT_TRUE(std::find(cat_groups.begin(),
- cat_groups.end(), "c7,c8") != cat_groups.end());
- EXPECT_TRUE(std::find(cat_groups.begin(),
- cat_groups.end(),
- "disabled-by-default-c9") != cat_groups.end());
+ EXPECT_TRUE(ContainsValue(cat_groups, "c1"));
+ EXPECT_TRUE(ContainsValue(cat_groups, "c2"));
+ EXPECT_TRUE(ContainsValue(cat_groups, "c3"));
+ EXPECT_TRUE(ContainsValue(cat_groups, "c4"));
+ EXPECT_TRUE(ContainsValue(cat_groups, "c5,c6"));
+ EXPECT_TRUE(ContainsValue(cat_groups, "c7,c8"));
+ EXPECT_TRUE(ContainsValue(cat_groups, "disabled-by-default-c9"));
// Make sure metadata isn't returned.
- EXPECT_TRUE(std::find(cat_groups.begin(),
- cat_groups.end(), "__metadata") == cat_groups.end());
+ EXPECT_FALSE(ContainsValue(cat_groups, "__metadata"));
const std::vector<std::string> empty_categories;
std::vector<std::string> included_categories;
@@ -2242,13 +2278,24 @@ TEST_F(TraceEventTestFixture, PrimitiveArgs) {
namespace {
+bool IsArgNameWhitelisted(const char* arg_name) {
+ return base::MatchPattern(arg_name, "granular_arg_whitelisted");
+}
+
bool IsTraceEventArgsWhitelisted(const char* category_group_name,
- const char* event_name) {
+ const char* event_name,
+ ArgumentNameFilterPredicate* arg_filter) {
if (base::MatchPattern(category_group_name, "toplevel") &&
base::MatchPattern(event_name, "*")) {
return true;
}
+ if (base::MatchPattern(category_group_name, "benchmark") &&
+ base::MatchPattern(event_name, "granularly_whitelisted")) {
+ *arg_filter = base::Bind(&IsArgNameWhitelisted);
+ return true;
+ }
+
return false;
}
@@ -2264,6 +2311,11 @@ TEST_F(TraceEventTestFixture, ArgsWhitelisting) {
TRACE_EVENT1("toplevel", "event1", "int_one", 1);
TRACE_EVENT1("whitewashed", "event2", "int_two", 1);
+
+ TRACE_EVENT2("benchmark", "granularly_whitelisted",
+ "granular_arg_whitelisted", "whitelisted_value",
+ "granular_arg_blacklisted", "blacklisted_value");
+
EndTraceAndFlush();
const DictionaryValue* args_dict = NULL;
@@ -2286,6 +2338,17 @@ TEST_F(TraceEventTestFixture, ArgsWhitelisting) {
std::string args_string;
EXPECT_TRUE(dict->GetString("args", &args_string));
EXPECT_EQ(args_string, "__stripped__");
+
+ dict = FindNamePhase("granularly_whitelisted", "X");
+ ASSERT_TRUE(dict);
+ dict->GetDictionary("args", &args_dict);
+ ASSERT_TRUE(args_dict);
+
+ EXPECT_TRUE(args_dict->GetString("granular_arg_whitelisted", &args_string));
+ EXPECT_EQ(args_string, "whitelisted_value");
+
+ EXPECT_TRUE(args_dict->GetString("granular_arg_blacklisted", &args_string));
+ EXPECT_EQ(args_string, "__stripped__");
}
class TraceEventCallbackTest : public TraceEventTestFixture {
@@ -2333,10 +2396,10 @@ class TraceEventCallbackTest : public TraceEventTestFixture {
std::vector<std::string> collected_events_categories_;
std::vector<std::string> collected_events_names_;
std::vector<unsigned char> collected_events_phases_;
- std::vector<TraceTicks> collected_events_timestamps_;
+ std::vector<TimeTicks> collected_events_timestamps_;
static TraceEventCallbackTest* s_instance;
- static void Callback(TraceTicks timestamp,
+ static void Callback(TimeTicks timestamp,
char phase,
const unsigned char* category_group_enabled,
const char* name,
@@ -2522,9 +2585,9 @@ TEST_F(TraceEventTestFixture, TraceBufferVectorReportFull) {
TraceBuffer::CreateTraceBufferVectorOfSize(100));
do {
TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0(
- "all", "with_timestamp", 0, 0, TraceTicks::Now().ToInternalValue());
+ "all", "with_timestamp", 0, 0, TimeTicks::Now().ToInternalValue());
TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0(
- "all", "with_timestamp", 0, 0, TraceTicks::Now().ToInternalValue());
+ "all", "with_timestamp", 0, 0, TimeTicks::Now().ToInternalValue());
} while (!trace_log->BufferIsFull());
EndTraceAndFlush();
@@ -2566,7 +2629,7 @@ TEST_F(TraceEventTestFixture, TraceBufferRingBufferGetReturnChunk) {
TraceBuffer* buffer = TraceLog::GetInstance()->trace_buffer();
size_t capacity = buffer->Capacity();
size_t num_chunks = capacity / TraceBufferChunk::kTraceBufferChunkSize;
- uint32 last_seq = 0;
+ uint32_t last_seq = 0;
size_t chunk_index;
EXPECT_EQ(0u, buffer->Size());
@@ -2897,7 +2960,7 @@ TEST_F(TraceEventTestFixture, EchoToConsoleTraceEventRecursion) {
TEST_F(TraceEventTestFixture, TimeOffset) {
BeginTrace();
// Let TraceLog timer start from 0.
- TimeDelta time_offset = TraceTicks::Now() - TraceTicks();
+ TimeDelta time_offset = TimeTicks::Now() - TimeTicks();
TraceLog::GetInstance()->SetTimeOffset(time_offset);
{
@@ -2905,15 +2968,15 @@ TEST_F(TraceEventTestFixture, TimeOffset) {
TRACE_EVENT0("all", "duration2");
}
TRACE_EVENT_BEGIN_WITH_ID_TID_AND_TIMESTAMP0(
- "all", "with_timestamp", 0, 0, TraceTicks::Now().ToInternalValue());
+ "all", "with_timestamp", 0, 0, TimeTicks::Now().ToInternalValue());
TRACE_EVENT_END_WITH_ID_TID_AND_TIMESTAMP0(
- "all", "with_timestamp", 0, 0, TraceTicks::Now().ToInternalValue());
+ "all", "with_timestamp", 0, 0, TimeTicks::Now().ToInternalValue());
EndTraceAndFlush();
DropTracedMetadataRecords();
double end_time = static_cast<double>(
- (TraceTicks::Now() - time_offset).ToInternalValue());
+ (TimeTicks::Now() - time_offset).ToInternalValue());
double last_timestamp = 0;
for (size_t i = 0; i < trace_parsed_.GetSize(); ++i) {
const DictionaryValue* item;
diff --git a/chromium/base/trace_event/trace_event_win.cc b/chromium/base/trace_event/trace_event_win.cc
deleted file mode 100644
index fdbd35a0e2f..00000000000
--- a/chromium/base/trace_event/trace_event_win.cc
+++ /dev/null
@@ -1,132 +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/trace_event/trace_event_win.h"
-
-#include "base/logging.h"
-#include "base/memory/singleton.h"
-#include <initguid.h> // NOLINT
-
-namespace base {
-namespace trace_event {
-
-using base::win::EtwEventType;
-using base::win::EtwMofEvent;
-
-// {3DADA31D-19EF-4dc1-B345-037927193422}
-const GUID kChromeTraceProviderName = {
- 0x3dada31d,
- 0x19ef,
- 0x4dc1,
- {0xb3, 0x45, 0x3, 0x79, 0x27, 0x19, 0x34, 0x22}};
-
-// {B967AE67-BB22-49d7-9406-55D91EE1D560}
-const GUID kTraceEventClass32 = {
- 0xb967ae67,
- 0xbb22,
- 0x49d7,
- {0x94, 0x6, 0x55, 0xd9, 0x1e, 0xe1, 0xd5, 0x60}};
-
-// {97BE602D-2930-4ac3-8046-B6763B631DFE}
-const GUID kTraceEventClass64 = {
- 0x97be602d,
- 0x2930,
- 0x4ac3,
- {0x80, 0x46, 0xb6, 0x76, 0x3b, 0x63, 0x1d, 0xfe}};
-
-TraceEventETWProvider::TraceEventETWProvider() :
- EtwTraceProvider(kChromeTraceProviderName) {
- Register();
-}
-
-TraceEventETWProvider* TraceEventETWProvider::GetInstance() {
- return Singleton<TraceEventETWProvider,
- StaticMemorySingletonTraits<TraceEventETWProvider> >::get();
-}
-
-bool TraceEventETWProvider::StartTracing() {
- return true;
-}
-
-void TraceEventETWProvider::TraceEvent(const char* name,
- size_t name_len,
- char type,
- const void* id,
- const char* extra,
- size_t extra_len) {
- // Make sure we don't touch NULL.
- if (name == NULL)
- name = "";
- if (extra == NULL)
- extra = "";
-
- EtwEventType etw_type = 0;
- switch (type) {
- case TRACE_EVENT_PHASE_BEGIN:
- etw_type = kTraceEventTypeBegin;
- break;
- case TRACE_EVENT_PHASE_END:
- etw_type = kTraceEventTypeEnd;
- break;
-
- case TRACE_EVENT_PHASE_INSTANT:
- etw_type = kTraceEventTypeInstant;
- break;
-
- default:
- NOTREACHED() << "Unknown event type";
- etw_type = kTraceEventTypeInstant;
- break;
- }
-
- EtwMofEvent<5> event(kTraceEventClass32,
- etw_type,
- TRACE_LEVEL_INFORMATION);
- event.SetField(0, name_len + 1, name);
- event.SetField(1, sizeof(id), &id);
- event.SetField(2, extra_len + 1, extra);
-
- // These variables are declared here so that they are not out of scope when
- // the event is logged.
- DWORD depth;
- void* backtrace[32];
-
- // See whether we're to capture a backtrace.
- if (enable_flags() & CAPTURE_STACK_TRACE) {
- depth = CaptureStackBackTrace(0,
- arraysize(backtrace),
- backtrace,
- NULL);
- event.SetField(3, sizeof(depth), &depth);
- event.SetField(4, sizeof(backtrace[0]) * depth, backtrace);
- }
-
- // Trace the event.
- Log(event.get());
-}
-
-void TraceEventETWProvider::Trace(const char* name,
- size_t name_len,
- char type,
- const void* id,
- const char* extra,
- size_t extra_len) {
- TraceEventETWProvider* provider = TraceEventETWProvider::GetInstance();
- if (provider && provider->IsTracing()) {
- // Compute the name & extra lengths if not supplied already.
- if (name_len == kUseStrlen)
- name_len = (name == NULL) ? 0 : strlen(name);
- if (extra_len == kUseStrlen)
- extra_len = (extra == NULL) ? 0 : strlen(extra);
-
- provider->TraceEvent(name, name_len, type, id, extra, extra_len);
- }
-}
-
-void TraceEventETWProvider::Resurrect() {
- StaticMemorySingletonTraits<TraceEventETWProvider>::Resurrect();
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/chromium/base/trace_event/trace_event_win.h b/chromium/base/trace_event/trace_event_win.h
deleted file mode 100644
index e64be4da2d2..00000000000
--- a/chromium/base/trace_event/trace_event_win.h
+++ /dev/null
@@ -1,125 +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 file contains the Windows-specific declarations for trace_event.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/trace_event/trace_event.h"
-#include "base/win/event_trace_provider.h"
-
-namespace base {
-
-template <typename Type>
-struct StaticMemorySingletonTraits;
-
-namespace trace_event {
-
-// This EtwTraceProvider subclass implements ETW logging
-// for the macros above on Windows.
-class BASE_EXPORT TraceEventETWProvider : public base::win::EtwTraceProvider {
- public:
- static const size_t kUseStrlen = static_cast<size_t>(-1);
-
- // Start logging trace events.
- // This is a noop in this implementation.
- static bool StartTracing();
-
- // Trace begin/end/instant events, this is the bottleneck implementation
- // all the others defer to.
- // Allowing the use of std::string for name or extra is a convenience,
- // whereas passing name or extra as a const char* avoids the construction
- // of temporary std::string instances.
- // If kUseStrlen is passed for name_len or extra_len, the strlen of the string
- // will be used for length.
- static void Trace(const char* name,
- size_t name_len,
- char type,
- const void* id,
- const char* extra,
- size_t extra_len);
-
- // Allows passing extra as a std::string for convenience.
- static void Trace(const char* name,
- char type,
- const void* id,
- const std::string& extra) {
- return Trace(name, kUseStrlen, type, id, extra.c_str(), extra.length());
- }
-
- // Allows passing extra as a const char* to avoid constructing temporary
- // std::string instances where not needed.
- static void Trace(const char* name,
- char type,
- const void* id,
- const char* extra) {
- return Trace(name, kUseStrlen, type, id, extra, kUseStrlen);
- }
-
- // Retrieves the singleton.
- // Note that this may return NULL post-AtExit processing.
- static TraceEventETWProvider* GetInstance();
-
- // Returns true iff tracing is turned on.
- bool IsTracing() {
- return enable_level() >= TRACE_LEVEL_INFORMATION;
- }
-
- // Emit a trace of type |type| containing |name|, |id|, and |extra|.
- // Note: |name| and |extra| must be NULL, or a zero-terminated string of
- // length |name_len| or |extra_len| respectively.
- // Note: if name_len or extra_len are kUseStrlen, the length of the
- // corresponding string will be used.
- void TraceEvent(const char* name,
- size_t name_len,
- char type,
- const void* id,
- const char* extra,
- size_t extra_len);
-
- // Exposed for unittesting only, allows resurrecting our
- // singleton instance post-AtExit processing.
- static void Resurrect();
-
- private:
- // Ensure only the provider can construct us.
- friend struct StaticMemorySingletonTraits<TraceEventETWProvider>;
- TraceEventETWProvider();
-
- DISALLOW_COPY_AND_ASSIGN(TraceEventETWProvider);
-};
-
-// The ETW trace provider GUID.
-BASE_EXPORT extern const GUID kChromeTraceProviderName;
-
-// The ETW event class GUID for 32 bit events.
-BASE_EXPORT extern const GUID kTraceEventClass32;
-
-// The ETW event class GUID for 64 bit events.
-BASE_EXPORT extern const GUID kTraceEventClass64;
-
-// The ETW event types, IDs 0x00-0x09 are reserved, so start at 0x10.
-const base::win::EtwEventType kTraceEventTypeBegin = 0x10;
-const base::win::EtwEventType kTraceEventTypeEnd = 0x11;
-const base::win::EtwEventType kTraceEventTypeInstant = 0x12;
-
-// If this flag is set in enable flags
-enum TraceEventETWFlags {
- CAPTURE_STACK_TRACE = 0x0001,
-};
-
-// The event format consists of:
-// The "name" string as a zero-terminated ASCII string.
-// The id pointer in the machine bitness.
-// The "extra" string as a zero-terminated ASCII string.
-// Optionally the stack trace, consisting of a DWORD "depth", followed
-// by an array of void* (machine bitness) of length "depth".
-
-} // namespace trace_event
-} // namespace base
-
-#endif // BASE_TRACE_EVENT_TRACE_EVENT_WIN_H_
diff --git a/chromium/base/trace_event/trace_event_win_unittest.cc b/chromium/base/trace_event/trace_event_win_unittest.cc
deleted file mode 100644
index d4dc8542c30..00000000000
--- a/chromium/base/trace_event/trace_event_win_unittest.cc
+++ /dev/null
@@ -1,319 +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/trace_event/trace_event.h"
-
-#include <strstream>
-
-#include "base/at_exit.h"
-#include "base/basictypes.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"
-#include "base/win/windows_version.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include <initguid.h> // NOLINT - must be last include.
-
-namespace base {
-namespace trace_event {
-
-namespace {
-
-using testing::_;
-using testing::AnyNumber;
-using testing::InSequence;
-using testing::Ge;
-using testing::Le;
-using testing::NotNull;
-
-using base::win::EtwEventType;
-using base::win::EtwTraceConsumerBase;
-using base::win::EtwTraceController;
-using base::win::EtwTraceProperties;
-
-// Data for unittests traces.
-const char kEmpty[] = "";
-const char kName[] = "unittest.trace_name";
-const char kExtra[] = "UnittestDummyExtraString";
-const void* kId = kName;
-
-const wchar_t kTestSessionName[] = L"TraceEvent unittest session";
-
-MATCHER_P(BufferStartsWith, str, "Buffer starts with") {
- return memcmp(arg, str.c_str(), str.length()) == 0;
-}
-
-// Duplicated from <evntrace.h> to fix link problems.
-DEFINE_GUID( /* 68fdd900-4a3e-11d1-84f4-0000f80464e3 */
- kEventTraceGuid,
- 0x68fdd900,
- 0x4a3e,
- 0x11d1,
- 0x84, 0xf4, 0x00, 0x00, 0xf8, 0x04, 0x64, 0xe3);
-
-class TestEventConsumer: public EtwTraceConsumerBase<TestEventConsumer> {
- public:
- TestEventConsumer() {
- EXPECT_TRUE(current_ == NULL);
- current_ = this;
- }
-
- ~TestEventConsumer() {
- EXPECT_TRUE(current_ == this);
- current_ = NULL;
- }
-
- MOCK_METHOD4(Event, void(REFGUID event_class,
- EtwEventType event_type,
- size_t buf_len,
- const void* buf));
-
- static void ProcessEvent(EVENT_TRACE* event) {
- ASSERT_TRUE(current_ != NULL);
- current_->Event(event->Header.Guid,
- event->Header.Class.Type,
- event->MofLength,
- event->MofData);
- }
-
- private:
- static TestEventConsumer* current_;
-};
-
-TestEventConsumer* TestEventConsumer::current_ = NULL;
-
-class TraceEventWinTest: public testing::Test {
- public:
- TraceEventWinTest() {
- }
-
- void SetUp() override {
- bool is_xp = win::GetVersion() < base::win::VERSION_VISTA;
-
- if (is_xp) {
- // Tear down any dangling session from an earlier failing test.
- EtwTraceProperties ignore;
- EtwTraceController::Stop(kTestSessionName, &ignore);
- }
-
- // Resurrect and initialize the TraceLog singleton instance.
- // On Vista and better, we need the provider registered before we
- // start the private, in-proc session, but on XP we need the global
- // session created and the provider enabled before we register our
- // provider.
- TraceEventETWProvider* tracelog = NULL;
- if (!is_xp) {
- TraceEventETWProvider::Resurrect();
- tracelog = TraceEventETWProvider::GetInstance();
- ASSERT_TRUE(tracelog != NULL);
- ASSERT_FALSE(tracelog->IsTracing());
- }
-
- // Create the log file.
- ASSERT_TRUE(base::CreateTemporaryFile(&log_file_));
-
- // Create a private log session on the file.
- EtwTraceProperties prop;
- ASSERT_HRESULT_SUCCEEDED(prop.SetLoggerFileName(log_file_.value().c_str()));
- EVENT_TRACE_PROPERTIES& p = *prop.get();
- p.Wnode.ClientContext = 1; // QPC timer accuracy.
- p.LogFileMode = EVENT_TRACE_FILE_MODE_SEQUENTIAL; // Sequential log.
-
- // On Vista and later, we create a private in-process log session, because
- // otherwise we'd need administrator privileges. Unfortunately we can't
- // do the same on XP and better, because the semantics of a private
- // logger session are different, and the IN_PROC flag is not supported.
- if (!is_xp) {
- p.LogFileMode |= EVENT_TRACE_PRIVATE_IN_PROC | // In-proc for non-admin.
- EVENT_TRACE_PRIVATE_LOGGER_MODE; // Process-private log.
- }
-
- p.MaximumFileSize = 100; // 100M file size.
- p.FlushTimer = 1; // 1 second flush lag.
- ASSERT_HRESULT_SUCCEEDED(controller_.Start(kTestSessionName, &prop));
-
- // Enable the TraceLog provider GUID.
- ASSERT_HRESULT_SUCCEEDED(
- controller_.EnableProvider(kChromeTraceProviderName,
- TRACE_LEVEL_INFORMATION,
- 0));
-
- if (is_xp) {
- TraceEventETWProvider::Resurrect();
- tracelog = TraceEventETWProvider::GetInstance();
- }
- ASSERT_TRUE(tracelog != NULL);
- EXPECT_TRUE(tracelog->IsTracing());
- }
-
- void TearDown() override {
- EtwTraceProperties prop;
- if (controller_.session() != 0)
- EXPECT_HRESULT_SUCCEEDED(controller_.Stop(&prop));
-
- if (!log_file_.value().empty())
- base::DeleteFile(log_file_, false);
-
- // We want our singleton torn down after each test.
- TraceLog::DeleteForTesting();
- }
-
- void ExpectEvent(REFGUID guid,
- EtwEventType type,
- const char* name,
- size_t name_len,
- const void* id,
- const char* extra,
- size_t extra_len) {
- // Build the trace event buffer we expect will result from this.
- std::stringbuf str;
- str.sputn(name, name_len + 1);
- str.sputn(reinterpret_cast<const char*>(&id), sizeof(id));
- str.sputn(extra, extra_len + 1);
-
- // And set up the expectation for the event callback.
- EXPECT_CALL(consumer_, Event(guid,
- type,
- testing::Ge(str.str().length()),
- BufferStartsWith(str.str())));
- }
-
- void ExpectPlayLog() {
- // Ignore EventTraceGuid events.
- EXPECT_CALL(consumer_, Event(kEventTraceGuid, _, _, _))
- .Times(AnyNumber());
- }
-
- void PlayLog() {
- EtwTraceProperties prop;
- EXPECT_HRESULT_SUCCEEDED(controller_.Flush(&prop));
- EXPECT_HRESULT_SUCCEEDED(controller_.Stop(&prop));
- ASSERT_HRESULT_SUCCEEDED(
- consumer_.OpenFileSession(log_file_.value().c_str()));
-
- ASSERT_HRESULT_SUCCEEDED(consumer_.Consume());
- }
-
- private:
- // We want our singleton torn down after each test.
- ShadowingAtExitManager at_exit_manager_;
- EtwTraceController controller_;
- FilePath log_file_;
- TestEventConsumer consumer_;
-};
-
-} // namespace
-
-
-TEST_F(TraceEventWinTest, TraceLog) {
- ExpectPlayLog();
-
- // The events should arrive in the same sequence as the expects.
- InSequence in_sequence;
-
- // Full argument version, passing lengths explicitly.
- TraceEventETWProvider::Trace(kName,
- strlen(kName),
- TRACE_EVENT_PHASE_BEGIN,
- kId,
- kExtra,
- strlen(kExtra));
-
- ExpectEvent(kTraceEventClass32,
- kTraceEventTypeBegin,
- kName, strlen(kName),
- kId,
- kExtra, strlen(kExtra));
-
- // Const char* version.
- TraceEventETWProvider::Trace(static_cast<const char*>(kName),
- TRACE_EVENT_PHASE_END,
- kId,
- static_cast<const char*>(kExtra));
-
- ExpectEvent(kTraceEventClass32,
- kTraceEventTypeEnd,
- kName, strlen(kName),
- kId,
- kExtra, strlen(kExtra));
-
- // std::string extra version.
- TraceEventETWProvider::Trace(static_cast<const char*>(kName),
- TRACE_EVENT_PHASE_INSTANT,
- kId,
- std::string(kExtra));
-
- ExpectEvent(kTraceEventClass32,
- kTraceEventTypeInstant,
- kName, strlen(kName),
- kId,
- kExtra, strlen(kExtra));
-
-
- // Test for sanity on NULL inputs.
- TraceEventETWProvider::Trace(NULL,
- 0,
- TRACE_EVENT_PHASE_BEGIN,
- kId,
- NULL,
- 0);
-
- ExpectEvent(kTraceEventClass32,
- kTraceEventTypeBegin,
- kEmpty, 0,
- kId,
- kEmpty, 0);
-
- TraceEventETWProvider::Trace(NULL,
- TraceEventETWProvider::kUseStrlen,
- TRACE_EVENT_PHASE_END,
- kId,
- NULL,
- TraceEventETWProvider::kUseStrlen);
-
- ExpectEvent(kTraceEventClass32,
- kTraceEventTypeEnd,
- kEmpty, 0,
- kId,
- kEmpty, 0);
-
- PlayLog();
-}
-
-TEST_F(TraceEventWinTest, Macros) {
- ExpectPlayLog();
-
- // The events should arrive in the same sequence as the expects.
- InSequence in_sequence;
-
- TRACE_EVENT_BEGIN_ETW(kName, kId, kExtra);
- ExpectEvent(kTraceEventClass32,
- kTraceEventTypeBegin,
- kName, strlen(kName),
- kId,
- kExtra, strlen(kExtra));
-
- TRACE_EVENT_END_ETW(kName, kId, kExtra);
- ExpectEvent(kTraceEventClass32,
- kTraceEventTypeEnd,
- kName, strlen(kName),
- kId,
- kExtra, strlen(kExtra));
-
- TRACE_EVENT_INSTANT_ETW(kName, kId, kExtra);
- ExpectEvent(kTraceEventClass32,
- kTraceEventTypeInstant,
- kName, strlen(kName),
- kId,
- kExtra, strlen(kExtra));
-
- PlayLog();
-}
-
-} // namespace trace_event
-} // namespace base
diff --git a/chromium/base/trace_event/trace_log.cc b/chromium/base/trace_event/trace_log.cc
index af7cf440686..c2d4b282b71 100644
--- a/chromium/base/trace_event/trace_log.cc
+++ b/chromium/base/trace_event/trace_log.cc
@@ -6,6 +6,7 @@
#include <algorithm>
#include <cmath>
+#include <utility>
#include "base/base_switches.h"
#include "base/bind.h"
@@ -13,8 +14,11 @@
#include "base/debug/leak_annotations.h"
#include "base/lazy_instance.h"
#include "base/location.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
#include "base/memory/singleton.h"
#include "base/process/process_metrics.h"
+#include "base/stl_util.h"
#include "base/strings/string_split.h"
#include "base/strings/string_tokenizer.h"
#include "base/strings/stringprintf.h"
@@ -25,19 +29,18 @@
#include "base/threading/thread_id_name_manager.h"
#include "base/threading/worker_pool.h"
#include "base/time/time.h"
+#include "base/trace_event/heap_profiler_allocation_context_tracker.h"
#include "base/trace_event/memory_dump_manager.h"
#include "base/trace_event/memory_dump_provider.h"
-#include "base/trace_event/memory_profiler_allocation_context.h"
#include "base/trace_event/process_memory_dump.h"
#include "base/trace_event/trace_buffer.h"
#include "base/trace_event/trace_event.h"
#include "base/trace_event/trace_event_synthetic_delay.h"
-#include "base/trace_event/trace_log.h"
#include "base/trace_event/trace_sampling_thread.h"
+#include "build/build_config.h"
#if defined(OS_WIN)
#include "base/trace_event/trace_event_etw_export_win.h"
-#include "base/trace_event/trace_event_win.h"
#endif
// The thread buckets for the sampling profiler.
@@ -83,11 +86,6 @@ const size_t kEchoToConsoleTraceEventBufferChunks = 256;
const size_t kTraceEventBufferSizeInBytes = 100 * 1024;
const int kThreadFlushTimeoutMs = 3000;
-#if !defined(OS_NACL)
-// These categories will cause deadlock when ECHO_TO_CONSOLE. crbug.com/325575.
-const char kEchoToConsoleCategoryFilter[] = "-ipc,-task";
-#endif
-
#define MAX_CATEGORY_GROUPS 100
// Parallel arrays g_category_groups and g_category_group_enabled are separate
@@ -137,13 +135,12 @@ void InitializeMetadataEvent(TraceEvent* trace_event,
::trace_event_internal::SetTraceValue(value, &arg_type, &arg_value);
trace_event->Initialize(
thread_id,
- TraceTicks(),
+ TimeTicks(),
ThreadTicks(),
TRACE_EVENT_PHASE_METADATA,
&g_category_group_enabled[g_category_metadata],
metadata_name,
trace_event_internal::kNoId, // id
- trace_event_internal::kNoId, // context_id
trace_event_internal::kNoId, // bind_id
num_args,
&arg_name,
@@ -169,7 +166,7 @@ class AutoThreadLocalBoolean {
// Use this function instead of TraceEventHandle constructor to keep the
// overhead of ScopedTracer (trace_event.h) constructor minimum.
-void MakeHandle(uint32 chunk_seq,
+void MakeHandle(uint32_t chunk_seq,
size_t chunk_index,
size_t event_index,
TraceEventHandle* handle) {
@@ -177,8 +174,8 @@ void MakeHandle(uint32 chunk_seq,
DCHECK(chunk_index <= TraceBufferChunk::kMaxChunkIndex);
DCHECK(event_index < TraceBufferChunk::kTraceBufferChunkSize);
handle->chunk_seq = chunk_seq;
- handle->chunk_index = static_cast<uint16>(chunk_index);
- handle->event_index = static_cast<uint16>(event_index);
+ handle->chunk_index = static_cast<uint16_t>(chunk_index);
+ handle->event_index = static_cast<uint16_t>(event_index);
}
} // namespace
@@ -211,15 +208,16 @@ class TraceLog::ThreadLocalEventBuffer
: public MessageLoop::DestructionObserver,
public MemoryDumpProvider {
public:
- ThreadLocalEventBuffer(TraceLog* trace_log);
+ explicit ThreadLocalEventBuffer(TraceLog* trace_log);
~ThreadLocalEventBuffer() override;
TraceEvent* AddTraceEvent(TraceEventHandle* handle);
TraceEvent* GetEventByHandle(TraceEventHandle handle) {
if (!chunk_ || handle.chunk_seq != chunk_->seq() ||
- handle.chunk_index != chunk_index_)
- return NULL;
+ handle.chunk_index != chunk_index_) {
+ return nullptr;
+ }
return chunk_->GetEventAt(handle.event_index);
}
@@ -261,7 +259,7 @@ TraceLog::ThreadLocalEventBuffer::ThreadLocalEventBuffer(TraceLog* trace_log)
// This is to report the local memory usage when memory-infra is enabled.
MemoryDumpManager::GetInstance()->RegisterDumpProvider(
- this, ThreadTaskRunnerHandle::Get());
+ this, "ThreadLocalEventBuffer", ThreadTaskRunnerHandle::Get());
AutoLock lock(trace_log->lock_);
trace_log->thread_message_loops_.insert(message_loop);
@@ -328,7 +326,7 @@ void TraceLog::ThreadLocalEventBuffer::FlushWhileLocked() {
trace_log_->lock_.AssertAcquired();
if (trace_log_->CheckGeneration(generation_)) {
// Return the chunk to the buffer only if the generation matches.
- trace_log_->logged_events_->ReturnChunk(chunk_index_, chunk_.Pass());
+ trace_log_->logged_events_->ReturnChunk(chunk_index_, std::move(chunk_));
}
// Otherwise this method may be called from the destructor, or TraceLog will
// find the generation mismatch and delete this buffer soon.
@@ -375,28 +373,12 @@ TraceLog::TraceLog()
SetProcessID(0);
#else
SetProcessID(static_cast<int>(GetCurrentProcId()));
-
- // NaCl also shouldn't access the command line.
- if (CommandLine::InitializedForCurrentProcess() &&
- CommandLine::ForCurrentProcess()->HasSwitch(switches::kTraceToConsole)) {
- std::string filter = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
- switches::kTraceToConsole);
- if (filter.empty()) {
- filter = kEchoToConsoleCategoryFilter;
- } else {
- filter.append(",");
- filter.append(kEchoToConsoleCategoryFilter);
- }
-
- LOG(ERROR) << "Start " << switches::kTraceToConsole
- << " with CategoryFilter '" << filter << "'.";
- SetEnabled(TraceConfig(filter, ECHO_TO_CONSOLE), RECORDING_MODE);
- }
#endif
logged_events_.reset(CreateTraceBuffer());
- MemoryDumpManager::GetInstance()->RegisterDumpProvider(this);
+ MemoryDumpManager::GetInstance()->RegisterDumpProvider(this, "TraceLog",
+ nullptr);
}
TraceLog::~TraceLog() {}
@@ -431,6 +413,9 @@ bool TraceLog::OnMemoryDump(const MemoryDumpArgs& args,
AutoLock lock(lock_);
if (logged_events_)
logged_events_->EstimateTraceMemoryOverhead(&overhead);
+
+ for (auto& metadata_event : metadata_events_)
+ metadata_event->EstimateTraceMemoryOverhead(&overhead);
}
overhead.AddSelf();
overhead.DumpInto("tracing/main_trace_log", pmd);
@@ -508,7 +493,7 @@ void TraceLog::UpdateSyntheticDelaysFromTraceConfig() {
double target_duration = strtod(token.c_str(), &duration_end);
if (duration_end != token.c_str()) {
delay->SetTargetDuration(TimeDelta::FromMicroseconds(
- static_cast<int64>(target_duration * 1e6)));
+ static_cast<int64_t>(target_duration * 1e6)));
} else if (token == "static") {
delay->SetMode(TraceEventSyntheticDelay::STATIC);
} else if (token == "oneshot") {
@@ -725,6 +710,9 @@ void TraceLog::SetDisabledWhileLocked() {
UpdateCategoryGroupEnabledFlags();
AddMetadataEventsWhileLocked();
+ // Remove metadata events so they will not get added to a subsequent trace.
+ metadata_events_.clear();
+
dispatching_to_observer_list_ = true;
std::vector<EnabledStateObserver*> observer_list =
enabled_state_observer_list_;
@@ -762,10 +750,7 @@ void TraceLog::RemoveEnabledStateObserver(EnabledStateObserver* listener) {
bool TraceLog::HasEnabledStateObserver(EnabledStateObserver* listener) const {
AutoLock lock(lock_);
- std::vector<EnabledStateObserver*>::const_iterator it =
- std::find(enabled_state_observer_list_.begin(),
- enabled_state_observer_list_.end(), listener);
- return it != enabled_state_observer_list_.end();
+ return ContainsValue(enabled_state_observer_list_, listener);
}
TraceLogStatus TraceLog::GetStatus() const {
@@ -788,7 +773,7 @@ TraceEvent* TraceLog::AddEventToThreadSharedChunkWhileLocked(
if (thread_shared_chunk_ && thread_shared_chunk_->IsFull()) {
logged_events_->ReturnChunk(thread_shared_chunk_index_,
- thread_shared_chunk_.Pass());
+ std::move(thread_shared_chunk_));
}
if (!thread_shared_chunk_) {
@@ -826,7 +811,7 @@ void TraceLog::SetEventCallbackEnabled(const TraceConfig& trace_config,
reinterpret_cast<subtle::AtomicWord>(cb));
event_callback_trace_config_ = trace_config;
UpdateCategoryGroupEnabledFlags();
-};
+}
void TraceLog::SetEventCallbackDisabled() {
AutoLock lock(lock_);
@@ -880,12 +865,12 @@ void TraceLog::FlushInternal(const TraceLog::OutputCallback& cb,
flush_task_runner_ = ThreadTaskRunnerHandle::IsSet()
? ThreadTaskRunnerHandle::Get()
: nullptr;
- DCHECK_IMPLIES(thread_message_loops_.size(), flush_task_runner_);
+ DCHECK(!thread_message_loops_.size() || flush_task_runner_);
flush_output_callback_ = cb;
if (thread_shared_chunk_) {
logged_events_->ReturnChunk(thread_shared_chunk_index_,
- thread_shared_chunk_.Pass());
+ std::move(thread_shared_chunk_));
}
if (thread_message_loops_.size()) {
@@ -982,7 +967,7 @@ void TraceLog::FinishFlush(int generation, bool discard_events) {
return;
}
- ConvertTraceEventsToTraceFormat(previous_logged_events.Pass(),
+ ConvertTraceEventsToTraceFormat(std::move(previous_logged_events),
flush_output_callback,
argument_filter_predicate);
}
@@ -1042,9 +1027,9 @@ void TraceLog::FlushButLeaveBufferIntact(
if (thread_shared_chunk_) {
// Return the chunk to the main buffer to flush the sampling data.
logged_events_->ReturnChunk(thread_shared_chunk_index_,
- thread_shared_chunk_.Pass());
+ std::move(thread_shared_chunk_));
}
- previous_logged_events = logged_events_->CloneForIteration().Pass();
+ previous_logged_events = logged_events_->CloneForIteration();
if (trace_options() & kInternalEnableArgumentFilter) {
CHECK(!argument_filter_predicate_.is_null());
@@ -1052,7 +1037,7 @@ void TraceLog::FlushButLeaveBufferIntact(
}
} // release lock
- ConvertTraceEventsToTraceFormat(previous_logged_events.Pass(),
+ ConvertTraceEventsToTraceFormat(std::move(previous_logged_events),
flush_output_callback,
argument_filter_predicate);
}
@@ -1076,13 +1061,12 @@ TraceEventHandle TraceLog::AddTraceEvent(
const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
unsigned int flags) {
int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
- base::TraceTicks now = base::TraceTicks::Now();
+ base::TimeTicks now = base::TimeTicks::Now();
return AddTraceEventWithThreadIdAndTimestamp(
phase,
category_group_enabled,
name,
id,
- trace_event_internal::kNoId, // context_id
trace_event_internal::kNoId, // bind_id
thread_id,
now,
@@ -1094,12 +1078,12 @@ TraceEventHandle TraceLog::AddTraceEvent(
flags);
}
-TraceEventHandle TraceLog::AddTraceEventWithContextId(
+TraceEventHandle TraceLog::AddTraceEventWithBindId(
char phase,
const unsigned char* category_group_enabled,
const char* name,
unsigned long long id,
- unsigned long long context_id,
+ unsigned long long bind_id,
int num_args,
const char** arg_names,
const unsigned char* arg_types,
@@ -1107,14 +1091,13 @@ TraceEventHandle TraceLog::AddTraceEventWithContextId(
const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
unsigned int flags) {
int thread_id = static_cast<int>(base::PlatformThread::CurrentId());
- base::TraceTicks now = base::TraceTicks::Now();
+ base::TimeTicks now = base::TimeTicks::Now();
return AddTraceEventWithThreadIdAndTimestamp(
phase,
category_group_enabled,
name,
id,
- context_id,
- trace_event_internal::kNoId, // bind_id
+ bind_id,
thread_id,
now,
num_args,
@@ -1125,6 +1108,35 @@ TraceEventHandle TraceLog::AddTraceEventWithContextId(
flags | TRACE_EVENT_FLAG_HAS_CONTEXT_ID);
}
+TraceEventHandle TraceLog::AddTraceEventWithProcessId(
+ char phase,
+ const unsigned char* category_group_enabled,
+ const char* name,
+ unsigned long long id,
+ int process_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,
+ unsigned int flags) {
+ base::TimeTicks now = base::TimeTicks::Now();
+ return AddTraceEventWithThreadIdAndTimestamp(
+ phase,
+ category_group_enabled,
+ name,
+ id,
+ trace_event_internal::kNoId, // bind_id
+ process_id,
+ now,
+ num_args,
+ arg_names,
+ arg_types,
+ arg_values,
+ convertable_values,
+ flags | TRACE_EVENT_FLAG_HAS_PROCESS_ID);
+}
+
// Handle legacy calls to AddTraceEventWithThreadIdAndTimestamp
// with kNoId as bind_id
TraceEventHandle TraceLog::AddTraceEventWithThreadIdAndTimestamp(
@@ -1132,9 +1144,8 @@ TraceEventHandle TraceLog::AddTraceEventWithThreadIdAndTimestamp(
const unsigned char* category_group_enabled,
const char* name,
unsigned long long id,
- unsigned long long context_id,
int thread_id,
- const TraceTicks& timestamp,
+ const TimeTicks& timestamp,
int num_args,
const char** arg_names,
const unsigned char* arg_types,
@@ -1146,7 +1157,6 @@ TraceEventHandle TraceLog::AddTraceEventWithThreadIdAndTimestamp(
category_group_enabled,
name,
id,
- context_id,
trace_event_internal::kNoId, // bind_id
thread_id,
timestamp,
@@ -1163,10 +1173,9 @@ TraceEventHandle TraceLog::AddTraceEventWithThreadIdAndTimestamp(
const unsigned char* category_group_enabled,
const char* name,
unsigned long long id,
- unsigned long long context_id,
unsigned long long bind_id,
int thread_id,
- const TraceTicks& timestamp,
+ const TimeTicks& timestamp,
int num_args,
const char** arg_names,
const unsigned char* arg_types,
@@ -1195,7 +1204,7 @@ TraceEventHandle TraceLog::AddTraceEventWithThreadIdAndTimestamp(
id = MangleEventId(id);
}
- TraceTicks offset_event_timestamp = OffsetTimestamp(timestamp);
+ TimeTicks offset_event_timestamp = OffsetTimestamp(timestamp);
ThreadTicks thread_now = ThreadNow();
// |thread_local_event_buffer_| can be null if the current thread doesn't have
@@ -1270,7 +1279,6 @@ TraceEventHandle TraceLog::AddTraceEventWithThreadIdAndTimestamp(
category_group_enabled,
name,
id,
- context_id,
bind_id,
num_args,
arg_names,
@@ -1333,10 +1341,30 @@ TraceEventHandle TraceLog::AddTraceEventWithThreadIdAndTimestamp(
return handle;
}
+void TraceLog::AddMetadataEvent(
+ const char* name,
+ int num_args,
+ const char** arg_names,
+ const unsigned char* arg_types,
+ const unsigned long long* arg_values,
+ const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
+ unsigned int flags) {
+ scoped_ptr<TraceEvent> trace_event(new TraceEvent);
+ AutoLock lock(lock_);
+ trace_event->Initialize(
+ 0, // thread_id
+ TimeTicks(), ThreadTicks(), TRACE_EVENT_PHASE_METADATA,
+ &g_category_group_enabled[g_category_metadata], name,
+ trace_event_internal::kNoId, // id
+ trace_event_internal::kNoId, // bind_id
+ num_args, arg_names, arg_types, arg_values, convertable_values, flags);
+ metadata_events_.push_back(std::move(trace_event));
+}
+
// May be called when a COMPELETE event ends and the unfinished event has been
// recycled (phase == TRACE_EVENT_PHASE_END and trace_event == NULL).
std::string TraceLog::EventToConsoleMessage(unsigned char phase,
- const TraceTicks& timestamp,
+ const TimeTicks& timestamp,
TraceEvent* trace_event) {
AutoLock thread_info_lock(thread_info_lock_);
@@ -1381,32 +1409,14 @@ std::string TraceLog::EventToConsoleMessage(unsigned char phase,
return log.str();
}
-void TraceLog::AddTraceEventEtw(char phase,
- const char* name,
- const void* id,
- const char* extra) {
-#if defined(OS_WIN)
- TraceEventETWProvider::Trace(name, phase, id, extra);
-#endif
- INTERNAL_TRACE_EVENT_ADD(phase, "ETW Trace Event", name,
- TRACE_EVENT_FLAG_COPY, "id", id, "extra", extra);
-}
-
-void TraceLog::AddTraceEventEtw(char phase,
- const char* name,
- const void* id,
- const std::string& extra) {
-#if defined(OS_WIN)
- TraceEventETWProvider::Trace(name, phase, id, extra);
-#endif
- INTERNAL_TRACE_EVENT_ADD(phase, "ETW Trace Event", name,
- TRACE_EVENT_FLAG_COPY, "id", id, "extra", extra);
-}
-
void TraceLog::UpdateTraceEventDuration(
const unsigned char* category_group_enabled,
const char* name,
TraceEventHandle handle) {
+ char category_group_enabled_local = *category_group_enabled;
+ if (!category_group_enabled_local)
+ return;
+
// Avoid re-entrance of AddTraceEvent. This may happen in GPU process when
// ECHO_TO_CONSOLE is enabled: AddTraceEvent -> LOG(ERROR) ->
// GpuProcessLogMessageHandler -> PostPendingTask -> TRACE_EVENT ...
@@ -1416,10 +1426,16 @@ void TraceLog::UpdateTraceEventDuration(
AutoThreadLocalBoolean thread_is_in_trace_event(&thread_is_in_trace_event_);
ThreadTicks thread_now = ThreadNow();
- TraceTicks now = OffsetNow();
+ TimeTicks now = OffsetNow();
+
+#if defined(OS_WIN)
+ // Generate an ETW event that marks the end of a complete event.
+ if (category_group_enabled_local & ENABLED_FOR_ETW_EXPORT)
+ TraceEventETWExport::AddCompleteEndEvent(name);
+#endif // OS_WIN
std::string console_message;
- if (*category_group_enabled & ENABLED_FOR_RECORDING) {
+ if (category_group_enabled_local & ENABLED_FOR_RECORDING) {
OptionalAutoLock lock(&lock_);
TraceEvent* trace_event = GetEventByHandleInternal(handle, &lock);
@@ -1445,7 +1461,7 @@ void TraceLog::UpdateTraceEventDuration(
if (console_message.size())
LOG(ERROR) << console_message;
- if (*category_group_enabled & ENABLED_FOR_EVENT_CALLBACK) {
+ if (category_group_enabled_local & ENABLED_FOR_EVENT_CALLBACK) {
EventCallback event_callback = reinterpret_cast<EventCallback>(
subtle::NoBarrier_Load(&event_callback_));
if (event_callback) {
@@ -1475,13 +1491,17 @@ void TraceLog::CancelWatchEvent() {
watch_event_callback_.Reset();
}
-uint64 TraceLog::MangleEventId(uint64 id) {
+uint64_t TraceLog::MangleEventId(uint64_t id) {
return id ^ process_id_hash_;
}
void TraceLog::AddMetadataEventsWhileLocked() {
lock_.AssertAcquired();
+ // Copy metadata added by |AddMetadataEvent| into the trace log.
+ for (const scoped_ptr<TraceEvent>& event : metadata_events_)
+ AddEventToThreadSharedChunkWhileLocked(nullptr, false)->CopyFrom(*event);
+
#if !defined(OS_NACL) // NaCl shouldn't expose the process id.
InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
0, "num_cpus", "number",
@@ -1706,9 +1726,8 @@ ScopedTraceBinaryEfficient::ScopedTraceBinaryEfficient(
category_group_enabled_,
name,
trace_event_internal::kNoId, // id
- trace_event_internal::kNoId, // context_id
static_cast<int>(base::PlatformThread::CurrentId()), // thread_id
- base::TraceTicks::Now(),
+ base::TimeTicks::Now(),
trace_event_internal::kZeroNumArgs,
nullptr,
nullptr,
diff --git a/chromium/base/trace_event/trace_log.h b/chromium/base/trace_event/trace_log.h
index 4fb33c177a9..a079f04378a 100644
--- a/chromium/base/trace_event/trace_log.h
+++ b/chromium/base/trace_event/trace_log.h
@@ -5,26 +5,22 @@
#ifndef BASE_TRACE_EVENT_TRACE_LOG_H_
#define BASE_TRACE_EVENT_TRACE_LOG_H_
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include "base/atomicops.h"
+#include "base/containers/hash_tables.h"
#include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
#include "base/trace_event/memory_dump_provider.h"
#include "base/trace_event/trace_config.h"
#include "base/trace_event/trace_event_impl.h"
-
-// 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::trace_event::TraceLog::AddTraceEventEtw( \
- TRACE_EVENT_PHASE_BEGIN, name, reinterpret_cast<const void*>(id), extra)
-
-#define TRACE_EVENT_END_ETW(name, id, extra) \
- 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::trace_event::TraceLog::AddTraceEventEtw( \
- TRACE_EVENT_PHASE_INSTANT, name, reinterpret_cast<const void*>(id), \
- extra)
+#include "build/build_config.h"
namespace base {
@@ -142,7 +138,7 @@ class BASE_EXPORT TraceLog : public MemoryDumpProvider {
// For TRACE_EVENT_PHASE_COMPLETE events, the client will still receive pairs
// of TRACE_EVENT_PHASE_BEGIN and TRACE_EVENT_PHASE_END events to keep the
// interface simple.
- typedef void (*EventCallback)(TraceTicks timestamp,
+ typedef void (*EventCallback)(TimeTicks timestamp,
char phase,
const unsigned char* category_group_enabled,
const char* name,
@@ -199,12 +195,24 @@ class BASE_EXPORT TraceLog : public MemoryDumpProvider {
const unsigned long long* arg_values,
const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
unsigned int flags);
- TraceEventHandle AddTraceEventWithContextId(
+ TraceEventHandle AddTraceEventWithBindId(
+ char phase,
+ const unsigned char* category_group_enabled,
+ const char* name,
+ unsigned long long id,
+ unsigned long long bind_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,
+ unsigned int flags);
+ TraceEventHandle AddTraceEventWithProcessId(
char phase,
const unsigned char* category_group_enabled,
const char* name,
unsigned long long id,
- unsigned long long context_id,
+ int process_id,
int num_args,
const char** arg_names,
const unsigned char* arg_types,
@@ -216,9 +224,8 @@ class BASE_EXPORT TraceLog : public MemoryDumpProvider {
const unsigned char* category_group_enabled,
const char* name,
unsigned long long id,
- unsigned long long context_id,
int thread_id,
- const TraceTicks& timestamp,
+ const TimeTicks& timestamp,
int num_args,
const char** arg_names,
const unsigned char* arg_types,
@@ -230,24 +237,25 @@ class BASE_EXPORT TraceLog : public MemoryDumpProvider {
const unsigned char* category_group_enabled,
const char* name,
unsigned long long id,
- unsigned long long context_id,
unsigned long long bind_id,
int thread_id,
- const TraceTicks& timestamp,
+ const TimeTicks& timestamp,
+ int num_args,
+ const char** arg_names,
+ const unsigned char* arg_types,
+ const unsigned long long* arg_values,
+ const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
+ unsigned int flags);
+
+ // Adds a metadata event that will be written when the trace log is flushed.
+ void AddMetadataEvent(
+ const char* name,
int num_args,
const char** arg_names,
const unsigned char* arg_types,
const unsigned long long* arg_values,
const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
unsigned int flags);
- static void AddTraceEventEtw(char phase,
- const char* category_group,
- const void* id,
- const char* extra);
- static void AddTraceEventEtw(char phase,
- const char* category_group,
- const void* id,
- const std::string& extra);
void UpdateTraceEventDuration(const unsigned char* category_group_enabled,
const char* name,
@@ -264,7 +272,7 @@ class BASE_EXPORT TraceLog : public MemoryDumpProvider {
int process_id() const { return process_id_; }
- uint64 MangleEventId(uint64 id);
+ uint64_t MangleEventId(uint64_t id);
// Exposed for unittesting:
@@ -296,7 +304,7 @@ class BASE_EXPORT TraceLog : public MemoryDumpProvider {
// sort index, ascending, then by their name, and then tid.
void SetThreadSortIndex(PlatformThreadId thread_id, int sort_index);
- // Allow setting an offset between the current TraceTicks time and the time
+ // Allow setting an offset between the current TimeTicks time and the time
// that should be reported.
void SetTimeOffset(TimeDelta offset);
@@ -369,7 +377,7 @@ class BASE_EXPORT TraceLog : public MemoryDumpProvider {
TraceBuffer* CreateTraceBuffer();
std::string EventToConsoleMessage(unsigned char phase,
- const TraceTicks& timestamp,
+ const TimeTicks& timestamp,
TraceEvent* trace_event);
TraceEvent* AddEventToThreadSharedChunkWhileLocked(TraceEventHandle* handle,
@@ -403,8 +411,8 @@ class BASE_EXPORT TraceLog : public MemoryDumpProvider {
}
void UseNextTraceBuffer();
- TraceTicks OffsetNow() const { return OffsetTimestamp(TraceTicks::Now()); }
- TraceTicks OffsetTimestamp(const TraceTicks& timestamp) const {
+ TimeTicks OffsetNow() const { return OffsetTimestamp(TimeTicks::Now()); }
+ TimeTicks OffsetTimestamp(const TimeTicks& timestamp) const {
return timestamp - time_offset_;
}
@@ -427,6 +435,7 @@ class BASE_EXPORT TraceLog : public MemoryDumpProvider {
Mode mode_;
int num_traces_recorded_;
scoped_ptr<TraceBuffer> logged_events_;
+ std::vector<scoped_ptr<TraceEvent>> metadata_events_;
subtle::AtomicWord /* EventCallback */ event_callback_;
bool dispatching_to_observer_list_;
std::vector<EnabledStateObserver*> enabled_state_observer_list_;
@@ -438,10 +447,10 @@ class BASE_EXPORT TraceLog : public MemoryDumpProvider {
base::hash_map<int, std::string> thread_names_;
// The following two maps are used only when ECHO_TO_CONSOLE.
- base::hash_map<int, std::stack<TraceTicks>> thread_event_start_times_;
+ base::hash_map<int, std::stack<TimeTicks>> thread_event_start_times_;
base::hash_map<std::string, int> thread_colors_;
- TraceTicks buffer_limit_reached_timestamp_;
+ TimeTicks buffer_limit_reached_timestamp_;
// XORed with TraceID to make it unlikely to collide with other processes.
unsigned long long process_id_hash_;
diff --git a/chromium/base/trace_event/trace_sampling_thread.cc b/chromium/base/trace_event/trace_sampling_thread.cc
index 32ce7bde769..ec4602ccc16 100644
--- a/chromium/base/trace_event/trace_sampling_thread.cc
+++ b/chromium/base/trace_event/trace_sampling_thread.cc
@@ -2,9 +2,11 @@
// 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_sampling_thread.h"
+#include <stddef.h>
+
#include "base/trace_event/trace_event_impl.h"
#include "base/trace_event/trace_log.h"
+#include "base/trace_event/trace_sampling_thread.h"
namespace base {
namespace trace_event {
diff --git a/chromium/base/trace_event/tracing_agent.cc b/chromium/base/trace_event/tracing_agent.cc
new file mode 100644
index 00000000000..3c95a3d63ca
--- /dev/null
+++ b/chromium/base/trace_event/tracing_agent.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/trace_event/tracing_agent.h"
+
+namespace base {
+namespace trace_event {
+
+TracingAgent::~TracingAgent() {}
+
+bool TracingAgent::SupportsExplicitClockSync() {
+ return false;
+}
+
+void TracingAgent::RecordClockSyncMarker(
+ int sync_id,
+ const RecordClockSyncMarkerCallback& callback) {
+ DCHECK(SupportsExplicitClockSync());
+}
+
+
+} // namespace trace_event
+} // namespace base
diff --git a/chromium/base/trace_event/tracing_agent.h b/chromium/base/trace_event/tracing_agent.h
new file mode 100644
index 00000000000..f8ca78e92db
--- /dev/null
+++ b/chromium/base/trace_event/tracing_agent.h
@@ -0,0 +1,92 @@
+// 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_TRACING_AGENT_H_
+#define BASE_TRACE_EVENT_TRACING_AGENT_H_
+
+#include "base/base_export.h"
+#include "base/callback.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/values.h"
+
+namespace base {
+
+class TimeTicks;
+
+namespace trace_event {
+
+class TraceConfig;
+
+// A tracing agent is an entity that records its own sort of trace. Each
+// tracing method that produces its own trace log should implement this
+// interface. All tracing agents must only be controlled by TracingController.
+// Some existing examples include TracingControllerImpl for Chrome trace events,
+// DebugDaemonClient for CrOs system trace, EtwSystemEventConsumer for Windows
+// system trace and PowerTracingAgent for BattOr power trace.
+class BASE_EXPORT TracingAgent {
+ public:
+ using StopAgentTracingCallback = base::Callback<void(
+ const std::string& agent_name,
+ const std::string& events_label,
+ const scoped_refptr<base::RefCountedString>& events_str_ptr)>;
+ using RecordClockSyncMarkerCallback = base::Callback<void(
+ int sync_id,
+ const TimeTicks& issue_ts,
+ const TimeTicks& issue_end_ts)>;
+
+ virtual ~TracingAgent();
+
+ // Gets the name of the tracing agent. Each tracing agent's name should be
+ // unique.
+ virtual std::string GetTracingAgentName() = 0;
+
+ // Gets the trace event label of this tracing agent. The label will be used to
+ // label this agent's trace when all traces from different tracing agents are
+ // combined. Multiple tracing agents could have the same label. The tracing
+ // agents using the same label should not be able to run at the same time. For
+ // example, ETW on Windows and CrOS system tracing both use
+ // "systemTraceEvents" as the label. Those two agents never run at the same
+ // time because they are for different platforms.
+ virtual std::string GetTraceEventLabel() = 0;
+
+ // Starts tracing on the tracing agent with the trace configuration.
+ virtual bool StartAgentTracing(const TraceConfig& trace_config) = 0;
+
+ // Stops tracing on the tracing agent. The trace data will be passed back to
+ // the TracingController via the callback.
+ virtual void StopAgentTracing(const StopAgentTracingCallback& callback) = 0;
+
+ // Checks if the tracing agent supports explicit clock synchronization.
+ virtual bool SupportsExplicitClockSync();
+
+ // Records a clock sync marker issued by another tracing agent. This is only
+ // used if the tracing agent supports explicit clock synchronization.
+ //
+ // Two things need to be done:
+ // 1. The issuer asks the receiver to record the clock sync marker.
+ // 2. The issuer records how long the receiver takes to do the recording.
+ //
+ // In Chrome, the receiver thread also runs in Chrome and it will talk to the
+ // real receiver entity, e.g., power monitor or Android device system, via
+ // different communication methods, e.g., through USB or file reading/writing.
+ // The 2nd task measures that communication latency.
+ //
+ // Having a reliable timing measurement for the 2nd task requires synchronous
+ // function call without any cross-thread or cross-process activity. However,
+ // tracing agents in Chrome run in their own threads. Therefore, the issuer
+ // needs to dedicate the 2nd task to the receiver to take time measurements
+ // in the receiver thread, and the receiver thread needs to pass them back to
+ // the issuer in the callback.
+ //
+ // The assumption is that the receiver thread knows the issuer's clock, which
+ // is true in Chrome because all agent threads' clocks are Chrome clock.
+ virtual void RecordClockSyncMarker(
+ int sync_id,
+ const RecordClockSyncMarkerCallback& callback);
+};
+
+} // namespace trace_event
+} // namespace base
+
+#endif // BASE_TRACE_EVENT_TRACING_AGENT_H_
diff --git a/chromium/base/trace_event/winheap_dump_provider_win.h b/chromium/base/trace_event/winheap_dump_provider_win.h
index e3653550d44..52edb06a8dc 100644
--- a/chromium/base/trace_event/winheap_dump_provider_win.h
+++ b/chromium/base/trace_event/winheap_dump_provider_win.h
@@ -5,8 +5,11 @@
#ifndef BASE_TRACE_EVENT_WINHEAP_DUMP_PROVIDER_WIN_H_
#define BASE_TRACE_EVENT_WINHEAP_DUMP_PROVIDER_WIN_H_
+#include <stddef.h>
+
#include <set>
+#include "base/macros.h"
#include "base/memory/singleton.h"
#include "base/trace_event/memory_dump_provider.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
index 2a072aa57bf..c74a7b7bc82 100644
--- a/chromium/base/trace_event/winheap_dump_provider_win_unittest.cc
+++ b/chromium/base/trace_event/winheap_dump_provider_win_unittest.cc
@@ -14,7 +14,7 @@ namespace base {
namespace trace_event {
TEST(WinHeapDumpProviderTest, OnMemoryDump) {
- ProcessMemoryDump pmd(make_scoped_refptr(new MemoryDumpSessionState()));
+ ProcessMemoryDump pmd(new MemoryDumpSessionState(nullptr, nullptr));
MemoryDumpArgs dump_args = {MemoryDumpLevelOfDetail::DETAILED};
WinHeapDumpProvider* winheap_dump_provider =
diff --git a/chromium/base/tracked_objects.cc b/chromium/base/tracked_objects.cc
index c7a6a3f3c95..0632edf71e5 100644
--- a/chromium/base/tracked_objects.cc
+++ b/chromium/base/tracked_objects.cc
@@ -18,6 +18,7 @@
#include "base/strings/stringprintf.h"
#include "base/third_party/valgrind/memcheck.h"
#include "base/tracking_info.h"
+#include "build/build_config.h"
using base::TimeDelta;
@@ -131,27 +132,31 @@ DeathData::~DeathData() {
// We use a macro rather than a template to force this to inline.
// Related code for calculating max is discussed on the web.
#define CONDITIONAL_ASSIGN(assign_it, target, source) \
- ((target) ^= ((target) ^ (source)) & -static_cast<int32>(assign_it))
+ ((target) ^= ((target) ^ (source)) & -static_cast<int32_t>(assign_it))
-void DeathData::RecordDeath(const int32 queue_duration,
- const int32 run_duration,
- const uint32 random_number) {
+void DeathData::RecordDeath(const int32_t queue_duration,
+ const int32_t run_duration,
+ const uint32_t random_number) {
// We'll just clamp at INT_MAX, but we should note this in the UI as such.
if (count_ < INT_MAX)
- ++count_;
+ base::subtle::NoBarrier_Store(&count_, count_ + 1);
- int sample_probability_count = sample_probability_count_;
+ int sample_probability_count =
+ base::subtle::NoBarrier_Load(&sample_probability_count_);
if (sample_probability_count < INT_MAX)
++sample_probability_count;
- sample_probability_count_ = sample_probability_count;
+ base::subtle::NoBarrier_Store(&sample_probability_count_,
+ sample_probability_count);
- queue_duration_sum_ += queue_duration;
- run_duration_sum_ += run_duration;
+ base::subtle::NoBarrier_Store(&queue_duration_sum_,
+ queue_duration_sum_ + queue_duration);
+ base::subtle::NoBarrier_Store(&run_duration_sum_,
+ run_duration_sum_ + run_duration);
- if (queue_duration_max_ < queue_duration)
- queue_duration_max_ = queue_duration;
- if (run_duration_max_ < run_duration)
- run_duration_max_ = run_duration;
+ if (queue_duration_max() < queue_duration)
+ base::subtle::NoBarrier_Store(&queue_duration_max_, queue_duration);
+ if (run_duration_max() < run_duration)
+ base::subtle::NoBarrier_Store(&run_duration_max_, run_duration);
// Take a uniformly distributed sample over all durations ever supplied during
// the current profiling phase.
@@ -163,17 +168,17 @@ void DeathData::RecordDeath(const int32 queue_duration,
// 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;
+ base::subtle::NoBarrier_Store(&queue_duration_sample_, queue_duration);
+ base::subtle::NoBarrier_Store(&run_duration_sample_, run_duration);
}
}
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_);
+ 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
@@ -192,15 +197,17 @@ void DeathData::OnProfilingPhaseCompleted(int profiling_phase) {
// 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
+ // after the reset. These fields are updated using atomics. However, race
+ // conditions are possible since these are updated individually and not
+ // together atomically, resulting in the values being mutually inconsistent.
+ // The damage is limited to selecting a wrong sample, which is not something
+ // that can cause accumulating or cascading effects.
+ // If there were no inconsistencies 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;
- queue_duration_max_ = 0;
+ base::subtle::NoBarrier_Store(&sample_probability_count_, 0);
+ base::subtle::NoBarrier_Store(&run_duration_max_, 0);
+ base::subtle::NoBarrier_Store(&queue_duration_max_, 0);
}
//------------------------------------------------------------------------------
@@ -215,20 +222,19 @@ DeathDataSnapshot::DeathDataSnapshot()
}
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)
+ int32_t run_duration_sum,
+ int32_t run_duration_max,
+ int32_t run_duration_sample,
+ int32_t queue_duration_sum,
+ int32_t queue_duration_max,
+ int32_t 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) {
-}
+ queue_duration_sample(queue_duration_sample) {}
DeathDataSnapshot::~DeathDataSnapshot() {
}
@@ -342,7 +348,7 @@ void ThreadData::PushToHeadOfList() {
(void)VALGRIND_MAKE_MEM_DEFINED_IF_ADDRESSABLE(&random_number_,
sizeof(random_number_));
MSAN_UNPOISON(&random_number_, sizeof(random_number_));
- random_number_ += static_cast<uint32>(this - static_cast<ThreadData*>(0));
+ random_number_ += static_cast<uint32_t>(this - static_cast<ThreadData*>(0));
random_number_ ^= (Now() - TrackedTime()).InMilliseconds();
DCHECK(!next_);
@@ -499,15 +505,16 @@ Births* ThreadData::TallyABirth(const Location& location) {
}
void ThreadData::TallyADeath(const Births& births,
- int32 queue_duration,
+ int32_t queue_duration,
const TaskStopwatch& stopwatch) {
- int32 run_duration = stopwatch.RunDurationMs();
+ int32_t run_duration = stopwatch.RunDurationMs();
// Stir in some randomness, plus add constant in case durations are zero.
- const uint32 kSomePrimeNumber = 2147483647;
+ const uint32_t 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<uint32>(&births - reinterpret_cast<Births*>(0));
+ random_number_ ^=
+ static_cast<uint32_t>(&births - reinterpret_cast<Births*>(0));
// 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
@@ -560,7 +567,7 @@ void ThreadData::TallyRunOnNamedThreadIfTracking(
// 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;
+ int32_t queue_duration = 0;
if (!start_of_run.is_null()) {
queue_duration = (start_of_run - completed_task.EffectiveTimePosted())
.InMilliseconds();
@@ -593,7 +600,7 @@ void ThreadData::TallyRunOnWorkerThreadIfTracking(
return;
TrackedTime start_of_run = stopwatch.StartTime();
- int32 queue_duration = 0;
+ int32_t queue_duration = 0;
if (!start_of_run.is_null()) {
queue_duration = (start_of_run - time_posted).InMilliseconds();
}
@@ -614,7 +621,7 @@ void ThreadData::TallyRunInAScopedRegionIfTracking(
if (!current_thread_data)
return;
- int32 queue_duration = 0;
+ int32_t queue_duration = 0;
current_thread_data->TallyADeath(*births, queue_duration, stopwatch);
}
@@ -925,7 +932,7 @@ TrackedTime TaskStopwatch::StartTime() const {
return start_time_;
}
-int32 TaskStopwatch::RunDurationMs() const {
+int32_t TaskStopwatch::RunDurationMs() const {
#if DCHECK_IS_ON()
DCHECK(state_ == STOPPED);
#endif
@@ -947,12 +954,12 @@ ThreadData* TaskStopwatch::GetThreadData() const {
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,
+ int32_t run_duration_sum,
+ int32_t run_duration_max,
+ int32_t run_duration_sample,
+ int32_t queue_duration_sum,
+ int32_t queue_duration_max,
+ int32_t queue_duration_sample,
const DeathDataPhaseSnapshot* prev)
: profiling_phase(profiling_phase),
death_data(count,
@@ -962,8 +969,7 @@ DeathDataPhaseSnapshot::DeathDataPhaseSnapshot(
queue_duration_sum,
queue_duration_max,
queue_duration_sample),
- prev(prev) {
-}
+ prev(prev) {}
//------------------------------------------------------------------------------
// TaskSnapshot
diff --git a/chromium/base/tracked_objects.h b/chromium/base/tracked_objects.h
index e62948d8d07..1a00ec0be05 100644
--- a/chromium/base/tracked_objects.h
+++ b/chromium/base/tracked_objects.h
@@ -5,6 +5,8 @@
#ifndef BASE_TRACKED_OBJECTS_H_
#define BASE_TRACKED_OBJECTS_H_
+#include <stdint.h>
+
#include <map>
#include <set>
#include <stack>
@@ -14,11 +16,11 @@
#include "base/atomicops.h"
#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/macros.h"
#include "base/process/process_handle.h"
#include "base/profiler/alternate_timer.h"
#include "base/profiler/tracked_time.h"
@@ -259,12 +261,12 @@ struct BASE_EXPORT DeathDataSnapshot {
// 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);
+ int32_t run_duration_sum,
+ int32_t run_duration_max,
+ int32_t run_duration_sample,
+ int32_t queue_duration_sum,
+ int32_t queue_duration_max,
+ int32_t queue_duration_sample);
~DeathDataSnapshot();
// Calculates and returns the delta between this snapshot and an earlier
@@ -272,12 +274,12 @@ struct BASE_EXPORT DeathDataSnapshot {
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;
+ int32_t run_duration_sum;
+ int32_t run_duration_max;
+ int32_t run_duration_sample;
+ int32_t queue_duration_sum;
+ int32_t queue_duration_max;
+ int32_t queue_duration_sample;
};
//------------------------------------------------------------------------------
@@ -287,12 +289,12 @@ struct BASE_EXPORT DeathDataSnapshot {
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,
+ int32_t run_duration_sum,
+ int32_t run_duration_max,
+ int32_t run_duration_sample,
+ int32_t queue_duration_sum,
+ int32_t queue_duration_max,
+ int32_t queue_duration_sample,
const DeathDataPhaseSnapshot* prev);
// Profiling phase at which completion this snapshot was taken.
@@ -325,19 +327,31 @@ class BASE_EXPORT 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,
- const uint32 random_number);
+ void RecordDeath(const int32_t queue_duration,
+ const int32_t run_duration,
+ const uint32_t 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_; }
+ int count() const { return base::subtle::NoBarrier_Load(&count_); }
+ int32_t run_duration_sum() const {
+ return base::subtle::NoBarrier_Load(&run_duration_sum_);
+ }
+ int32_t run_duration_max() const {
+ return base::subtle::NoBarrier_Load(&run_duration_max_);
+ }
+ int32_t run_duration_sample() const {
+ return base::subtle::NoBarrier_Load(&run_duration_sample_);
+ }
+ int32_t queue_duration_sum() const {
+ return base::subtle::NoBarrier_Load(&queue_duration_sum_);
+ }
+ int32_t queue_duration_max() const {
+ return base::subtle::NoBarrier_Load(&queue_duration_max_);
+ }
+ int32_t queue_duration_sample() const {
+ return base::subtle::NoBarrier_Load(&queue_duration_sample_);
+ }
const DeathDataPhaseSnapshot* last_phase_snapshot() const {
return last_phase_snapshot_;
}
@@ -352,28 +366,28 @@ class BASE_EXPORT DeathData {
// 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_;
+ base::subtle::Atomic32 count_;
// 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_;
+ base::subtle::Atomic32 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_;
+ base::subtle::Atomic32 run_duration_sum_;
+ base::subtle::Atomic32 queue_duration_sum_;
// Max values, used by local visualization routines. These are often read,
// 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_;
+ base::subtle::Atomic32 run_duration_max_;
+ base::subtle::Atomic32 queue_duration_max_;
// Samples, used by crowd sourcing gatherers. These are almost never read,
// and rarely updated. They can be modified only on the death thread.
- int32 run_duration_sample_;
- int32 queue_duration_sample_;
+ base::subtle::Atomic32 run_duration_sample_;
+ base::subtle::Atomic32 queue_duration_sample_;
// Snapshot of this death data made at the last profiling phase completion, if
// any. DeathData owns the whole list starting with this pointer.
@@ -575,7 +589,7 @@ class BASE_EXPORT ThreadData {
// Find a place to record a death on this thread.
void TallyADeath(const Births& births,
- int32 queue_duration,
+ int32_t queue_duration,
const TaskStopwatch& stopwatch);
// Snapshots (under a lock) the profiled data for the tasks for this thread
@@ -708,7 +722,7 @@ class BASE_EXPORT ThreadData {
// 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.
- uint32 random_number_;
+ uint32_t 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
@@ -748,7 +762,7 @@ class BASE_EXPORT TaskStopwatch {
// and stopping this stopwatch, minus the wallclock durations of any other
// instances that are immediately nested in this one, started and stopped on
// this thread during that period.
- int32 RunDurationMs() const;
+ int32_t RunDurationMs() const;
// Returns tracking info for the current thread.
ThreadData* GetThreadData() const;
@@ -758,14 +772,14 @@ class BASE_EXPORT TaskStopwatch {
TrackedTime start_time_;
// Wallclock duration of the task.
- int32 wallclock_duration_ms_;
+ int32_t wallclock_duration_ms_;
// Tracking info for the current thread.
ThreadData* current_thread_data_;
// Sum of wallclock durations of all stopwatches that were directly nested in
// this one.
- int32 excluded_duration_ms_;
+ int32_t excluded_duration_ms_;
// Stopwatch which was running on our thread when this stopwatch was started.
// That preexisting stopwatch must be adjusted to the exclude the wallclock
diff --git a/chromium/base/tracked_objects_unittest.cc b/chromium/base/tracked_objects_unittest.cc
index cdbf9ac7a6c..69dd85e1a00 100644
--- a/chromium/base/tracked_objects_unittest.cc
+++ b/chromium/base/tracked_objects_unittest.cc
@@ -7,6 +7,7 @@
#include "base/tracked_objects.h"
#include <stddef.h>
+#include <stdint.h>
#include "base/memory/scoped_ptr.h"
#include "base/process/process_handle.h"
@@ -184,7 +185,7 @@ TEST_F(TrackedObjectsTest, TinyStartupShutdown) {
// execution.
// Create a child (using the same birth location).
// TrackingInfo will call TallyABirth() during construction.
- const int32 start_time = 1;
+ const int32_t start_time = 1;
base::TimeTicks kBogusBirthTime = base::TimeTicks() +
base::TimeDelta::FromMilliseconds(start_time);
base::TrackingInfo pending_task(location, kBogusBirthTime);
@@ -192,7 +193,7 @@ TEST_F(TrackedObjectsTest, TinyStartupShutdown) {
TaskStopwatch stopwatch;
stopwatch.Start();
// Finally conclude the outer run.
- const int32 time_elapsed = 1000;
+ const int32_t time_elapsed = 1000;
SetTestTime(start_time + time_elapsed);
stopwatch.Stop();
@@ -240,7 +241,7 @@ TEST_F(TrackedObjectsTest, DeathDataTestRecordDeath) {
ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
scoped_ptr<DeathData> data(new DeathData());
- ASSERT_NE(data, reinterpret_cast<DeathData*>(NULL));
+ ASSERT_NE(data, nullptr);
EXPECT_EQ(data->run_duration_sum(), 0);
EXPECT_EQ(data->run_duration_max(), 0);
EXPECT_EQ(data->run_duration_sample(), 0);
@@ -250,8 +251,8 @@ TEST_F(TrackedObjectsTest, DeathDataTestRecordDeath) {
EXPECT_EQ(data->count(), 0);
EXPECT_EQ(nullptr, data->last_phase_snapshot());
- int32 run_ms = 42;
- int32 queue_ms = 8;
+ int32_t run_ms = 42;
+ int32_t queue_ms = 8;
const int kUnrandomInt = 0; // Fake random int that ensure we sample data.
data->RecordDeath(queue_ms, run_ms, kUnrandomInt);
@@ -279,10 +280,10 @@ TEST_F(TrackedObjectsTest, DeathDataTest2Phases) {
ThreadData::InitializeAndSetTrackingStatus(ThreadData::PROFILING_ACTIVE);
scoped_ptr<DeathData> data(new DeathData());
- ASSERT_NE(data, reinterpret_cast<DeathData*>(NULL));
+ ASSERT_NE(data, nullptr);
- int32 run_ms = 42;
- int32 queue_ms = 8;
+ int32_t run_ms = 42;
+ int32_t queue_ms = 8;
const int kUnrandomInt = 0; // Fake random int that ensure we sample data.
data->RecordDeath(queue_ms, run_ms, kUnrandomInt);
@@ -312,8 +313,8 @@ TEST_F(TrackedObjectsTest, DeathDataTest2Phases) {
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;
+ int32_t run_ms1 = 21;
+ int32_t queue_ms1 = 4;
data->RecordDeath(queue_ms1, run_ms1, kUnrandomInt);
EXPECT_EQ(data->run_duration_sum(), run_ms + run_ms + run_ms1);
diff --git a/chromium/base/tuple.h b/chromium/base/tuple.h
index ef51d85fed9..e5872cc4fa8 100644
--- a/chromium/base/tuple.h
+++ b/chromium/base/tuple.h
@@ -28,7 +28,10 @@
#ifndef BASE_TUPLE_H_
#define BASE_TUPLE_H_
+#include <stddef.h>
+
#include "base/bind_helpers.h"
+#include "build/build_config.h"
namespace base {
@@ -150,7 +153,7 @@ template <size_t N, typename T>
struct TupleLeaf;
template <typename... Ts>
-struct Tuple : TupleBase<Ts...> {
+struct Tuple final : TupleBase<Ts...> {
Tuple() : TupleBase<Ts...>() {}
explicit Tuple(typename TupleTraits<Ts>::ParamType... args)
: TupleBase<Ts...>(args...) {}
@@ -158,7 +161,7 @@ struct Tuple : TupleBase<Ts...> {
// Avoids ambiguity between Tuple's two constructors.
template <>
-struct Tuple<> {};
+struct Tuple<> final {};
template <size_t... Ns, typename... Ts>
struct TupleBaseImpl<IndexSequence<Ns...>, Ts...> : TupleLeaf<Ns, Ts>... {
@@ -241,11 +244,6 @@ inline Tuple<Ts&...> MakeRefTuple(Ts&... arg) {
// Non-Static Dispatchers with no out params.
-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 <typename ObjT, typename Method, typename... Ts, size_t... Ns>
inline void DispatchToMethodImpl(ObjT* obj,
Method method,
@@ -263,11 +261,6 @@ inline void DispatchToMethod(ObjT* obj,
// Static Dispatchers with no out params.
-template <typename Function, typename A>
-inline void DispatchToMethod(Function function, const A& arg) {
- (*function)(base::internal::UnwrapTraits<A>::Unwrap(arg));
-}
-
template <typename Function, typename... Ts, size_t... Ns>
inline void DispatchToFunctionImpl(Function function,
const Tuple<Ts...>& arg,
@@ -284,29 +277,6 @@ inline void DispatchToFunction(Function function, const Tuple<Ts...>& arg) {
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 <typename ObjT, typename Method, typename In, typename... OutTs>
-inline void DispatchToMethod(ObjT* obj,
- Method method,
- 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,
diff --git a/chromium/base/value_conversions.cc b/chromium/base/value_conversions.cc
index 45cd619e908..a461e2c31a9 100644
--- a/chromium/base/value_conversions.cc
+++ b/chromium/base/value_conversions.cc
@@ -4,9 +4,10 @@
#include "base/value_conversions.h"
+#include <stdint.h>
+
#include <string>
-#include "base/basictypes.h"
#include "base/files/file_path.h"
#include "base/strings/string_number_conversions.h"
#include "base/time/time.h"
@@ -38,7 +39,7 @@ StringValue* CreateTimeDeltaValue(const TimeDelta& time) {
bool GetValueAsTimeDelta(const Value& value, TimeDelta* time) {
std::string str;
- int64 int_value;
+ int64_t int_value;
if (!value.GetAsString(&str) || !base::StringToInt64(str, &int_value))
return false;
if (time)
diff --git a/chromium/base/values.cc b/chromium/base/values.cc
index 9b2483e7c18..ab3c38a02e8 100644
--- a/chromium/base/values.cc
+++ b/chromium/base/values.cc
@@ -9,6 +9,7 @@
#include <algorithm>
#include <cmath>
#include <ostream>
+#include <utility>
#include "base/json/json_writer.h"
#include "base/logging.h"
@@ -32,7 +33,7 @@ scoped_ptr<ListValue> CopyListWithoutEmptyChildren(const ListValue& list) {
if (child_copy) {
if (!copy)
copy.reset(new ListValue);
- copy->Append(child_copy.Pass());
+ copy->Append(std::move(child_copy));
}
}
return copy;
@@ -46,7 +47,7 @@ scoped_ptr<DictionaryValue> CopyDictionaryWithoutEmptyChildren(
if (child_copy) {
if (!copy)
copy.reset(new DictionaryValue);
- copy->SetWithoutPathExpansion(it.key(), child_copy.Pass());
+ copy->SetWithoutPathExpansion(it.key(), std::move(child_copy));
}
}
return copy;
@@ -313,10 +314,7 @@ BinaryValue::BinaryValue()
}
BinaryValue::BinaryValue(scoped_ptr<char[]> buffer, size_t size)
- : Value(TYPE_BINARY),
- buffer_(buffer.Pass()),
- size_(size) {
-}
+ : Value(TYPE_BINARY), buffer_(std::move(buffer)), size_(size) {}
BinaryValue::~BinaryValue() {
}
@@ -327,7 +325,7 @@ BinaryValue* BinaryValue::CreateWithCopiedBuffer(const char* buffer,
char* buffer_copy = new char[size];
memcpy(buffer_copy, buffer, size);
scoped_ptr<char[]> scoped_buffer_copy(buffer_copy);
- return new BinaryValue(scoped_buffer_copy.Pass(), size);
+ return new BinaryValue(std::move(scoped_buffer_copy), size);
}
bool BinaryValue::GetAsBinary(const BinaryValue** out_value) const {
@@ -419,7 +417,8 @@ void DictionaryValue::Set(const std::string& path, scoped_ptr<Value> in_value) {
current_path.erase(0, delimiter_position + 1);
}
- current_dictionary->SetWithoutPathExpansion(current_path, in_value.Pass());
+ current_dictionary->SetWithoutPathExpansion(current_path,
+ std::move(in_value));
}
void DictionaryValue::Set(const std::string& path, Value* in_value) {
diff --git a/chromium/base/values.h b/chromium/base/values.h
index 56be542d747..07e5b6c8382 100644
--- a/chromium/base/values.h
+++ b/chromium/base/values.h
@@ -9,7 +9,7 @@
// JavaScript. As such, it is NOT a generalized variant type, since only the
// types supported by JavaScript/JSON are supported.
//
-// IN PARTICULAR this means that there is no support for int64 or unsigned
+// IN PARTICULAR this means that there is no support for int64_t or unsigned
// numbers. Writing JSON with such types would violate the spec. If you need
// something like this, either use a double or make a string value containing
// the number you want.
@@ -18,6 +18,7 @@
#define BASE_VALUES_H_
#include <stddef.h>
+#include <stdint.h>
#include <iosfwd>
#include <map>
@@ -26,8 +27,8 @@
#include <vector>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/string16.h"
#include "base/strings/string_piece.h"
@@ -531,7 +532,8 @@ class BASE_EXPORT ValueDeserializer {
// error_code will be set with the underlying error.
// If |error_message| is non-null, it will be filled in with a formatted
// error message including the location of the error if appropriate.
- virtual Value* Deserialize(int* error_code, std::string* error_str) = 0;
+ virtual scoped_ptr<Value> Deserialize(int* error_code,
+ std::string* error_str) = 0;
};
// Stream operator so Values can be used in assertion statements. In order that
diff --git a/chromium/base/values_unittest.cc b/chromium/base/values_unittest.cc
index 37ed7cecb7e..66453e013b1 100644
--- a/chromium/base/values_unittest.cc
+++ b/chromium/base/values_unittest.cc
@@ -2,7 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
+
#include <limits>
+#include <utility>
#include "base/memory/scoped_ptr.h"
#include "base/strings/string16.h"
@@ -34,13 +37,13 @@ TEST(ValuesTest, Basic) {
settings.GetList("global.toolbar.bookmarks", &toolbar_bookmarks));
scoped_ptr<ListValue> new_toolbar_bookmarks(new ListValue);
- settings.Set("global.toolbar.bookmarks", new_toolbar_bookmarks.Pass());
+ settings.Set("global.toolbar.bookmarks", std::move(new_toolbar_bookmarks));
ASSERT_TRUE(settings.GetList("global.toolbar.bookmarks", &toolbar_bookmarks));
scoped_ptr<DictionaryValue> new_bookmark(new DictionaryValue);
new_bookmark->SetString("name", "Froogle");
new_bookmark->SetString("url", "http://froogle.com");
- toolbar_bookmarks->Append(new_bookmark.Pass());
+ toolbar_bookmarks->Append(std::move(new_bookmark));
ListValue* bookmark_list;
ASSERT_TRUE(settings.GetList("global.toolbar.bookmarks", &bookmark_list));
@@ -114,7 +117,7 @@ TEST(ValuesTest, BinaryValue) {
// Test the common case of a non-empty buffer
scoped_ptr<char[]> buffer(new char[15]);
char* original_buffer = buffer.get();
- binary.reset(new BinaryValue(buffer.Pass(), 15));
+ binary.reset(new BinaryValue(std::move(buffer), 15));
ASSERT_TRUE(binary.get());
ASSERT_TRUE(binary->GetBuffer());
ASSERT_EQ(original_buffer, binary->GetBuffer());
@@ -250,7 +253,7 @@ TEST(ValuesTest, ListRemoval) {
ListValue list;
scoped_ptr<DeletionTestValue> value(new DeletionTestValue(&deletion_flag));
DeletionTestValue* original_value = value.get();
- list.Append(value.Pass());
+ list.Append(std::move(value));
EXPECT_FALSE(deletion_flag);
size_t index = 0;
list.Remove(*original_value, &index);
@@ -393,45 +396,45 @@ TEST(ValuesTest, DeepCopy) {
DictionaryValue original_dict;
scoped_ptr<Value> scoped_null = Value::CreateNullValue();
Value* original_null = scoped_null.get();
- original_dict.Set("null", scoped_null.Pass());
+ original_dict.Set("null", std::move(scoped_null));
scoped_ptr<FundamentalValue> scoped_bool(new FundamentalValue(true));
FundamentalValue* original_bool = scoped_bool.get();
- original_dict.Set("bool", scoped_bool.Pass());
+ original_dict.Set("bool", std::move(scoped_bool));
scoped_ptr<FundamentalValue> scoped_int(new FundamentalValue(42));
FundamentalValue* original_int = scoped_int.get();
- original_dict.Set("int", scoped_int.Pass());
+ original_dict.Set("int", std::move(scoped_int));
scoped_ptr<FundamentalValue> scoped_double(new FundamentalValue(3.14));
FundamentalValue* original_double = scoped_double.get();
- original_dict.Set("double", scoped_double.Pass());
+ original_dict.Set("double", std::move(scoped_double));
scoped_ptr<StringValue> scoped_string(new StringValue("hello"));
StringValue* original_string = scoped_string.get();
- original_dict.Set("string", scoped_string.Pass());
+ original_dict.Set("string", std::move(scoped_string));
scoped_ptr<StringValue> scoped_string16(
new StringValue(ASCIIToUTF16("hello16")));
StringValue* original_string16 = scoped_string16.get();
- original_dict.Set("string16", scoped_string16.Pass());
+ original_dict.Set("string16", std::move(scoped_string16));
scoped_ptr<char[]> original_buffer(new char[42]);
memset(original_buffer.get(), '!', 42);
scoped_ptr<BinaryValue> scoped_binary(
- new BinaryValue(original_buffer.Pass(), 42));
+ new BinaryValue(std::move(original_buffer), 42));
BinaryValue* original_binary = scoped_binary.get();
- original_dict.Set("binary", scoped_binary.Pass());
+ original_dict.Set("binary", std::move(scoped_binary));
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_list->Append(std::move(scoped_list_element_0));
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_list->Append(std::move(scoped_list_element_1));
+ original_dict.Set("list", std::move(scoped_list));
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());
+ original_dict.Set("dictionary", std::move(scoped_nested_dictionary));
scoped_ptr<DictionaryValue> copy_dict = original_dict.CreateDeepCopy();
ASSERT_TRUE(copy_dict.get());
@@ -568,9 +571,9 @@ TEST(ValuesTest, Equals) {
list->Append(make_scoped_ptr(new DictionaryValue));
scoped_ptr<Value> list_copy(list->CreateDeepCopy());
- dv.Set("f", list.Pass());
+ dv.Set("f", std::move(list));
EXPECT_FALSE(dv.Equals(copy.get()));
- copy->Set("f", list_copy.Pass());
+ copy->Set("f", std::move(list_copy));
EXPECT_TRUE(dv.Equals(copy.get()));
original_list->Append(make_scoped_ptr(new FundamentalValue(true)));
@@ -611,38 +614,38 @@ TEST(ValuesTest, DeepCopyCovariantReturnTypes) {
DictionaryValue original_dict;
scoped_ptr<Value> scoped_null(Value::CreateNullValue());
Value* original_null = scoped_null.get();
- original_dict.Set("null", scoped_null.Pass());
+ original_dict.Set("null", std::move(scoped_null));
scoped_ptr<FundamentalValue> scoped_bool(new FundamentalValue(true));
Value* original_bool = scoped_bool.get();
- original_dict.Set("bool", scoped_bool.Pass());
+ original_dict.Set("bool", std::move(scoped_bool));
scoped_ptr<FundamentalValue> scoped_int(new FundamentalValue(42));
Value* original_int = scoped_int.get();
- original_dict.Set("int", scoped_int.Pass());
+ original_dict.Set("int", std::move(scoped_int));
scoped_ptr<FundamentalValue> scoped_double(new FundamentalValue(3.14));
Value* original_double = scoped_double.get();
- original_dict.Set("double", scoped_double.Pass());
+ original_dict.Set("double", std::move(scoped_double));
scoped_ptr<StringValue> scoped_string(new StringValue("hello"));
Value* original_string = scoped_string.get();
- original_dict.Set("string", scoped_string.Pass());
+ original_dict.Set("string", std::move(scoped_string));
scoped_ptr<StringValue> scoped_string16(
new StringValue(ASCIIToUTF16("hello16")));
Value* original_string16 = scoped_string16.get();
- original_dict.Set("string16", scoped_string16.Pass());
+ original_dict.Set("string16", std::move(scoped_string16));
scoped_ptr<char[]> original_buffer(new char[42]);
memset(original_buffer.get(), '!', 42);
scoped_ptr<BinaryValue> scoped_binary(
- new BinaryValue(original_buffer.Pass(), 42));
+ new BinaryValue(std::move(original_buffer), 42));
Value* original_binary = scoped_binary.get();
- original_dict.Set("binary", scoped_binary.Pass());
+ original_dict.Set("binary", std::move(scoped_binary));
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_list->Append(std::move(scoped_list_element_0));
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_list->Append(std::move(scoped_list_element_1));
+ original_dict.Set("list", std::move(scoped_list));
scoped_ptr<Value> copy_dict = original_dict.CreateDeepCopy();
scoped_ptr<Value> copy_null = original_null->CreateDeepCopy();
@@ -697,7 +700,7 @@ TEST(ValuesTest, RemoveEmptyChildren) {
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->Set("dict_with_empty_children", std::move(inner));
root = root->DeepCopyWithoutEmptyChildren();
EXPECT_EQ(2U, root->size());
}
@@ -705,7 +708,7 @@ TEST(ValuesTest, RemoveEmptyChildren) {
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->Set("list_with_empty_children", std::move(inner));
root = root->DeepCopyWithoutEmptyChildren();
EXPECT_EQ(2U, root->size());
}
@@ -715,11 +718,11 @@ TEST(ValuesTest, RemoveEmptyChildren) {
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->Set("list_with_empty_children", std::move(inner));
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->Set("dict_with_empty_children", std::move(inner2));
root = root->DeepCopyWithoutEmptyChildren();
EXPECT_EQ(2U, root->size());
}
@@ -730,8 +733,8 @@ TEST(ValuesTest, RemoveEmptyChildren) {
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());
+ inner->Append(std::move(inner2));
+ root->Set("list_with_empty_children", std::move(inner));
root = root->DeepCopyWithoutEmptyChildren();
EXPECT_EQ(3U, root->size());
@@ -750,7 +753,7 @@ TEST(ValuesTest, MergeDictionary) {
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.Pass());
+ base->Set("sub_dict_key", std::move(base_sub_dict));
scoped_ptr<DictionaryValue> merge(new DictionaryValue);
merge->SetString("merge_key", "merge_key_value_merge");
@@ -758,7 +761,7 @@ TEST(ValuesTest, MergeDictionary) {
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.Pass());
+ merge->Set("sub_dict_key", std::move(merge_sub_dict));
base->MergeDictionary(merge.get());
@@ -799,7 +802,7 @@ TEST(ValuesTest, MergeDictionaryDeepCopy) {
EXPECT_EQ("value", value);
scoped_ptr<DictionaryValue> base(new DictionaryValue);
- base->Set("dict", child.Pass());
+ base->Set("dict", std::move(child));
EXPECT_EQ(1U, base->size());
DictionaryValue* ptr;
diff --git a/chromium/base/version.h b/chromium/base/version.h
index 814acaa2b4e..85c99a355bd 100644
--- a/chromium/base/version.h
+++ b/chromium/base/version.h
@@ -10,7 +10,6 @@
#include <vector>
#include "base/base_export.h"
-#include "base/basictypes.h"
namespace base {
@@ -25,7 +24,7 @@ class BASE_EXPORT Version {
~Version();
// Initializes from a decimal dotted version number, like "0.1.1".
- // Each component is limited to a uint16. Call IsValid() to learn
+ // Each component is limited to a uint16_t. Call IsValid() to learn
// the outcome.
explicit Version(const std::string& version_str);
diff --git a/chromium/base/version_unittest.cc b/chromium/base/version_unittest.cc
index f40ed27d881..bef96f4a501 100644
--- a/chromium/base/version_unittest.cc
+++ b/chromium/base/version_unittest.cc
@@ -4,6 +4,10 @@
#include "base/version.h"
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/macros.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
diff --git a/chromium/base/vlog.cc b/chromium/base/vlog.cc
index 519ceff10c0..c00e63185a3 100644
--- a/chromium/base/vlog.cc
+++ b/chromium/base/vlog.cc
@@ -4,12 +4,13 @@
#include "base/vlog.h"
-#include <cstddef>
+#include <stddef.h>
+
#include <ostream>
#include <utility>
-#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
diff --git a/chromium/base/vlog.h b/chromium/base/vlog.h
index a32ed14c7dd..2950904c55d 100644
--- a/chromium/base/vlog.h
+++ b/chromium/base/vlog.h
@@ -9,7 +9,7 @@
#include <vector>
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/strings/string_piece.h"
namespace logging {
diff --git a/chromium/base/vlog_unittest.cc b/chromium/base/vlog_unittest.cc
index b505d4cbf54..3c3f49cb13b 100644
--- a/chromium/base/vlog_unittest.cc
+++ b/chromium/base/vlog_unittest.cc
@@ -4,7 +4,6 @@
#include "base/vlog.h"
-#include "base/basictypes.h"
#include "base/logging.h"
#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/base/win/OWNERS b/chromium/base/win/OWNERS
index 9c18edfcb10..78473b9e74f 100644
--- a/chromium/base/win/OWNERS
+++ b/chromium/base/win/OWNERS
@@ -1,2 +1,4 @@
cpu@chromium.org
grt@chromium.org
+jschuh@chromium.org
+scottmg@chromium.org
diff --git a/chromium/base/win/enum_variant_unittest.cc b/chromium/base/win/enum_variant_unittest.cc
index 99645a26502..288c97ea559 100644
--- a/chromium/base/win/enum_variant_unittest.cc
+++ b/chromium/base/win/enum_variant_unittest.cc
@@ -31,7 +31,7 @@ TEST(EnumVariantTest, EmptyEnumVariant) {
VARIANT out_element;
ULONG out_received = 0;
EXPECT_EQ(S_FALSE, ev->Next(1, &out_element, &out_received));
- EXPECT_EQ(0, out_received);
+ EXPECT_EQ(0u, out_received);
EXPECT_EQ(S_FALSE, ev->Skip(1));
@@ -46,10 +46,10 @@ TEST(EnumVariantTest, EmptyEnumVariant) {
EXPECT_EQ(S_OK, ev2->Reset());
ULONG ev2_finalrefcount = ev2->Release();
- EXPECT_EQ(0, ev2_finalrefcount);
+ EXPECT_EQ(0u, ev2_finalrefcount);
ULONG ev_finalrefcount = ev->Release();
- EXPECT_EQ(0, ev_finalrefcount);
+ EXPECT_EQ(0u, ev_finalrefcount);
}
TEST(EnumVariantTest, SimpleEnumVariant) {
@@ -68,12 +68,12 @@ TEST(EnumVariantTest, SimpleEnumVariant) {
VARIANT out_element;
ULONG out_received = 0;
EXPECT_EQ(S_OK, ev->Next(1, &out_element, &out_received));
- EXPECT_EQ(1, out_received);
+ EXPECT_EQ(1u, out_received);
EXPECT_EQ(VT_I4, out_element.vt);
EXPECT_EQ(10, out_element.lVal);
EXPECT_EQ(S_OK, ev->Skip(1));
EXPECT_EQ(S_OK, ev->Next(1, &out_element, &out_received));
- EXPECT_EQ(1, out_received);
+ EXPECT_EQ(1u, out_received);
EXPECT_EQ(VT_I4, out_element.vt);
EXPECT_EQ(30, out_element.lVal);
EXPECT_EQ(S_FALSE, ev->Next(1, &out_element, &out_received));
@@ -82,7 +82,7 @@ TEST(EnumVariantTest, SimpleEnumVariant) {
VARIANT out_elements[3];
EXPECT_EQ(S_OK, ev->Reset());
EXPECT_EQ(S_OK, ev->Next(3, out_elements, &out_received));
- EXPECT_EQ(3, out_received);
+ EXPECT_EQ(3u, out_received);
EXPECT_EQ(VT_I4, out_elements[0].vt);
EXPECT_EQ(10, out_elements[0].lVal);
EXPECT_EQ(VT_I4, out_elements[1].vt);
@@ -98,7 +98,7 @@ TEST(EnumVariantTest, SimpleEnumVariant) {
EXPECT_EQ(S_FALSE, ev->Next(1, &out_element, &out_received));
EXPECT_EQ(S_OK, ev2->Reset());
EXPECT_EQ(S_OK, ev2->Next(3, out_elements, &out_received));
- EXPECT_EQ(3, out_received);
+ EXPECT_EQ(3u, out_received);
EXPECT_EQ(VT_I4, out_elements[0].vt);
EXPECT_EQ(10, out_elements[0].lVal);
EXPECT_EQ(VT_I4, out_elements[1].vt);
@@ -108,10 +108,10 @@ TEST(EnumVariantTest, SimpleEnumVariant) {
EXPECT_EQ(S_FALSE, ev2->Next(1, &out_element, &out_received));
ULONG ev2_finalrefcount = ev2->Release();
- EXPECT_EQ(0, ev2_finalrefcount);
+ EXPECT_EQ(0u, ev2_finalrefcount);
ULONG ev_finalrefcount = ev->Release();
- EXPECT_EQ(0, ev_finalrefcount);
+ EXPECT_EQ(0u, ev_finalrefcount);
}
} // namespace win
diff --git a/chromium/base/win/event_trace_consumer.h b/chromium/base/win/event_trace_consumer.h
index fd44894993f..9f97e0df650 100644
--- a/chromium/base/win/event_trace_consumer.h
+++ b/chromium/base/win/event_trace_consumer.h
@@ -9,8 +9,10 @@
#include <windows.h>
#include <wmistr.h>
#include <evntrace.h>
+#include <stddef.h>
#include <vector>
-#include "base/basictypes.h"
+
+#include "base/macros.h"
namespace base {
namespace win {
diff --git a/chromium/base/win/event_trace_consumer_unittest.cc b/chromium/base/win/event_trace_consumer_unittest.cc
index ecbf238bea4..8858aaf8dec 100644
--- a/chromium/base/win/event_trace_consumer_unittest.cc
+++ b/chromium/base/win/event_trace_consumer_unittest.cc
@@ -9,11 +9,11 @@
#include <objbase.h>
-#include "base/basictypes.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/process/process_handle.h"
#include "base/strings/stringprintf.h"
#include "base/win/event_trace_controller.h"
@@ -209,7 +209,8 @@ TEST_F(EtwTraceConsumerRealtimeTest, ConsumerReturnsWhenSessionClosed) {
ASSERT_HRESULT_SUCCEEDED(StartConsumerThread());
// Wait around for the consumer_ thread a bit.
- ASSERT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(consumer_thread_.Get(), 50));
+ ASSERT_EQ(static_cast<DWORD>(WAIT_TIMEOUT),
+ ::WaitForSingleObject(consumer_thread_.Get(), 50));
ASSERT_HRESULT_SUCCEEDED(controller.Stop(NULL));
// The consumer_ returns success on session stop.
@@ -237,14 +238,14 @@ TEST_F(EtwTraceConsumerRealtimeTest, ConsumeEvent) {
test_provider_, TRACE_LEVEL_VERBOSE, 0xFFFFFFFF));
EtwTraceProvider provider(test_provider_);
- ASSERT_EQ(ERROR_SUCCESS, provider.Register());
+ ASSERT_EQ(static_cast<DWORD>(ERROR_SUCCESS), provider.Register());
// Start the consumer_.
ASSERT_HRESULT_SUCCEEDED(StartConsumerThread());
- ASSERT_EQ(0, TestConsumer::events_.size());
+ ASSERT_EQ(0u, TestConsumer::events_.size());
EtwMofEvent<1> event(kTestEventType, 1, TRACE_LEVEL_ERROR);
- EXPECT_EQ(ERROR_SUCCESS, provider.Log(&event.header));
+ EXPECT_EQ(static_cast<DWORD>(ERROR_SUCCESS), provider.Log(&event.header));
EXPECT_EQ(WAIT_OBJECT_0,
::WaitForSingleObject(TestConsumer::sank_event_.Get(), INFINITE));
ASSERT_HRESULT_SUCCEEDED(controller.Stop(NULL));
@@ -294,9 +295,9 @@ class EtwTraceConsumerDataTest: public EtwTraceConsumerBaseTest {
EtwTraceProvider provider(test_provider_);
// Then register our provider, means we get a session handle immediately.
- EXPECT_EQ(ERROR_SUCCESS, provider.Register());
+ EXPECT_EQ(static_cast<DWORD>(ERROR_SUCCESS), provider.Register());
// Trace the event, it goes to the temp file.
- EXPECT_EQ(ERROR_SUCCESS, provider.Log(header));
+ EXPECT_EQ(static_cast<DWORD>(ERROR_SUCCESS), provider.Log(header));
EXPECT_HRESULT_SUCCEEDED(controller.DisableProvider(test_provider_));
EXPECT_HRESULT_SUCCEEDED(provider.Unregister());
EXPECT_HRESULT_SUCCEEDED(controller.Flush(NULL));
diff --git a/chromium/base/win/event_trace_controller.h b/chromium/base/win/event_trace_controller.h
index 69e755b468f..2e32b4c8efa 100644
--- a/chromium/base/win/event_trace_controller.h
+++ b/chromium/base/win/event_trace_controller.h
@@ -23,10 +23,11 @@
#include <windows.h>
#include <wmistr.h>
#include <evntrace.h>
+#include <stddef.h>
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
namespace base {
namespace win {
diff --git a/chromium/base/win/event_trace_controller_unittest.cc b/chromium/base/win/event_trace_controller_unittest.cc
index c947ed707f5..3eeeb88a79d 100644
--- a/chromium/base/win/event_trace_controller_unittest.cc
+++ b/chromium/base/win/event_trace_controller_unittest.cc
@@ -11,6 +11,7 @@
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/process/process_handle.h"
#include "base/strings/stringprintf.h"
#include "base/sys_info.h"
@@ -62,25 +63,25 @@ TEST(EtwTracePropertiesTest, Initialization) {
EXPECT_EQ(0u, p->Wnode.HistoricalContext);
EXPECT_TRUE(kGuidNull == p->Wnode.Guid);
- EXPECT_EQ(0, p->Wnode.ClientContext);
- EXPECT_EQ(WNODE_FLAG_TRACED_GUID, p->Wnode.Flags);
-
- EXPECT_EQ(0, p->BufferSize);
- EXPECT_EQ(0, p->MinimumBuffers);
- EXPECT_EQ(0, p->MaximumBuffers);
- EXPECT_EQ(0, p->MaximumFileSize);
- EXPECT_EQ(0, p->LogFileMode);
- EXPECT_EQ(0, p->FlushTimer);
- EXPECT_EQ(0, p->EnableFlags);
+ EXPECT_EQ(0u, p->Wnode.ClientContext);
+ EXPECT_EQ(static_cast<ULONG>(WNODE_FLAG_TRACED_GUID), p->Wnode.Flags);
+
+ EXPECT_EQ(0u, p->BufferSize);
+ EXPECT_EQ(0u, p->MinimumBuffers);
+ EXPECT_EQ(0u, p->MaximumBuffers);
+ EXPECT_EQ(0u, p->MaximumFileSize);
+ EXPECT_EQ(0u, p->LogFileMode);
+ EXPECT_EQ(0u, p->FlushTimer);
+ EXPECT_EQ(0u, p->EnableFlags);
EXPECT_EQ(0, p->AgeLimit);
- EXPECT_EQ(0, p->NumberOfBuffers);
- EXPECT_EQ(0, p->FreeBuffers);
- EXPECT_EQ(0, p->EventsLost);
- EXPECT_EQ(0, p->BuffersWritten);
- EXPECT_EQ(0, p->LogBuffersLost);
- EXPECT_EQ(0, p->RealTimeBuffersLost);
- EXPECT_EQ(0, p->LoggerThreadId);
+ EXPECT_EQ(0u, p->NumberOfBuffers);
+ EXPECT_EQ(0u, p->FreeBuffers);
+ EXPECT_EQ(0u, p->EventsLost);
+ EXPECT_EQ(0u, p->BuffersWritten);
+ EXPECT_EQ(0u, p->LogBuffersLost);
+ EXPECT_EQ(0u, p->RealTimeBuffersLost);
+ EXPECT_EQ(0u, p->LoggerThreadId);
EXPECT_NE(0u, p->LogFileNameOffset);
EXPECT_NE(0u, p->LoggerNameOffset);
}
@@ -133,7 +134,7 @@ class EtwTraceControllerTest : public testing::Test {
TEST_F(EtwTraceControllerTest, Initialize) {
EtwTraceController controller;
- EXPECT_EQ(NULL, controller.session());
+ EXPECT_EQ(0u, controller.session());
EXPECT_STREQ(L"", controller.session_name());
}
@@ -148,11 +149,11 @@ TEST_F(EtwTraceControllerTest, StartRealTimeSession) {
return;
}
- EXPECT_TRUE(NULL != controller.session());
+ EXPECT_NE(0u, controller.session());
EXPECT_STREQ(session_name_.c_str(), controller.session_name());
EXPECT_HRESULT_SUCCEEDED(controller.Stop(NULL));
- EXPECT_EQ(NULL, controller.session());
+ EXPECT_EQ(0u, controller.session());
EXPECT_STREQ(L"", controller.session_name());
}
@@ -171,11 +172,11 @@ TEST_F(EtwTraceControllerTest, StartFileSession) {
return;
}
- EXPECT_TRUE(NULL != controller.session());
+ EXPECT_NE(0u, controller.session());
EXPECT_STREQ(session_name_.c_str(), controller.session_name());
EXPECT_HRESULT_SUCCEEDED(controller.Stop(NULL));
- EXPECT_EQ(NULL, controller.session());
+ EXPECT_EQ(0u, controller.session());
EXPECT_STREQ(L"", controller.session_name());
base::DeleteFile(temp, false);
}
@@ -184,8 +185,8 @@ TEST_F(EtwTraceControllerTest, StartFileSession) {
TEST_F(EtwTraceControllerTest, DISABLED_EnableDisable) {
TestingProvider provider(test_provider_);
- EXPECT_EQ(ERROR_SUCCESS, provider.Register());
- EXPECT_EQ(NULL, provider.session_handle());
+ EXPECT_EQ(static_cast<DWORD>(ERROR_SUCCESS), provider.Register());
+ EXPECT_EQ(0u, provider.session_handle());
EtwTraceController controller;
HRESULT hr = controller.StartRealtimeSession(session_name_.c_str(),
@@ -208,9 +209,9 @@ TEST_F(EtwTraceControllerTest, DISABLED_EnableDisable) {
provider.WaitForCallback();
EXPECT_EQ(0, provider.enable_level());
- EXPECT_EQ(0, provider.enable_flags());
+ EXPECT_EQ(0u, provider.enable_flags());
- EXPECT_EQ(ERROR_SUCCESS, provider.Unregister());
+ EXPECT_EQ(static_cast<DWORD>(ERROR_SUCCESS), provider.Unregister());
// Enable the provider again, before registering.
EXPECT_HRESULT_SUCCEEDED(controller.EnableProvider(test_provider_,
@@ -218,7 +219,7 @@ TEST_F(EtwTraceControllerTest, DISABLED_EnableDisable) {
// Register the provider again, the settings above
// should take immediate effect.
- EXPECT_EQ(ERROR_SUCCESS, provider.Register());
+ EXPECT_EQ(static_cast<DWORD>(ERROR_SUCCESS), provider.Register());
EXPECT_EQ(TRACE_LEVEL_VERBOSE, provider.enable_level());
EXPECT_EQ(kTestProviderFlags, provider.enable_flags());
@@ -235,7 +236,7 @@ TEST_F(EtwTraceControllerTest, DISABLED_EnableDisable) {
// Session should have wound down.
EXPECT_EQ(0, provider.enable_level());
- EXPECT_EQ(0, provider.enable_flags());
+ EXPECT_EQ(0u, provider.enable_flags());
}
}
diff --git a/chromium/base/win/event_trace_provider.h b/chromium/base/win/event_trace_provider.h
index 7907347b724..d550dd6894a 100644
--- a/chromium/base/win/event_trace_provider.h
+++ b/chromium/base/win/event_trace_provider.h
@@ -10,9 +10,13 @@
#include <windows.h>
#include <wmistr.h>
#include <evntrace.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <limits>
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
namespace base {
namespace win {
@@ -64,9 +68,9 @@ template <size_t N> class EtwMofEvent: public EtwMofEventBase<N> {
header.Flags = WNODE_FLAG_TRACED_GUID | WNODE_FLAG_USE_MOF_PTR;
}
- void SetField(int field, size_t size, const void *data) {
+ void SetField(size_t field, size_t size, const void* data) {
// DCHECK(field < N);
- if ((field < N) && (size <= kuint32max)) {
+ if ((field < N) && (size <= std::numeric_limits<uint32_t>::max())) {
fields[field].DataPtr = reinterpret_cast<ULONG64>(data);
fields[field].Length = static_cast<ULONG>(size);
}
diff --git a/chromium/base/win/event_trace_provider_unittest.cc b/chromium/base/win/event_trace_provider_unittest.cc
index 55b5ae6aed6..7d5777300a3 100644
--- a/chromium/base/win/event_trace_provider_unittest.cc
+++ b/chromium/base/win/event_trace_provider_unittest.cc
@@ -31,10 +31,10 @@ TEST(EtwTraceProviderTest, ToleratesPreCreateInvocations) {
char buf[sizeof(EtwTraceProvider)] = {0};
EtwTraceProvider& provider = reinterpret_cast<EtwTraceProvider&>(buf);
- EXPECT_EQ(NULL, provider.registration_handle());
- EXPECT_EQ(NULL, provider.session_handle());
- EXPECT_EQ(0, provider.enable_flags());
- EXPECT_EQ(0, provider.enable_level());
+ EXPECT_EQ(0u, provider.registration_handle());
+ EXPECT_EQ(0u, provider.session_handle());
+ EXPECT_EQ(0u, provider.enable_flags());
+ EXPECT_EQ(0u, provider.enable_level());
EXPECT_FALSE(provider.ShouldLog(TRACE_LEVEL_FATAL, 0xfffffff));
@@ -51,16 +51,16 @@ TEST(EtwTraceProviderTest, ToleratesPreCreateInvocations) {
new (buf) EtwTraceProvider(kTestProvider);
// Registration is now safe.
- EXPECT_EQ(ERROR_SUCCESS, provider.Register());
+ EXPECT_EQ(static_cast<ULONG>(ERROR_SUCCESS), provider.Register());
// Destruct the instance, this should unregister it.
provider.EtwTraceProvider::~EtwTraceProvider();
// And post-destruction, all of the above should still be safe.
- EXPECT_EQ(NULL, provider.registration_handle());
- EXPECT_EQ(NULL, provider.session_handle());
- EXPECT_EQ(0, provider.enable_flags());
- EXPECT_EQ(0, provider.enable_level());
+ EXPECT_EQ(0u, provider.registration_handle());
+ EXPECT_EQ(0u, provider.session_handle());
+ EXPECT_EQ(0u, provider.enable_flags());
+ EXPECT_EQ(0u, provider.enable_level());
EXPECT_FALSE(provider.ShouldLog(TRACE_LEVEL_FATAL, 0xfffffff));
@@ -73,19 +73,19 @@ TEST(EtwTraceProviderTest, ToleratesPreCreateInvocations) {
TEST(EtwTraceProviderTest, Initialize) {
EtwTraceProvider provider(kTestProvider);
- EXPECT_EQ(NULL, provider.registration_handle());
- EXPECT_EQ(NULL, provider.session_handle());
- EXPECT_EQ(0, provider.enable_flags());
- EXPECT_EQ(0, provider.enable_level());
+ EXPECT_EQ(0u, provider.registration_handle());
+ EXPECT_EQ(0u, provider.session_handle());
+ EXPECT_EQ(0u, provider.enable_flags());
+ EXPECT_EQ(0u, provider.enable_level());
}
TEST(EtwTraceProviderTest, Register) {
EtwTraceProvider provider(kTestProvider);
- ASSERT_EQ(ERROR_SUCCESS, provider.Register());
- EXPECT_NE(NULL, provider.registration_handle());
- ASSERT_EQ(ERROR_SUCCESS, provider.Unregister());
- EXPECT_EQ(NULL, provider.registration_handle());
+ ASSERT_EQ(static_cast<ULONG>(ERROR_SUCCESS), provider.Register());
+ EXPECT_NE(0u, provider.registration_handle());
+ ASSERT_EQ(static_cast<ULONG>(ERROR_SUCCESS), provider.Unregister());
+ EXPECT_EQ(0u, provider.registration_handle());
}
TEST(EtwTraceProviderTest, RegisterWithNoNameFails) {
@@ -97,14 +97,14 @@ TEST(EtwTraceProviderTest, RegisterWithNoNameFails) {
TEST(EtwTraceProviderTest, Enable) {
EtwTraceProvider provider(kTestProvider);
- ASSERT_EQ(ERROR_SUCCESS, provider.Register());
- EXPECT_NE(NULL, provider.registration_handle());
+ ASSERT_EQ(static_cast<ULONG>(ERROR_SUCCESS), provider.Register());
+ EXPECT_NE(0u, provider.registration_handle());
// No session so far.
- EXPECT_EQ(NULL, provider.session_handle());
- EXPECT_EQ(0, provider.enable_flags());
- EXPECT_EQ(0, provider.enable_level());
+ EXPECT_EQ(0u, provider.session_handle());
+ EXPECT_EQ(0u, provider.enable_flags());
+ EXPECT_EQ(0u, provider.enable_level());
- ASSERT_EQ(ERROR_SUCCESS, provider.Unregister());
- EXPECT_EQ(NULL, provider.registration_handle());
+ ASSERT_EQ(static_cast<ULONG>(ERROR_SUCCESS), provider.Unregister());
+ EXPECT_EQ(0u, provider.registration_handle());
}
diff --git a/chromium/base/win/i18n.cc b/chromium/base/win/i18n.cc
index 9e523a15cb2..d7017e3186b 100644
--- a/chromium/base/win/i18n.cc
+++ b/chromium/base/win/i18n.cc
@@ -7,6 +7,7 @@
#include <windows.h>
#include "base/logging.h"
+#include "base/macros.h"
namespace {
@@ -32,8 +33,9 @@ const char *const kLanguageFunctionNames[] = {
&kThreadLanguagesFunctionName[0]
};
-COMPILE_ASSERT(NUM_FUNCTIONS == arraysize(kLanguageFunctionNames),
- language_function_enum_and_names_out_of_sync);
+static_assert(NUM_FUNCTIONS == arraysize(kLanguageFunctionNames),
+ "LanguageFunction enum and kLanguageFunctionNames array must be "
+ "kept in sync");
// Calls one of the MUI Get*PreferredUILanguages functions, placing the result
// in |languages|. |function| identifies the function to call and |flags| is
diff --git a/chromium/base/win/i18n.h b/chromium/base/win/i18n.h
index c0379c15599..9e74d3f3da3 100644
--- a/chromium/base/win/i18n.h
+++ b/chromium/base/win/i18n.h
@@ -9,7 +9,6 @@
#include <vector>
#include "base/base_export.h"
-#include "base/basictypes.h"
namespace base {
namespace win {
diff --git a/chromium/base/win/i18n_unittest.cc b/chromium/base/win/i18n_unittest.cc
index 781fc39db34..9af6dbfb10d 100644
--- a/chromium/base/win/i18n_unittest.cc
+++ b/chromium/base/win/i18n_unittest.cc
@@ -6,6 +6,8 @@
#include "testing/gtest/include/gtest/gtest.h"
+#include <stddef.h>
+
#include "base/win/i18n.h"
#include "base/win/windows_version.h"
diff --git a/chromium/base/win/iat_patch_function.cc b/chromium/base/win/iat_patch_function.cc
index 31659c6c82d..be7c545b5ac 100644
--- a/chromium/base/win/iat_patch_function.cc
+++ b/chromium/base/win/iat_patch_function.cc
@@ -67,8 +67,9 @@ bool InterceptEnumCallback(const base::win::PEImage& image, const char* module,
}
// portability check
- COMPILE_ASSERT(sizeof(iat->u1.Function) ==
- sizeof(intercept_information->new_function), unknown_IAT_thunk_format);
+ static_assert(
+ sizeof(iat->u1.Function) == sizeof(intercept_information->new_function),
+ "unknown IAT thunk format");
// Patch the function.
intercept_information->return_code =
diff --git a/chromium/base/win/iat_patch_function.h b/chromium/base/win/iat_patch_function.h
index 8be97f82527..55c59307f03 100644
--- a/chromium/base/win/iat_patch_function.h
+++ b/chromium/base/win/iat_patch_function.h
@@ -8,7 +8,7 @@
#include <windows.h>
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
namespace base {
namespace win {
diff --git a/chromium/base/win/iunknown_impl_unittest.cc b/chromium/base/win/iunknown_impl_unittest.cc
index 874a43a39a9..c6c3539037e 100644
--- a/chromium/base/win/iunknown_impl_unittest.cc
+++ b/chromium/base/win/iunknown_impl_unittest.cc
@@ -30,8 +30,8 @@ TEST(IUnknownImplTest, IUnknownImpl) {
EXPECT_EQ(1, TestIUnknownImplSubclass::instance_count);
- EXPECT_EQ(1, u->AddRef());
- EXPECT_EQ(1, u->AddRef());
+ EXPECT_EQ(1u, u->AddRef());
+ EXPECT_EQ(1u, u->AddRef());
IUnknown* other = NULL;
EXPECT_EQ(E_NOINTERFACE, u->QueryInterface(
@@ -40,8 +40,8 @@ TEST(IUnknownImplTest, IUnknownImpl) {
IID_IUnknown, reinterpret_cast<void**>(&other)));
other->Release();
- EXPECT_EQ(1, u->Release());
- EXPECT_EQ(0, u->Release());
+ EXPECT_EQ(1u, u->Release());
+ EXPECT_EQ(0u, u->Release());
EXPECT_EQ(0, TestIUnknownImplSubclass::instance_count);
}
diff --git a/chromium/base/win/message_window.cc b/chromium/base/win/message_window.cc
index 57fe64c7981..381b1b167bb 100644
--- a/chromium/base/win/message_window.cc
+++ b/chromium/base/win/message_window.cc
@@ -6,6 +6,7 @@
#include "base/lazy_instance.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/process/memory.h"
#include "base/win/wrapped_window_proc.h"
diff --git a/chromium/base/win/message_window.h b/chromium/base/win/message_window.h
index ae0c6f0bc7e..950d03a90e5 100644
--- a/chromium/base/win/message_window.h
+++ b/chromium/base/win/message_window.h
@@ -8,9 +8,9 @@
#include <windows.h>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/callback.h"
#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "base/strings/string16.h"
#include "base/threading/non_thread_safe.h"
diff --git a/chromium/base/win/metro.cc b/chromium/base/win/metro.cc
deleted file mode 100644
index 794669803ca..00000000000
--- a/chromium/base/win/metro.cc
+++ /dev/null
@@ -1,110 +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/win/metro.h"
-
-#include "base/strings/string_util.h"
-
-namespace base {
-namespace win {
-
-HMODULE GetMetroModule() {
- const HMODULE kUninitialized = reinterpret_cast<HMODULE>(1);
- static HMODULE metro_module = kUninitialized;
-
- if (metro_module == kUninitialized) {
- // Initialize the cache, note that the initialization is idempotent
- // under the assumption that metro_driver is never unloaded, so the
- // race to this assignment is safe.
- metro_module = GetModuleHandleA("metro_driver.dll");
- if (metro_module != NULL) {
- // This must be a metro process if the metro_driver is loaded.
- DCHECK(IsMetroProcess());
- }
- }
-
- DCHECK(metro_module != kUninitialized);
- return metro_module;
-}
-
-bool IsMetroProcess() {
- enum ImmersiveState {
- kImmersiveUnknown,
- kImmersiveTrue,
- kImmersiveFalse
- };
- // The immersive state of a process can never change.
- // Look it up once and cache it here.
- static ImmersiveState state = kImmersiveUnknown;
-
- if (state == kImmersiveUnknown) {
- if (IsProcessImmersive(::GetCurrentProcess())) {
- state = kImmersiveTrue;
- } else {
- state = kImmersiveFalse;
- }
- }
- DCHECK_NE(kImmersiveUnknown, state);
- return state == kImmersiveTrue;
-}
-
-bool IsProcessImmersive(HANDLE process) {
- typedef BOOL (WINAPI* IsImmersiveProcessFunc)(HANDLE process);
- HMODULE user32 = ::GetModuleHandleA("user32.dll");
- DCHECK(user32 != NULL);
-
- IsImmersiveProcessFunc is_immersive_process =
- reinterpret_cast<IsImmersiveProcessFunc>(
- ::GetProcAddress(user32, "IsImmersiveProcess"));
-
- if (is_immersive_process)
- return is_immersive_process(process) ? true: false;
- return false;
-}
-
-wchar_t* LocalAllocAndCopyString(const string16& src) {
- size_t dest_size = (src.length() + 1) * sizeof(wchar_t);
- wchar_t* dest = reinterpret_cast<wchar_t*>(LocalAlloc(LPTR, dest_size));
- base::wcslcpy(dest, src.c_str(), dest_size);
- return dest;
-}
-
-// Metro driver exports for getting the launch type, initial url, initial
-// search term, etc.
-extern "C" {
-typedef const wchar_t* (*GetInitialUrl)();
-typedef const wchar_t* (*GetInitialSearchString)();
-typedef base::win::MetroLaunchType (*GetLaunchType)(
- base::win::MetroPreviousExecutionState* previous_state);
-}
-
-MetroLaunchType GetMetroLaunchParams(string16* params) {
- HMODULE metro = base::win::GetMetroModule();
- if (!metro)
- return base::win::METRO_LAUNCH_ERROR;
-
- GetLaunchType get_launch_type = reinterpret_cast<GetLaunchType>(
- ::GetProcAddress(metro, "GetLaunchType"));
- DCHECK(get_launch_type);
-
- base::win::MetroLaunchType launch_type = get_launch_type(NULL);
-
- if ((launch_type == base::win::METRO_PROTOCOL) ||
- (launch_type == base::win::METRO_LAUNCH)) {
- GetInitialUrl initial_metro_url = reinterpret_cast<GetInitialUrl>(
- ::GetProcAddress(metro, "GetInitialUrl"));
- DCHECK(initial_metro_url);
- *params = initial_metro_url();
- } else if (launch_type == base::win::METRO_SEARCH) {
- GetInitialSearchString initial_search_string =
- reinterpret_cast<GetInitialSearchString>(
- ::GetProcAddress(metro, "GetInitialSearchString"));
- DCHECK(initial_search_string);
- *params = initial_search_string();
- }
- return launch_type;
-}
-
-} // namespace win
-} // namespace base
diff --git a/chromium/base/win/metro.h b/chromium/base/win/metro.h
deleted file mode 100644
index 06960067519..00000000000
--- a/chromium/base/win/metro.h
+++ /dev/null
@@ -1,125 +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_WIN_METRO_H_
-#define BASE_WIN_METRO_H_
-
-#include <windows.h>
-
-#include "base/base_export.h"
-#include "base/callback.h"
-#include "base/files/file_path.h"
-#include "base/strings/string16.h"
-
-namespace base {
-namespace win {
-
-// Identifies the type of the metro launch.
-enum MetroLaunchType {
- METRO_LAUNCH,
- METRO_SEARCH,
- METRO_SHARE,
- METRO_FILE,
- METRO_PROTOCOL,
- METRO_LAUNCH_ERROR,
- METRO_LASTLAUNCHTYPE,
-};
-
-// In metro mode, this enum identifies the last execution state, i.e. whether
-// we crashed, terminated, etc.
-enum MetroPreviousExecutionState {
- NOTRUNNING,
- RUNNING,
- SUSPENDED,
- TERMINATED,
- CLOSEDBYUSER,
- LASTEXECUTIONSTATE,
-};
-
-// Enum values for UMA histogram reporting of site-specific tile pinning.
-// TODO(tapted): Move this to win8/util when ready (http://crbug.com/160288).
-enum MetroSecondaryTilePinUmaResult {
- METRO_PIN_STATE_NONE,
- METRO_PIN_INITIATED,
- METRO_PIN_LOGO_READY,
- METRO_PIN_REQUEST_SHOW_ERROR,
- METRO_PIN_RESULT_CANCEL,
- METRO_PIN_RESULT_OK,
- METRO_PIN_RESULT_OTHER,
- METRO_PIN_RESULT_ERROR,
- METRO_UNPIN_INITIATED,
- METRO_UNPIN_REQUEST_SHOW_ERROR,
- METRO_UNPIN_RESULT_CANCEL,
- METRO_UNPIN_RESULT_OK,
- METRO_UNPIN_RESULT_OTHER,
- METRO_UNPIN_RESULT_ERROR,
- METRO_PIN_STATE_LIMIT
-};
-
-// Contains information about the currently displayed tab in metro mode.
-struct CurrentTabInfo {
- wchar_t* title;
- wchar_t* url;
-};
-
-// Returns the handle to the metro dll loaded in the process. A NULL return
-// indicates that the metro dll was not loaded in the process.
-BASE_EXPORT HMODULE GetMetroModule();
-
-// Returns true if this process is running as an immersive program
-// in Windows Metro mode.
-BASE_EXPORT bool IsMetroProcess();
-
-// Returns true if the process identified by the handle passed in is an
-// immersive (Metro) process.
-BASE_EXPORT bool IsProcessImmersive(HANDLE process);
-
-// Allocates and returns the destination string via the LocalAlloc API after
-// copying the src to it.
-BASE_EXPORT wchar_t* LocalAllocAndCopyString(const string16& src);
-
-// 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);
-
-// Handler function for the buttons on a metro dialog box
-typedef void (*MetroDialogButtonPressedHandler)();
-
-// Handler function invoked when a metro style notification is clicked.
-typedef void (*MetroNotificationClickedHandler)(const wchar_t* context);
-
-// Function to display metro style notifications.
-typedef void (*MetroNotification)(const char* origin_url,
- const char* icon_url,
- const wchar_t* title,
- const wchar_t* body,
- const wchar_t* display_source,
- const char* notification_id,
- MetroNotificationClickedHandler handler,
- const wchar_t* handler_context);
-
-// Function to cancel displayed notification.
-typedef bool (*MetroCancelNotification)(const char* notification_id);
-
-// Callback for UMA invoked by Metro Pin and UnPin functions after user gesture.
-typedef base::Callback<void(MetroSecondaryTilePinUmaResult)>
- MetroPinUmaResultCallback;
-
-// Function to pin a site-specific tile (bookmark) to the start screen.
-typedef void (*MetroPinToStartScreen)(
- const string16& tile_id,
- const string16& title,
- const string16& url,
- const FilePath& logo_path,
- const MetroPinUmaResultCallback& callback);
-
-// Function to un-pin a site-specific tile (bookmark) from the start screen.
-typedef void (*MetroUnPinFromStartScreen)(
- const string16& title_id,
- const MetroPinUmaResultCallback& callback);
-
-} // namespace win
-} // namespace base
-
-#endif // BASE_WIN_METRO_H_
diff --git a/chromium/base/win/object_watcher.h b/chromium/base/win/object_watcher.h
index f4d608553d7..3701d0f5f90 100644
--- a/chromium/base/win/object_watcher.h
+++ b/chromium/base/win/object_watcher.h
@@ -9,6 +9,7 @@
#include "base/base_export.h"
#include "base/callback.h"
+#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
diff --git a/chromium/base/win/pe_image.cc b/chromium/base/win/pe_image.cc
index 692b7b66507..4b5d620999a 100644
--- a/chromium/base/win/pe_image.cc
+++ b/chromium/base/win/pe_image.cc
@@ -5,13 +5,13 @@
// This file implements PEImage, a generic class to manipulate PE files.
// This file was adapted from GreenBorder's Code.
+#include <stddef.h>
+
#include "base/win/pe_image.h"
namespace base {
namespace win {
-// TODO(jschuh): crbug.com/167707 Make sure this code works on 64-bit.
-
// Structure to perform imports enumerations.
struct EnumAllImportsStorage {
PEImage::EnumImportsFunction callback;
@@ -20,55 +20,56 @@ 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
- // if s1 > s2, return positive
- // Exception if inputs are invalid.
- int StrCmpByByte(LPCSTR s1, LPCSTR s2) {
- while (*s1 != '\0' && *s1 == *s2) {
- ++s1;
- ++s2;
- }
-
- return (*reinterpret_cast<const unsigned char*>(s1) -
- *reinterpret_cast<const unsigned char*>(s2));
+// 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
+// if s1 > s2, return positive
+// Exception if inputs are invalid.
+int StrCmpByByte(LPCSTR s1, LPCSTR s2) {
+ while (*s1 != '\0' && *s1 == *s2) {
+ ++s1;
+ ++s2;
}
- struct PdbInfo {
- DWORD Signature;
- GUID Guid;
- DWORD Age;
- char PdbFileName[1];
- };
+ return (*reinterpret_cast<const unsigned char*>(s1) -
+ *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.
bool ProcessImportChunk(const PEImage &image, LPCSTR module,
PIMAGE_THUNK_DATA name_table,
PIMAGE_THUNK_DATA iat, PVOID cookie) {
- EnumAllImportsStorage &storage = *reinterpret_cast<EnumAllImportsStorage*>(
- cookie);
+ EnumAllImportsStorage& storage =
+ *reinterpret_cast<EnumAllImportsStorage*>(cookie);
return image.EnumOneImportChunk(storage.callback, module, name_table, iat,
storage.cookie);
}
// Callback used to enumerate delay imports. See EnumDelayImportChunksFunction.
-bool ProcessDelayImportChunk(const PEImage &image,
+bool ProcessDelayImportChunk(const PEImage& image,
PImgDelayDescr delay_descriptor,
- LPCSTR module, PIMAGE_THUNK_DATA name_table,
- PIMAGE_THUNK_DATA iat, PIMAGE_THUNK_DATA bound_iat,
- PIMAGE_THUNK_DATA unload_iat, PVOID cookie) {
- EnumAllImportsStorage &storage = *reinterpret_cast<EnumAllImportsStorage*>(
- cookie);
+ LPCSTR module,
+ PIMAGE_THUNK_DATA name_table,
+ PIMAGE_THUNK_DATA iat,
+ PVOID cookie) {
+ EnumAllImportsStorage& storage =
+ *reinterpret_cast<EnumAllImportsStorage*>(cookie);
return image.EnumOneDelayImportChunk(storage.callback, delay_descriptor,
- module, name_table, iat, bound_iat,
- unload_iat, storage.cookie);
+ module, name_table, iat, storage.cookie);
}
void PEImage::set_module(HMODULE module) {
@@ -210,11 +211,7 @@ FARPROC PEImage::GetProcAddress(LPCSTR function_name) const {
// Check for forwarded exports as a special case.
if (exports <= function && exports + size > function)
-#pragma warning(push)
-#pragma warning(disable: 4312)
- // This cast generates a warning because it is 32 bit specific.
- return reinterpret_cast<FARPROC>(0xFFFFFFFF);
-#pragma warning(pop)
+ return reinterpret_cast<FARPROC>(-1);
return reinterpret_cast<FARPROC>(function);
}
@@ -439,8 +436,6 @@ bool PEImage::EnumDelayImportChunks(EnumDelayImportChunksFunction callback,
for (; delay_descriptor->rvaHmod; delay_descriptor++) {
PIMAGE_THUNK_DATA name_table;
PIMAGE_THUNK_DATA iat;
- PIMAGE_THUNK_DATA bound_iat; // address of the optional bound IAT
- PIMAGE_THUNK_DATA unload_iat; // address of optional copy of original IAT
LPCSTR module_name;
// check if VC7-style imports, using RVAs instead of
@@ -448,33 +443,25 @@ bool PEImage::EnumDelayImportChunks(EnumDelayImportChunksFunction callback,
bool rvas = (delay_descriptor->grAttrs & dlattrRva) != 0;
if (rvas) {
- module_name = reinterpret_cast<LPCSTR>(
- RVAToAddr(delay_descriptor->rvaDLLName));
+ module_name =
+ reinterpret_cast<LPCSTR>(RVAToAddr(delay_descriptor->rvaDLLName));
name_table = reinterpret_cast<PIMAGE_THUNK_DATA>(
- RVAToAddr(delay_descriptor->rvaINT));
+ RVAToAddr(delay_descriptor->rvaINT));
iat = reinterpret_cast<PIMAGE_THUNK_DATA>(
- RVAToAddr(delay_descriptor->rvaIAT));
- bound_iat = reinterpret_cast<PIMAGE_THUNK_DATA>(
- RVAToAddr(delay_descriptor->rvaBoundIAT));
- unload_iat = reinterpret_cast<PIMAGE_THUNK_DATA>(
- RVAToAddr(delay_descriptor->rvaUnloadIAT));
+ RVAToAddr(delay_descriptor->rvaIAT));
} else {
-#pragma warning(push)
-#pragma warning(disable: 4312)
- // These casts generate warnings because they are 32 bit specific.
- module_name = reinterpret_cast<LPCSTR>(delay_descriptor->rvaDLLName);
+ // Values in IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT are 32-bit, even on 64-bit
+ // platforms. See section 4.8 of PECOFF image spec rev 8.3.
+ module_name = reinterpret_cast<LPCSTR>(
+ static_cast<uintptr_t>(delay_descriptor->rvaDLLName));
name_table = reinterpret_cast<PIMAGE_THUNK_DATA>(
- delay_descriptor->rvaINT);
- iat = reinterpret_cast<PIMAGE_THUNK_DATA>(delay_descriptor->rvaIAT);
- bound_iat = reinterpret_cast<PIMAGE_THUNK_DATA>(
- delay_descriptor->rvaBoundIAT);
- unload_iat = reinterpret_cast<PIMAGE_THUNK_DATA>(
- delay_descriptor->rvaUnloadIAT);
-#pragma warning(pop)
+ static_cast<uintptr_t>(delay_descriptor->rvaINT));
+ iat = reinterpret_cast<PIMAGE_THUNK_DATA>(
+ static_cast<uintptr_t>(delay_descriptor->rvaIAT));
}
if (!callback(*this, delay_descriptor, module_name, name_table, iat,
- bound_iat, unload_iat, cookie))
+ cookie))
return false;
}
@@ -486,12 +473,7 @@ bool PEImage::EnumOneDelayImportChunk(EnumImportsFunction callback,
LPCSTR module_name,
PIMAGE_THUNK_DATA name_table,
PIMAGE_THUNK_DATA iat,
- PIMAGE_THUNK_DATA bound_iat,
- PIMAGE_THUNK_DATA unload_iat,
PVOID cookie) const {
- UNREFERENCED_PARAMETER(bound_iat);
- UNREFERENCED_PARAMETER(unload_iat);
-
for (; name_table->u1.Ordinal; name_table++, iat++) {
LPCSTR name = NULL;
WORD ordinal = 0;
@@ -507,12 +489,8 @@ bool PEImage::EnumOneDelayImportChunk(EnumImportsFunction callback,
import = reinterpret_cast<PIMAGE_IMPORT_BY_NAME>(
RVAToAddr(name_table->u1.ForwarderString));
} else {
-#pragma warning(push)
-#pragma warning(disable: 4312)
- // This cast generates a warning because it is 32 bit specific.
import = reinterpret_cast<PIMAGE_IMPORT_BY_NAME>(
name_table->u1.ForwarderString);
-#pragma warning(pop)
}
hint = import->Hint;
@@ -553,13 +531,13 @@ bool PEImage::VerifyMagic() const {
return true;
}
-bool PEImage::ImageRVAToOnDiskOffset(DWORD rva, DWORD *on_disk_offset) const {
+bool PEImage::ImageRVAToOnDiskOffset(DWORD rva, DWORD* on_disk_offset) const {
LPVOID address = RVAToAddr(rva);
return ImageAddrToOnDiskOffset(address, on_disk_offset);
}
bool PEImage::ImageAddrToOnDiskOffset(LPVOID address,
- DWORD *on_disk_offset) const {
+ DWORD* on_disk_offset) const {
if (NULL == address)
return false;
diff --git a/chromium/base/win/pe_image.h b/chromium/base/win/pe_image.h
index 343d2866436..4c36bcf850e 100644
--- a/chromium/base/win/pe_image.h
+++ b/chromium/base/win/pe_image.h
@@ -69,8 +69,6 @@ class PEImage {
LPCSTR module,
PIMAGE_THUNK_DATA name_table,
PIMAGE_THUNK_DATA iat,
- PIMAGE_THUNK_DATA bound_iat,
- PIMAGE_THUNK_DATA unload_iat,
PVOID cookie);
// Callback to enumerate relocations.
@@ -148,7 +146,7 @@ class PEImage {
// Pre: 'f' is either a zero terminated string or ordinal.
// Post: if 'f' is a non-forwarded export from image, 'p' is
// the exported function. If 'f' is a forwarded export
- // then p is the special value 0xFFFFFFFF. In this case
+ // then p is the special value -1. In this case
// RVAToAddr(*GetExportEntry) can be used to resolve
// the string that describes the forward.
FARPROC GetProcAddress(LPCSTR function_name) const;
@@ -204,8 +202,6 @@ class PEImage {
LPCSTR module_name,
PIMAGE_THUNK_DATA name_table,
PIMAGE_THUNK_DATA iat,
- PIMAGE_THUNK_DATA bound_iat,
- PIMAGE_THUNK_DATA unload_iat,
PVOID cookie) const;
// Enumerates PE relocation entries.
diff --git a/chromium/base/win/pe_image_test.cc b/chromium/base/win/pe_image_test.cc
index e374598ada7..85914958961 100644
--- a/chromium/base/win/pe_image_test.cc
+++ b/chromium/base/win/pe_image_test.cc
@@ -7,6 +7,8 @@
#include <cfgmgr32.h>
#include <shellapi.h>
+#pragma comment(linker, "/export:FwdExport=KERNEL32.CreateFileA")
+
extern "C" {
__declspec(dllexport) void ExportFunc1() {
diff --git a/chromium/base/win/pe_image_unittest.cc b/chromium/base/win/pe_image_unittest.cc
index 28b65a4e0ba..35b81528f1b 100644
--- a/chromium/base/win/pe_image_unittest.cc
+++ b/chromium/base/win/pe_image_unittest.cc
@@ -8,7 +8,9 @@
#include "base/files/file_path.h"
#include "base/path_service.h"
+#include "base/scoped_native_library.h"
#include "base/win/pe_image.h"
+#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
@@ -67,8 +69,6 @@ bool DelayImportChunksCallback(const PEImage& image,
LPCSTR module,
PIMAGE_THUNK_DATA name_table,
PIMAGE_THUNK_DATA iat,
- PIMAGE_THUNK_DATA bound_iat,
- PIMAGE_THUNK_DATA unload_iat,
PVOID cookie) {
int* count = reinterpret_cast<int*>(cookie);
(*count)++;
@@ -103,26 +103,26 @@ TEST(PEImageTest, EnumeratesPE) {
const int sections = 6;
const int imports_dlls = 2;
const int delay_dlls = 2;
- const int exports = 2;
- const int imports = 69;
+ const int exports = 3;
+ const int imports = 70;
const int delay_imports = 2;
- const int relocs = 632;
+ const int relocs = 976;
#else
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 exports = 3;
const int imports = 66;
const int delay_imports = 2;
- const int relocs = 1586;
+ const int relocs = 2114;
#endif
- HMODULE module = LoadLibrary(pe_image_test_path.value().c_str());
- ASSERT_TRUE(NULL != module);
+ ScopedNativeLibrary module(pe_image_test_path);
+ ASSERT_TRUE(module.is_valid());
- PEImage pe(module);
+ PEImage pe(module.get());
int count = 0;
EXPECT_TRUE(pe.VerifyMagic());
@@ -152,16 +152,14 @@ TEST(PEImageTest, EnumeratesPE) {
count = 0;
pe.EnumRelocs(RelocsCallback, &count);
EXPECT_EQ(relocs, count);
-
- FreeLibrary(module);
}
// Tests that we can locate an specific exported symbol, by name and by ordinal.
TEST(PEImageTest, RetrievesExports) {
- HMODULE module = LoadLibrary(L"advapi32.dll");
- ASSERT_TRUE(NULL != module);
+ ScopedNativeLibrary module(FilePath(L"advapi32.dll"));
+ ASSERT_TRUE(module.is_valid());
- PEImage pe(module);
+ PEImage pe(module.get());
WORD ordinal;
EXPECT_TRUE(pe.GetProcOrdinal("RegEnumKeyExW", &ordinal));
@@ -171,16 +169,44 @@ TEST(PEImageTest, RetrievesExports) {
EXPECT_TRUE(address1 != NULL);
EXPECT_TRUE(address2 != NULL);
EXPECT_TRUE(address1 == address2);
+}
+
+// Tests that we can locate a forwarded export.
+TEST(PEImageTest, ForwardedExport) {
+ 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"));
+#else
+ pe_image_test_path =
+ pe_image_test_path.Append(FILE_PATH_LITERAL("pe_image_test_32.dll"));
+#endif
+
+ ScopedNativeLibrary module(pe_image_test_path);
+
+ ASSERT_TRUE(module.is_valid());
+
+ PEImage pe(module.get());
+
+ FARPROC addr = pe.GetProcAddress("FwdExport");
+ EXPECT_EQ(FARPROC(-1), addr);
- FreeLibrary(module);
+ PDWORD export_entry = pe.GetExportEntry("FwdExport");
+ EXPECT_NE(nullptr, export_entry);
+ PVOID fwd_addr = pe.RVAToAddr(*export_entry);
+ const char expected_fwd[] = "KERNEL32.CreateFileA";
+ EXPECT_STREQ(expected_fwd, reinterpret_cast<char*>(fwd_addr));
}
// Test that we can get debug id out of a module.
TEST(PEImageTest, GetDebugId) {
- HMODULE module = LoadLibrary(L"advapi32.dll");
- ASSERT_TRUE(NULL != module);
+ ScopedNativeLibrary module(FilePath(L"advapi32.dll"));
+ ASSERT_TRUE(module.is_valid());
- PEImage pe(module);
+ PEImage pe(module.get());
GUID guid = {0};
DWORD age = 0;
EXPECT_TRUE(pe.GetDebugId(&guid, &age));
@@ -188,7 +214,6 @@ TEST(PEImageTest, GetDebugId) {
GUID empty_guid = {0};
EXPECT_TRUE(!IsEqualGUID(empty_guid, guid));
EXPECT_NE(0U, age);
- FreeLibrary(module);
}
} // namespace win
diff --git a/chromium/base/win/process_startup_helper.cc b/chromium/base/win/process_startup_helper.cc
new file mode 100644
index 00000000000..7a01211368b
--- /dev/null
+++ b/chromium/base/win/process_startup_helper.cc
@@ -0,0 +1,55 @@
+// 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/win/process_startup_helper.h"
+
+#include <crtdbg.h>
+#include <new.h>
+
+#include "base/base_switches.h"
+#include "base/command_line.h"
+
+namespace {
+
+#pragma optimize("", off)
+// Handlers for invalid parameter and pure call. They generate a breakpoint to
+// tell breakpad that it needs to dump the process.
+void InvalidParameter(const wchar_t* expression, const wchar_t* function,
+ const wchar_t* file, unsigned int line,
+ uintptr_t reserved) {
+ __debugbreak();
+ _exit(1);
+}
+
+void PureCall() {
+ __debugbreak();
+ _exit(1);
+}
+#pragma optimize("", on)
+
+} // namespace
+
+namespace base {
+namespace win {
+
+// Register the invalid param handler and pure call handler to be able to
+// notify breakpad when it happens.
+void RegisterInvalidParamHandler() {
+ _set_invalid_parameter_handler(InvalidParameter);
+ _set_purecall_handler(PureCall);
+}
+
+void SetupCRT(const CommandLine& command_line) {
+#if defined(_CRTDBG_MAP_ALLOC)
+ _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
+ _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
+#else
+ if (!command_line.HasSwitch(switches::kDisableBreakpad)) {
+ _CrtSetReportMode(_CRT_ASSERT, 0);
+ }
+#endif
+}
+
+} // namespace win
+} // namespace base
diff --git a/chromium/base/win/process_startup_helper.h b/chromium/base/win/process_startup_helper.h
new file mode 100644
index 00000000000..f633dda990e
--- /dev/null
+++ b/chromium/base/win/process_startup_helper.h
@@ -0,0 +1,26 @@
+// 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.
+
+#ifndef BASE_WIN_PROCESS_STARTUP_HELPER_H_
+#define BASE_WIN_PROCESS_STARTUP_HELPER_H_
+
+#include "base/base_export.h"
+
+namespace base {
+
+class CommandLine;
+
+namespace win {
+
+// Register the invalid param handler and pure call handler to be able to
+// notify breakpad when it happens.
+BASE_EXPORT void RegisterInvalidParamHandler();
+
+// Sets up the CRT's debugging macros to output to stdout.
+BASE_EXPORT void SetupCRT(const CommandLine& command_line);
+
+} // namespace win
+} // namespace base
+
+#endif // BASE_WIN_PROCESS_STARTUP_HELPER_H_
diff --git a/chromium/base/win/registry.cc b/chromium/base/win/registry.cc
index 28e0461c621..ee7b8cda9f2 100644
--- a/chromium/base/win/registry.cc
+++ b/chromium/base/win/registry.cc
@@ -5,9 +5,11 @@
#include "base/win/registry.h"
#include <shlwapi.h>
+#include <stddef.h>
#include <algorithm>
#include "base/logging.h"
+#include "base/macros.h"
#include "base/strings/string_util.h"
#include "base/threading/thread_restrictions.h"
#include "base/win/windows_version.h"
@@ -301,10 +303,10 @@ LONG RegKey::ReadValueDW(const wchar_t* name, DWORD* out_value) const {
return result;
}
-LONG RegKey::ReadInt64(const wchar_t* name, int64* out_value) const {
+LONG RegKey::ReadInt64(const wchar_t* name, int64_t* out_value) const {
DCHECK(out_value);
DWORD type = REG_QWORD;
- int64 local_value = 0;
+ int64_t local_value = 0;
DWORD size = sizeof(local_value);
LONG result = ReadValue(name, &local_value, &size, &type);
if (result == ERROR_SUCCESS) {
@@ -364,7 +366,7 @@ LONG RegKey::ReadValues(const wchar_t* name,
DWORD type = REG_MULTI_SZ;
DWORD size = 0;
LONG result = ReadValue(name, NULL, &size, &type);
- if (FAILED(result) || size == 0)
+ if (result != ERROR_SUCCESS || size == 0)
return result;
if (type != REG_MULTI_SZ)
@@ -372,7 +374,7 @@ LONG RegKey::ReadValues(const wchar_t* name,
std::vector<wchar_t> buffer(size / sizeof(wchar_t));
result = ReadValue(name, &buffer[0], &size, NULL);
- if (FAILED(result) || size == 0)
+ if (result != ERROR_SUCCESS || size == 0)
return result;
// Parse the double-null-terminated list of strings.
@@ -569,7 +571,7 @@ bool RegistryValueIterator::Read() {
value_size_ = static_cast<DWORD>((value_.size() - 1) * sizeof(wchar_t));
LONG result = ::RegEnumValue(
key_, index_, WriteInto(&name_, name_size), &name_size, NULL, &type_,
- reinterpret_cast<BYTE*>(vector_as_array(&value_)), &value_size_);
+ reinterpret_cast<BYTE*>(value_.data()), &value_size_);
if (result == ERROR_MORE_DATA) {
// Registry key names are limited to 255 characters and fit within
@@ -585,7 +587,7 @@ bool RegistryValueIterator::Read() {
name_size = name_size == capacity ? MAX_REGISTRY_NAME_SIZE : capacity;
result = ::RegEnumValue(
key_, index_, WriteInto(&name_, name_size), &name_size, NULL, &type_,
- reinterpret_cast<BYTE*>(vector_as_array(&value_)), &value_size_);
+ reinterpret_cast<BYTE*>(value_.data()), &value_size_);
}
if (result == ERROR_SUCCESS) {
diff --git a/chromium/base/win/registry.h b/chromium/base/win/registry.h
index c3e015b3bf0..1285be010d4 100644
--- a/chromium/base/win/registry.h
+++ b/chromium/base/win/registry.h
@@ -6,12 +6,12 @@
#define BASE_WIN_REGISTRY_H_
#include <windows.h>
+#include <stdint.h>
#include <string>
#include <vector>
#include "base/base_export.h"
-#include "base/basictypes.h"
-#include "base/stl_util.h"
+#include "base/macros.h"
#include "base/win/object_watcher.h"
#include "base/win/scoped_handle.h"
@@ -85,13 +85,13 @@ class BASE_EXPORT RegKey {
// Getters:
- // Returns an int32 value. If |name| is NULL or empty, returns the default
+ // Returns an int32_t value. If |name| is NULL or empty, returns the default
// value, if any.
LONG ReadValueDW(const wchar_t* name, DWORD* out_value) const;
- // Returns an int64 value. If |name| is NULL or empty, returns the default
+ // Returns an int64_t value. If |name| is NULL or empty, returns the default
// value, if any.
- LONG ReadInt64(const wchar_t* name, int64* out_value) const;
+ LONG ReadInt64(const wchar_t* name, int64_t* out_value) const;
// Returns a string value. If |name| is NULL or empty, returns the default
// value, if any.
@@ -111,7 +111,7 @@ class BASE_EXPORT RegKey {
// Setters:
- // Sets an int32 value.
+ // Sets an int32_t value.
LONG WriteValue(const wchar_t* name, DWORD in_value);
// Sets a string value.
@@ -180,7 +180,7 @@ class BASE_EXPORT RegistryValueIterator {
void operator++();
const wchar_t* Name() const { return name_.c_str(); }
- const wchar_t* Value() const { return vector_as_array(&value_); }
+ const wchar_t* Value() const { return value_.data(); }
// ValueSize() is in bytes.
DWORD ValueSize() const { return value_size_; }
DWORD Type() const { return type_; }
diff --git a/chromium/base/win/registry_unittest.cc b/chromium/base/win/registry_unittest.cc
index 22576634f9a..08d5d484d48 100644
--- a/chromium/base/win/registry_unittest.cc
+++ b/chromium/base/win/registry_unittest.cc
@@ -4,11 +4,14 @@
#include "base/win/registry.h"
+#include <stdint.h>
+
#include <cstring>
#include <vector>
#include "base/bind.h"
#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/stl_util.h"
@@ -86,7 +89,7 @@ TEST_F(RegistryTest, ValueTest) {
const wchar_t kInt64ValueName[] = L"Int64Value";
const wchar_t kStringData[] = L"string data";
const DWORD kDWORDData = 0xdeadbabe;
- const int64 kInt64Data = 0xdeadbabedeadbabeLL;
+ const int64_t kInt64Data = 0xdeadbabedeadbabeLL;
// Test value creation
ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(kStringValueName, kStringData));
@@ -101,7 +104,7 @@ TEST_F(RegistryTest, ValueTest) {
// Test Read
std::wstring string_value;
DWORD dword_value = 0;
- int64 int64_value = 0;
+ int64_t int64_value = 0;
ASSERT_EQ(ERROR_SUCCESS, key.ReadValue(kStringValueName, &string_value));
ASSERT_EQ(ERROR_SUCCESS, key.ReadValueDW(kDWORDValueName, &dword_value));
ASSERT_EQ(ERROR_SUCCESS, key.ReadInt64(kInt64ValueName, &int64_value));
@@ -166,8 +169,8 @@ TEST_F(RegistryTest, TruncatedCharTest) {
const wchar_t kName[] = L"name";
// kData size is not a multiple of sizeof(wchar_t).
- const uint8 kData[] = { 1, 2, 3, 4, 5 };
- EXPECT_EQ(5, arraysize(kData));
+ const uint8_t kData[] = {1, 2, 3, 4, 5};
+ EXPECT_EQ(5u, arraysize(kData));
ASSERT_EQ(ERROR_SUCCESS, key.WriteValue(kName, kData,
arraysize(kData), REG_BINARY));
diff --git a/chromium/base/win/resource_util.h b/chromium/base/win/resource_util.h
index 8a8baa0f532..00687b9ff79 100644
--- a/chromium/base/win/resource_util.h
+++ b/chromium/base/win/resource_util.h
@@ -9,9 +9,9 @@
#define BASE_WIN_RESOURCE_UTIL_H_
#include <windows.h>
+#include <stddef.h>
#include "base/base_export.h"
-#include "base/basictypes.h"
namespace base {
namespace win {
diff --git a/chromium/base/win/scoped_bstr.cc b/chromium/base/win/scoped_bstr.cc
index 63ade0cb421..02f3d541222 100644
--- a/chromium/base/win/scoped_bstr.cc
+++ b/chromium/base/win/scoped_bstr.cc
@@ -4,6 +4,8 @@
#include "base/win/scoped_bstr.h"
+#include <stdint.h>
+
#include "base/logging.h"
namespace base {
@@ -14,7 +16,7 @@ ScopedBstr::ScopedBstr(const char16* non_bstr)
}
ScopedBstr::~ScopedBstr() {
- COMPILE_ASSERT(sizeof(ScopedBstr) == sizeof(BSTR), ScopedBstrSize);
+ static_assert(sizeof(ScopedBstr) == sizeof(BSTR), "ScopedBstrSize");
SysFreeString(bstr_);
}
@@ -55,8 +57,8 @@ BSTR ScopedBstr::AllocateBytes(size_t bytes) {
void ScopedBstr::SetByteLen(size_t bytes) {
DCHECK(bstr_ != NULL) << "attempting to modify a NULL bstr";
- uint32* data = reinterpret_cast<uint32*>(bstr_);
- data[-1] = static_cast<uint32>(bytes);
+ uint32_t* data = reinterpret_cast<uint32_t*>(bstr_);
+ data[-1] = static_cast<uint32_t>(bytes);
}
size_t ScopedBstr::Length() const {
diff --git a/chromium/base/win/scoped_bstr.h b/chromium/base/win/scoped_bstr.h
index 7c9f5df0868..413fb28681e 100644
--- a/chromium/base/win/scoped_bstr.h
+++ b/chromium/base/win/scoped_bstr.h
@@ -7,9 +7,11 @@
#include <windows.h>
#include <oleauto.h>
+#include <stddef.h>
#include "base/base_export.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/strings/string16.h"
namespace base {
diff --git a/chromium/base/win/scoped_bstr_unittest.cc b/chromium/base/win/scoped_bstr_unittest.cc
index 5f6f7dffe4d..d305e5a2b7d 100644
--- a/chromium/base/win/scoped_bstr_unittest.cc
+++ b/chromium/base/win/scoped_bstr_unittest.cc
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stddef.h>
+
+#include "base/macros.h"
#include "base/win/scoped_bstr.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -18,8 +21,8 @@ size_t test2_len = arraysize(kTestString2) - 1;
void DumbBstrTests() {
ScopedBstr b;
EXPECT_TRUE(b == NULL);
- EXPECT_EQ(0, b.Length());
- EXPECT_EQ(0, b.ByteLength());
+ EXPECT_EQ(0u, b.Length());
+ EXPECT_EQ(0u, b.ByteLength());
b.Reset(NULL);
EXPECT_TRUE(b == NULL);
EXPECT_TRUE(b.Release() == NULL);
@@ -40,7 +43,7 @@ void BasicBstrTests() {
ScopedBstr b2;
b1.Swap(b2);
EXPECT_EQ(test1_len, b2.Length());
- EXPECT_EQ(0, b1.Length());
+ EXPECT_EQ(0u, b1.Length());
EXPECT_EQ(0, lstrcmp(b2, kTestString1));
BSTR tmp = b2.Release();
EXPECT_TRUE(tmp != NULL);
@@ -52,13 +55,13 @@ void BasicBstrTests() {
EXPECT_TRUE(b2 != NULL);
b2.Reset();
EXPECT_TRUE(b2.AllocateBytes(100) != NULL);
- EXPECT_EQ(100, b2.ByteLength());
+ EXPECT_EQ(100u, b2.ByteLength());
EXPECT_EQ(100 / sizeof(kTestString1[0]), b2.Length());
lstrcpy(static_cast<BSTR>(b2), kTestString1);
- EXPECT_EQ(test1_len, lstrlen(b2));
+ EXPECT_EQ(test1_len, static_cast<size_t>(lstrlen(b2)));
EXPECT_EQ(100 / sizeof(kTestString1[0]), b2.Length());
b2.SetByteLen(lstrlen(b2) * sizeof(kTestString2[0]));
- EXPECT_EQ(b2.Length(), lstrlen(b2));
+ EXPECT_EQ(b2.Length(), static_cast<size_t>(lstrlen(b2)));
EXPECT_TRUE(b1.Allocate(kTestString2) != NULL);
EXPECT_EQ(test2_len, b1.Length());
diff --git a/chromium/base/win/scoped_co_mem.h b/chromium/base/win/scoped_co_mem.h
index fc85114828f..a3737dd571a 100644
--- a/chromium/base/win/scoped_co_mem.h
+++ b/chromium/base/win/scoped_co_mem.h
@@ -7,8 +7,8 @@
#include <objbase.h>
-#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/macros.h"
namespace base {
namespace win {
diff --git a/chromium/base/win/scoped_com_initializer.h b/chromium/base/win/scoped_com_initializer.h
index 92228baa507..8efff856f0c 100644
--- a/chromium/base/win/scoped_com_initializer.h
+++ b/chromium/base/win/scoped_com_initializer.h
@@ -7,8 +7,8 @@
#include <objbase.h>
-#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "build/build_config.h"
namespace base {
diff --git a/chromium/base/win/scoped_comptr.h b/chromium/base/win/scoped_comptr.h
index ade12fe549a..5ce60e2b688 100644
--- a/chromium/base/win/scoped_comptr.h
+++ b/chromium/base/win/scoped_comptr.h
@@ -43,8 +43,9 @@ class ScopedComPtr : public scoped_refptr<Interface> {
~ScopedComPtr() {
// We don't want the smart pointer class to be bigger than the pointer
// it wraps.
- COMPILE_ASSERT(sizeof(ScopedComPtr<Interface, interface_id>) ==
- sizeof(Interface*), ScopedComPtrSize);
+ static_assert(
+ sizeof(ScopedComPtr<Interface, interface_id>) == sizeof(Interface*),
+ "ScopedComPtrSize");
}
// Explicit Release() of the held object. Useful for reuse of the
diff --git a/chromium/base/win/scoped_gdi_object.h b/chromium/base/win/scoped_gdi_object.h
index 57b013e2fba..9d8465b25bd 100644
--- a/chromium/base/win/scoped_gdi_object.h
+++ b/chromium/base/win/scoped_gdi_object.h
@@ -7,64 +7,32 @@
#include <windows.h>
-#include "base/basictypes.h"
-#include "base/logging.h"
+#include "base/scoped_generic.h"
namespace base {
namespace win {
-// Like ScopedHandle but for GDI objects.
-template<class T>
-class ScopedGDIObject {
- public:
- ScopedGDIObject() : object_(NULL) {}
- explicit ScopedGDIObject(T object) : object_(object) {}
-
- ~ScopedGDIObject() {
- Close();
- }
-
- T Get() {
- return object_;
- }
-
- void Set(T object) {
- if (object_ && object != object_)
- Close();
- object_ = object;
- }
-
- ScopedGDIObject& operator=(T object) {
- Set(object);
- return *this;
- }
-
- T release() {
- T object = object_;
- object_ = NULL;
- return object;
- }
+namespace internal {
- operator T() { return object_; }
-
- private:
- void Close() {
- if (object_)
- DeleteObject(object_);
- }
-
- T object_;
- DISALLOW_COPY_AND_ASSIGN(ScopedGDIObject);
+template <class T>
+struct ScopedGDIObjectTraits {
+ static T InvalidValue() { return nullptr; }
+ static void Free(T object) { DeleteObject(object); }
};
// An explicit specialization for HICON because we have to call DestroyIcon()
// instead of DeleteObject() for HICON.
-template<>
-void inline ScopedGDIObject<HICON>::Close() {
- if (object_)
- DestroyIcon(object_);
+template <>
+void inline ScopedGDIObjectTraits<HICON>::Free(HICON icon) {
+ DestroyIcon(icon);
}
+} // namespace internal
+
+// Like ScopedHandle but for GDI objects.
+template <class T>
+using ScopedGDIObject = ScopedGeneric<T, internal::ScopedGDIObjectTraits<T>>;
+
// Typedefs for some common use cases.
typedef ScopedGDIObject<HBITMAP> ScopedBitmap;
typedef ScopedGDIObject<HRGN> ScopedRegion;
diff --git a/chromium/base/win/scoped_handle.cc b/chromium/base/win/scoped_handle.cc
index 2ebef320bb8..9c21603a0e8 100644
--- a/chromium/base/win/scoped_handle.cc
+++ b/chromium/base/win/scoped_handle.cc
@@ -4,12 +4,15 @@
#include "base/win/scoped_handle.h"
+#include <stddef.h>
+
#include <unordered_map>
#include "base/debug/alias.h"
#include "base/hash.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/synchronization/lock_impl.h"
extern "C" {
@@ -191,6 +194,9 @@ void ActiveVerifier::Disable() {
}
void ActiveVerifier::OnHandleBeingClosed(HANDLE handle) {
+ if (!enabled_)
+ return;
+
AutoNativeLock lock(*lock_);
if (closing_)
return;
diff --git a/chromium/base/win/scoped_handle.h b/chromium/base/win/scoped_handle.h
index d1eb1d688ae..404ab669385 100644
--- a/chromium/base/win/scoped_handle.h
+++ b/chromium/base/win/scoped_handle.h
@@ -8,9 +8,9 @@
#include <windows.h>
#include "base/base_export.h"
-#include "base/basictypes.h"
#include "base/location.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/move.h"
// TODO(rvargas): remove this with the rest of the verifier.
@@ -36,7 +36,7 @@ namespace win {
// this explicitly is necessary because of bug 528394 and VC++ 2015.
template <class Traits, class Verifier>
class GenericScopedHandle {
- MOVE_ONLY_TYPE_FOR_CPP_03(GenericScopedHandle, RValue)
+ MOVE_ONLY_TYPE_FOR_CPP_03(GenericScopedHandle)
public:
typedef typename Traits::Handle Handle;
@@ -47,9 +47,9 @@ class GenericScopedHandle {
Set(handle);
}
- // Move constructor for C++03 move emulation of this type.
- GenericScopedHandle(RValue other) : handle_(Traits::NullHandle()) {
- Set(other.object->Take());
+ GenericScopedHandle(GenericScopedHandle&& other)
+ : handle_(Traits::NullHandle()) {
+ Set(other.Take());
}
~GenericScopedHandle() {
@@ -60,11 +60,9 @@ class GenericScopedHandle {
return Traits::IsHandleValid(handle_);
}
- // Move operator= for C++03 move emulation of this type.
- GenericScopedHandle& operator=(RValue other) {
- if (this != other.object) {
- Set(other.object->Take());
- }
+ GenericScopedHandle& operator=(GenericScopedHandle&& other) {
+ DCHECK_NE(this, &other);
+ Set(other.Take());
return *this;
}
diff --git a/chromium/base/win/scoped_hdc.h b/chromium/base/win/scoped_hdc.h
index 2452067dfb3..fa686dd0500 100644
--- a/chromium/base/win/scoped_hdc.h
+++ b/chromium/base/win/scoped_hdc.h
@@ -7,8 +7,8 @@
#include <windows.h>
-#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/win/scoped_handle.h"
namespace base {
diff --git a/chromium/base/win/scoped_hglobal.h b/chromium/base/win/scoped_hglobal.h
index 185ccbd5f0c..abe9a5a3dd3 100644
--- a/chromium/base/win/scoped_hglobal.h
+++ b/chromium/base/win/scoped_hglobal.h
@@ -6,8 +6,9 @@
#define BASE_WIN_SCOPED_HGLOBAL_H_
#include <windows.h>
+#include <stddef.h>
-#include "base/basictypes.h"
+#include "base/macros.h"
namespace base {
namespace win {
diff --git a/chromium/base/win/scoped_process_information.h b/chromium/base/win/scoped_process_information.h
index 2e240544122..01df861f0e7 100644
--- a/chromium/base/win/scoped_process_information.h
+++ b/chromium/base/win/scoped_process_information.h
@@ -7,8 +7,8 @@
#include <windows.h>
-#include "base/basictypes.h"
#include "base/base_export.h"
+#include "base/macros.h"
#include "base/win/scoped_handle.h"
namespace base {
diff --git a/chromium/base/win/scoped_process_information_unittest.cc b/chromium/base/win/scoped_process_information_unittest.cc
index 614504d414e..799b273f0ed 100644
--- a/chromium/base/win/scoped_process_information_unittest.cc
+++ b/chromium/base/win/scoped_process_information_unittest.cc
@@ -80,7 +80,7 @@ TEST_F(ScopedProcessInformationTest, TakeProcess) {
HANDLE process = process_info.TakeProcessHandle();
EXPECT_EQ(kProcessHandle, process);
EXPECT_EQ(NULL, process_info.process_handle());
- EXPECT_EQ(0, process_info.process_id());
+ EXPECT_EQ(0u, process_info.process_id());
EXPECT_TRUE(process_info.IsValid());
process_info.Take();
}
@@ -92,7 +92,7 @@ TEST_F(ScopedProcessInformationTest, TakeThread) {
HANDLE thread = process_info.TakeThreadHandle();
EXPECT_EQ(kThreadHandle, thread);
EXPECT_EQ(NULL, process_info.thread_handle());
- EXPECT_EQ(0, process_info.thread_id());
+ EXPECT_EQ(0u, process_info.thread_id());
EXPECT_TRUE(process_info.IsValid());
process_info.Take();
}
diff --git a/chromium/base/win/scoped_propvariant.h b/chromium/base/win/scoped_propvariant.h
index 62cc6a6d152..aa9afec1c17 100644
--- a/chromium/base/win/scoped_propvariant.h
+++ b/chromium/base/win/scoped_propvariant.h
@@ -7,8 +7,8 @@
#include <propidl.h>
-#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/macros.h"
namespace base {
namespace win {
diff --git a/chromium/base/win/scoped_select_object.h b/chromium/base/win/scoped_select_object.h
index 347de798e28..59b21c1335d 100644
--- a/chromium/base/win/scoped_select_object.h
+++ b/chromium/base/win/scoped_select_object.h
@@ -7,8 +7,8 @@
#include <windows.h>
-#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/macros.h"
namespace base {
namespace win {
diff --git a/chromium/base/win/scoped_variant.cc b/chromium/base/win/scoped_variant.cc
index 2cf265740d8..0c1ee314864 100644
--- a/chromium/base/win/scoped_variant.cc
+++ b/chromium/base/win/scoped_variant.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "base/win/scoped_variant.h"
+
#include "base/logging.h"
namespace base {
@@ -12,7 +13,7 @@ namespace win {
const VARIANT ScopedVariant::kEmptyVariant = {{{VT_EMPTY}}};
ScopedVariant::~ScopedVariant() {
- COMPILE_ASSERT(sizeof(ScopedVariant) == sizeof(VARIANT), ScopedVariantSize);
+ static_assert(sizeof(ScopedVariant) == sizeof(VARIANT), "ScopedVariantSize");
::VariantClear(&var_);
}
@@ -117,49 +118,49 @@ void ScopedVariant::Set(const wchar_t* str) {
var_.bstrVal = ::SysAllocString(str);
}
-void ScopedVariant::Set(int8 i8) {
+void ScopedVariant::Set(int8_t i8) {
DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
var_.vt = VT_I1;
var_.cVal = i8;
}
-void ScopedVariant::Set(uint8 ui8) {
+void ScopedVariant::Set(uint8_t ui8) {
DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
var_.vt = VT_UI1;
var_.bVal = ui8;
}
-void ScopedVariant::Set(int16 i16) {
+void ScopedVariant::Set(int16_t i16) {
DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
var_.vt = VT_I2;
var_.iVal = i16;
}
-void ScopedVariant::Set(uint16 ui16) {
+void ScopedVariant::Set(uint16_t ui16) {
DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
var_.vt = VT_UI2;
var_.uiVal = ui16;
}
-void ScopedVariant::Set(int32 i32) {
+void ScopedVariant::Set(int32_t i32) {
DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
var_.vt = VT_I4;
var_.lVal = i32;
}
-void ScopedVariant::Set(uint32 ui32) {
+void ScopedVariant::Set(uint32_t ui32) {
DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
var_.vt = VT_UI4;
var_.ulVal = ui32;
}
-void ScopedVariant::Set(int64 i64) {
+void ScopedVariant::Set(int64_t i64) {
DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
var_.vt = VT_I8;
var_.llVal = i64;
}
-void ScopedVariant::Set(uint64 ui64) {
+void ScopedVariant::Set(uint64_t ui64) {
DCHECK(!IsLeakableVarType(var_.vt)) << "leaking variant: " << var_.vt;
var_.vt = VT_UI8;
var_.ullVal = ui64;
diff --git a/chromium/base/win/scoped_variant.h b/chromium/base/win/scoped_variant.h
index 322fcf71e55..16d43f99b6c 100644
--- a/chromium/base/win/scoped_variant.h
+++ b/chromium/base/win/scoped_variant.h
@@ -7,9 +7,10 @@
#include <windows.h>
#include <oleauto.h>
+#include <stdint.h>
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
namespace base {
namespace win {
@@ -90,14 +91,14 @@ class BASE_EXPORT ScopedVariant {
void Set(const wchar_t* str);
// Setters for simple types.
- void Set(int8 i8);
- void Set(uint8 ui8);
- void Set(int16 i16);
- void Set(uint16 ui16);
- void Set(int32 i32);
- void Set(uint32 ui32);
- void Set(int64 i64);
- void Set(uint64 ui64);
+ void Set(int8_t i8);
+ void Set(uint8_t ui8);
+ void Set(int16_t i16);
+ void Set(uint16_t ui16);
+ void Set(int32_t i32);
+ void Set(uint32_t ui32);
+ void Set(int64_t i64);
+ void Set(uint64_t ui64);
void Set(float r32);
void Set(double r64);
void Set(bool b);
diff --git a/chromium/base/win/scoped_variant_unittest.cc b/chromium/base/win/scoped_variant_unittest.cc
index d530d5bcd91..7d61e2859b8 100644
--- a/chromium/base/win/scoped_variant_unittest.cc
+++ b/chromium/base/win/scoped_variant_unittest.cc
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <stdint.h>
+
#include "base/win/scoped_variant.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -126,7 +128,7 @@ TEST(ScopedVariantTest, ScopedVariant) {
// need to be freed explicitly).
// We need static cast here since char defaults to int (!?).
- var.Set(static_cast<int8>('v'));
+ var.Set(static_cast<int8_t>('v'));
EXPECT_EQ(VT_I1, var.type());
EXPECT_EQ('v', V_I1(var.ptr()));
@@ -134,29 +136,29 @@ TEST(ScopedVariantTest, ScopedVariant) {
EXPECT_EQ(VT_I2, var.type());
EXPECT_EQ(123, V_I2(var.ptr()));
- var.Set(static_cast<int32>(123));
+ var.Set(static_cast<int32_t>(123));
EXPECT_EQ(VT_I4, var.type());
EXPECT_EQ(123, V_I4(var.ptr()));
- var.Set(static_cast<int64>(123));
+ var.Set(static_cast<int64_t>(123));
EXPECT_EQ(VT_I8, var.type());
EXPECT_EQ(123, V_I8(var.ptr()));
- var.Set(static_cast<uint8>(123));
+ var.Set(static_cast<uint8_t>(123));
EXPECT_EQ(VT_UI1, var.type());
- EXPECT_EQ(123, V_UI1(var.ptr()));
+ EXPECT_EQ(123u, V_UI1(var.ptr()));
var.Set(static_cast<unsigned short>(123));
EXPECT_EQ(VT_UI2, var.type());
- EXPECT_EQ(123, V_UI2(var.ptr()));
+ EXPECT_EQ(123u, V_UI2(var.ptr()));
- var.Set(static_cast<uint32>(123));
+ var.Set(static_cast<uint32_t>(123));
EXPECT_EQ(VT_UI4, var.type());
- EXPECT_EQ(123, V_UI4(var.ptr()));
+ EXPECT_EQ(123u, V_UI4(var.ptr()));
- var.Set(static_cast<uint64>(123));
+ var.Set(static_cast<uint64_t>(123));
EXPECT_EQ(VT_UI8, var.type());
- EXPECT_EQ(123, V_UI8(var.ptr()));
+ EXPECT_EQ(123u, V_UI8(var.ptr()));
var.Set(123.123f);
EXPECT_EQ(VT_R4, var.type());
diff --git a/chromium/base/win/shortcut.cc b/chromium/base/win/shortcut.cc
index 2dd01a83d9e..5621b94a539 100644
--- a/chromium/base/win/shortcut.cc
+++ b/chromium/base/win/shortcut.cc
@@ -5,18 +5,13 @@
#include "base/win/shortcut.h"
#include <shellapi.h>
-#include <shldisp.h>
#include <shlobj.h>
#include <propkey.h>
#include "base/files/file_util.h"
-#include "base/strings/string_util.h"
#include "base/threading/thread_restrictions.h"
-#include "base/win/scoped_bstr.h"
#include "base/win/scoped_comptr.h"
-#include "base/win/scoped_handle.h"
#include "base/win/scoped_propvariant.h"
-#include "base/win/scoped_variant.h"
#include "base/win/win_util.h"
#include "base/win/windows_version.h"
@@ -25,92 +20,6 @@ namespace win {
namespace {
-// String resource IDs in shell32.dll.
-const uint32_t kPinToTaskbarID = 5386; // Win7+
-const uint32_t kUnpinFromTaskbarID = 5387; // Win7+
-const uint32_t kPinToStartID = 51201; // Win8+
-const uint32_t kUnpinFromStartID = 51394; // Win10+
-
-// Traits for a GenericScopedHandle that will free a module on closure.
-struct ModuleTraits {
- typedef HMODULE Handle;
- static Handle NullHandle() { return nullptr; }
- static bool IsHandleValid(Handle module) { return !!module; }
- static bool CloseHandle(Handle module) { return !!::FreeLibrary(module); }
-
- private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(ModuleTraits);
-};
-
-// An object that will free a module when it goes out of scope.
-using ScopedLibrary = GenericScopedHandle<ModuleTraits, DummyVerifierTraits>;
-
-// Returns the shell resource string identified by |resource_id|, or an empty
-// string on error.
-string16 LoadShellResourceString(uint32_t resource_id) {
- ScopedLibrary shell32(::LoadLibrary(L"shell32.dll"));
- if (!shell32.IsValid())
- return string16();
-
- const wchar_t* resource_ptr = nullptr;
- int length = ::LoadStringW(shell32.Get(), resource_id,
- reinterpret_cast<wchar_t*>(&resource_ptr), 0);
- if (!length || !resource_ptr)
- return string16();
- return string16(resource_ptr, length);
-}
-
-// Uses the shell to perform the verb identified by |resource_id| on |path|.
-bool DoVerbOnFile(uint32_t resource_id, const FilePath& path) {
- string16 verb_name(LoadShellResourceString(resource_id));
- if (verb_name.empty())
- return false;
-
- ScopedComPtr<IShellDispatch> shell_dispatch;
- HRESULT hresult =
- shell_dispatch.CreateInstance(CLSID_Shell, nullptr, CLSCTX_INPROC_SERVER);
- if (FAILED(hresult) || !shell_dispatch.get())
- return false;
-
- ScopedComPtr<Folder> folder;
- hresult = shell_dispatch->NameSpace(
- ScopedVariant(path.DirName().value().c_str()), folder.Receive());
- if (FAILED(hresult) || !folder.get())
- return false;
-
- ScopedComPtr<FolderItem> item;
- hresult = folder->ParseName(ScopedBstr(path.BaseName().value().c_str()),
- item.Receive());
- if (FAILED(hresult) || !item.get())
- return false;
-
- ScopedComPtr<FolderItemVerbs> verbs;
- hresult = item->Verbs(verbs.Receive());
- if (FAILED(hresult) || !verbs.get())
- return false;
-
- long verb_count = 0;
- hresult = verbs->get_Count(&verb_count);
- if (FAILED(hresult))
- return false;
-
- for (long i = 0; i < verb_count; ++i) {
- ScopedComPtr<FolderItemVerb> verb;
- hresult = verbs->Item(ScopedVariant(i, VT_I4), verb.Receive());
- if (FAILED(hresult) || !verb.get())
- continue;
- ScopedBstr name;
- hresult = verb->get_Name(name.Receive());
- if (FAILED(hresult))
- continue;
- if (StringPiece16(name, name.Length()) == verb_name) {
- hresult = verb->DoIt();
- return SUCCEEDED(hresult);
- }
- }
- return false;
-}
-
// Initializes |i_shell_link| and |i_persist_file| (releasing them first if they
// are already initialized).
// If |shortcut| is not NULL, loads |shortcut| into |i_persist_file|.
@@ -274,7 +183,7 @@ bool CreateOrUpdateShortcutLink(const FilePath& shortcut_path,
}
bool ResolveShortcutProperties(const FilePath& shortcut_path,
- uint32 options,
+ uint32_t options,
ShortcutProperties* properties) {
DCHECK(options && properties);
base::ThreadRestrictions::AssertIOAllowed();
@@ -387,7 +296,7 @@ bool ResolveShortcutProperties(const FilePath& shortcut_path,
bool ResolveShortcut(const FilePath& shortcut_path,
FilePath* target_path,
string16* args) {
- uint32 options = 0;
+ uint32_t options = 0;
if (target_path)
options |= ShortcutProperties::PROPERTIES_TARGET;
if (args)
@@ -405,49 +314,32 @@ bool ResolveShortcut(const FilePath& shortcut_path,
return true;
}
+bool CanPinShortcutToTaskbar() {
+ // "Pin to taskbar" appeared in Windows 7 and stopped being supported in
+ // Windows 10.
+ return GetVersion() >= VERSION_WIN7 && GetVersion() < VERSION_WIN10;
+}
+
bool PinShortcutToTaskbar(const FilePath& shortcut) {
base::ThreadRestrictions::AssertIOAllowed();
+ DCHECK(CanPinShortcutToTaskbar());
- // "Pin to taskbar" is only supported after Win7.
- if (GetVersion() < VERSION_WIN7)
- return false;
-
- return DoVerbOnFile(kPinToTaskbarID, shortcut);
+ intptr_t result = reinterpret_cast<intptr_t>(ShellExecute(
+ NULL, L"taskbarpin", shortcut.value().c_str(), NULL, NULL, 0));
+ return result > 32;
}
bool UnpinShortcutFromTaskbar(const FilePath& shortcut) {
base::ThreadRestrictions::AssertIOAllowed();
- // "Unpin from taskbar" is only supported after Win7.
+ // "Unpin from taskbar" is only supported after Win7. It is possible to remove
+ // a shortcut pinned by a user on Windows 10+.
if (GetVersion() < VERSION_WIN7)
return false;
- return DoVerbOnFile(kUnpinFromTaskbarID, shortcut);
-}
-
-bool PinShortcutToStart(const FilePath& shortcut) {
- base::ThreadRestrictions::AssertIOAllowed();
-
- // While "Pin to Start" is supported as of Win8, it was never used by Chrome
- // in Win8. The behaviour on Win8 is different (new shortcut every time
- // instead of a single pin associated with its app id) and the Start Menu
- // shortcut itself is visible on the Start Screen whereas it is not on Win10.
- // For simplicity's sake and per greater necessity on Win10, it is only
- // supported in Chrome on Win10+.
- if (GetVersion() < VERSION_WIN10)
- return false;
-
- return DoVerbOnFile(kPinToStartID, shortcut);
-}
-
-bool UnpinShortcutFromStart(const FilePath& shortcut) {
- base::ThreadRestrictions::AssertIOAllowed();
-
- // "Unpin from Start Menu" is only supported after Win10.
- if (GetVersion() < VERSION_WIN10)
- return false;
-
- return DoVerbOnFile(kUnpinFromStartID, shortcut);
+ intptr_t result = reinterpret_cast<intptr_t>(ShellExecute(
+ NULL, L"taskbarunpin", shortcut.value().c_str(), NULL, NULL, 0));
+ return result > 32;
}
} // namespace win
diff --git a/chromium/base/win/shortcut.h b/chromium/base/win/shortcut.h
index 4ff2912afeb..c592b28f87e 100644
--- a/chromium/base/win/shortcut.h
+++ b/chromium/base/win/shortcut.h
@@ -6,6 +6,7 @@
#define BASE_WIN_SHORTCUT_H_
#include <windows.h>
+#include <stdint.h>
#include "base/base_export.h"
#include "base/files/file_path.h"
@@ -113,7 +114,7 @@ struct BASE_EXPORT ShortcutProperties {
bool dual_mode;
// Bitfield made of IndividualProperties. Properties set in |options| will be
// set on the shortcut, others will be ignored.
- uint32 options;
+ uint32_t options;
};
// This method creates (or updates) a shortcut link at |shortcut_path| using the
@@ -138,7 +139,7 @@ BASE_EXPORT bool CreateOrUpdateShortcutLink(
// properties are successfully read. Otherwise some reads have failed and
// intermediate values written to |properties| should be ignored.
BASE_EXPORT bool ResolveShortcutProperties(const FilePath& shortcut_path,
- uint32 options,
+ uint32_t options,
ShortcutProperties* properties);
// Resolves Windows shortcut (.LNK file).
@@ -152,9 +153,13 @@ BASE_EXPORT bool ResolveShortcut(const FilePath& shortcut_path,
FilePath* target_path,
string16* args);
-// Pins a shortcut to the Windows 7+ taskbar. The |shortcut| file must already
-// exist and be a shortcut that points to an executable. The app id of the
-// shortcut is used to group windows and must be set correctly.
+// Pin to taskbar is only supported on Windows 7 and Windows 8. Returns true on
+// those platforms.
+BASE_EXPORT bool CanPinShortcutToTaskbar();
+
+// Pins a shortcut to the taskbar on Windows 7 and 8. The |shortcut| file must
+// already exist and be a shortcut that points to an executable. The app id of
+// the shortcut is used to group windows and must be set correctly.
BASE_EXPORT bool PinShortcutToTaskbar(const FilePath& shortcut);
// Unpins a shortcut from the Windows 7+ taskbar. The |shortcut| must exist and
@@ -162,20 +167,6 @@ BASE_EXPORT bool PinShortcutToTaskbar(const FilePath& shortcut);
// identifier for the taskbar item to remove and must be set correctly.
BASE_EXPORT bool UnpinShortcutFromTaskbar(const FilePath& shortcut);
-// Pins a shortcut to the Windows 10+ start menu. The |shortcut| file must
-// already exist and be a shortcut that points to an executable. The app id of
-// the shortcut is used as an identifier by the shell to know that all shortcuts
-// with this app id point to this pin (i.e. "Unpin" instead of "Pin" in those
-// shortcuts' context menus). Unpinning is unecessary on uninstall as Windows
-// handles getting rid of stale Start pins.
-BASE_EXPORT bool PinShortcutToStart(const FilePath& shortcut);
-
-// Unpins a shortcut from the Windows 10+ start menu. The |shortcut| must exist
-// and already be pinned to the start menu. The app id of the shortcut is used
-// as the identifier for the start menu item to remove and must be set
-// correctly.
-BASE_EXPORT bool UnpinShortcutFromStart(const FilePath& shortcut);
-
} // namespace win
} // namespace base
diff --git a/chromium/base/win/shortcut_unittest.cc b/chromium/base/win/shortcut_unittest.cc
index 794be2364f4..c1ebcf185c2 100644
--- a/chromium/base/win/shortcut_unittest.cc
+++ b/chromium/base/win/shortcut_unittest.cc
@@ -4,11 +4,14 @@
#include "base/win/shortcut.h"
+#include <stdint.h>
+
#include <string>
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
+#include "base/macros.h"
#include "base/test/test_file_util.h"
#include "base/test/test_shortcut_win.h"
#include "base/win/scoped_com_initializer.h"
@@ -80,7 +83,7 @@ class ShortcutTest : public testing::Test {
} // namespace
TEST_F(ShortcutTest, CreateAndResolveShortcutProperties) {
- uint32 valid_properties = ShortcutProperties::PROPERTIES_BASIC;
+ uint32_t valid_properties = ShortcutProperties::PROPERTIES_BASIC;
if (GetVersion() >= VERSION_WIN7)
valid_properties |= ShortcutProperties::PROPERTIES_WIN7;
diff --git a/chromium/base/win/startup_information.h b/chromium/base/win/startup_information.h
index 3f18ee58efb..5b777baefe1 100644
--- a/chromium/base/win/startup_information.h
+++ b/chromium/base/win/startup_information.h
@@ -6,9 +6,10 @@
#define BASE_WIN_STARTUP_INFORMATION_H_
#include <windows.h>
+#include <stddef.h>
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
namespace base {
namespace win {
@@ -31,7 +32,7 @@ class BASE_EXPORT StartupInformation {
size_t size);
LPSTARTUPINFOW startup_info() { return &startup_info_.StartupInfo; }
- const LPSTARTUPINFOW startup_info() const {
+ LPSTARTUPINFOW startup_info() const {
return const_cast<const LPSTARTUPINFOW>(&startup_info_.StartupInfo);
}
diff --git a/chromium/base/win/startup_information_unittest.cc b/chromium/base/win/startup_information_unittest.cc
index 36c6e848c66..5002a22ca83 100644
--- a/chromium/base/win/startup_information_unittest.cc
+++ b/chromium/base/win/startup_information_unittest.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include <windows.h>
+#include <stddef.h>
#include <string>
diff --git a/chromium/base/win/win_util.cc b/chromium/base/win/win_util.cc
index 98d451f9cc7..57bee8a57a7 100644
--- a/chromium/base/win/win_util.cc
+++ b/chromium/base/win/win_util.cc
@@ -17,18 +17,19 @@
#include <sddl.h>
#include <setupapi.h>
#include <signal.h>
+#include <stddef.h>
#include <stdlib.h>
#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_restrictions.h"
-#include "base/win/metro.h"
#include "base/win/registry.h"
#include "base/win/scoped_co_mem.h"
#include "base/win/scoped_handle.h"
@@ -99,6 +100,12 @@ const wchar_t kWindows8OSKRegPath[] =
L"Software\\Classes\\CLSID\\{054AAE20-4BEA-4347-8A35-64A533254A9D}"
L"\\LocalServer32";
+// Returns the current platform role. We use the PowerDeterminePlatformRoleEx
+// API for that.
+POWER_PLATFORM_ROLE GetPlatformRole() {
+ return PowerDeterminePlatformRoleEx(POWER_PLATFORM_ROLE_V2);
+}
+
} // namespace
// Returns true if a physical keyboard is detected on Windows 8 and up.
@@ -109,7 +116,7 @@ const wchar_t kWindows8OSKRegPath[] =
bool IsKeyboardPresentOnSlate(std::string* reason) {
bool result = false;
- if (GetVersion() < VERSION_WIN7) {
+ if (GetVersion() < VERSION_WIN8) {
*reason = "Detection not supported";
return false;
}
@@ -133,10 +140,13 @@ bool IsKeyboardPresentOnSlate(std::string* reason) {
}
}
- // If the device is docked, the user is treating the device as a PC.
- if (GetSystemMetrics(SM_SYSTEMDOCKED) != 0) {
+ if (IsTabletDevice(reason)) {
+ if (reason)
+ *reason += "Tablet device.\n";
+ return true;
+ } else {
if (reason) {
- *reason += "SM_SYSTEMDOCKED\n";
+ *reason += "Not a tablet device";
result = true;
} else {
return true;
@@ -182,23 +192,6 @@ bool IsKeyboardPresentOnSlate(std::string* reason) {
}
}
- // 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)) {
- if (reason) {
- *reason += (role == PlatformRoleMobile) ? "PlatformRoleMobile\n" :
- "PlatformRoleSlate\n";
- // Don't change result here if it's already true.
- } else {
- return false;
- }
- }
-
const GUID KEYBOARD_CLASS_GUID =
{ 0x4D36E96B, 0xE325, 0x11CE,
{ 0xBF, 0xC1, 0x08, 0x00, 0x2B, 0xE1, 0x03, 0x18 } };
@@ -290,23 +283,6 @@ bool GetUserSidString(std::wstring* user_sid) {
return true;
}
-bool IsShiftPressed() {
- return (::GetKeyState(VK_SHIFT) & 0x8000) == 0x8000;
-}
-
-bool IsCtrlPressed() {
- return (::GetKeyState(VK_CONTROL) & 0x8000) == 0x8000;
-}
-
-bool IsAltPressed() {
- return (::GetKeyState(VK_MENU) & 0x8000) == 0x8000;
-}
-
-bool IsAltGrPressed() {
- return (::GetKeyState(VK_MENU) & 0x8000) == 0x8000 &&
- (::GetKeyState(VK_CONTROL) & 0x8000) == 0x8000;
-}
-
bool UserAccountControlIsEnabled() {
// This can be slow if Windows ends up going to disk. Should watch this key
// for changes and only read it once, preferably on the file thread.
@@ -407,30 +383,56 @@ void SetAbortBehaviorForCrashReporting() {
signal(SIGABRT, ForceCrashOnSigAbort);
}
-bool IsTabletDevice() {
- if (GetSystemMetrics(SM_MAXIMUMTOUCHES) == 0)
+bool IsTabletDevice(std::string* reason) {
+ if (GetVersion() < VERSION_WIN8) {
+ if (reason)
+ *reason = "Tablet device detection not supported below Windows 8\n";
return false;
+ }
- Version version = GetVersion();
- if (version == VERSION_XP)
- return (GetSystemMetrics(SM_TABLETPC) != 0);
+ if (GetSystemMetrics(SM_MAXIMUMTOUCHES) == 0) {
+ if (reason) {
+ *reason += "Device does not support touch.\n";
+ } else {
+ return false;
+ }
+ }
// If the device is docked, the user is treating the device as a PC.
- if (GetSystemMetrics(SM_SYSTEMDOCKED) != 0)
- return false;
+ if (GetSystemMetrics(SM_SYSTEMDOCKED) != 0) {
+ if (reason) {
+ *reason += "SM_SYSTEMDOCKED\n";
+ } else {
+ return false;
+ }
+ }
- // PlatformRoleSlate was only added in Windows 8, but prior to Win8 it is
- // still possible to check for a mobile power profile.
- POWER_PLATFORM_ROLE role = PowerDeterminePlatformRole();
+ // PlatformRoleSlate was added in Windows 8+.
+ POWER_PLATFORM_ROLE role = GetPlatformRole();
bool mobile_power_profile = (role == PlatformRoleMobile);
- bool slate_power_profile = false;
- if (version >= VERSION_WIN8)
- slate_power_profile = (role == PlatformRoleSlate);
+ bool slate_power_profile = (role == PlatformRoleSlate);
- if (mobile_power_profile || slate_power_profile)
- return (GetSystemMetrics(SM_CONVERTIBLESLATEMODE) == 0);
+ bool is_tablet = false;
- return false;
+ if (mobile_power_profile || slate_power_profile) {
+ is_tablet = !GetSystemMetrics(SM_CONVERTIBLESLATEMODE);
+ if (!is_tablet) {
+ if (reason) {
+ *reason += "Not in slate mode.\n";
+ } else {
+ return false;
+ }
+ } else {
+ if (reason) {
+ *reason += (role == PlatformRoleMobile) ? "PlatformRoleMobile\n" :
+ "PlatformRoleSlate\n";
+ }
+ }
+ } else {
+ if (reason)
+ *reason += "Device role is not mobile or slate.\n";
+ }
+ return is_tablet;
}
bool DisplayVirtualKeyboard() {
@@ -529,8 +531,6 @@ bool DismissVirtualKeyboard() {
return false;
}
-typedef HWND (*MetroRootWindow) ();
-
enum DomainEnrollementState {UNKNOWN = -1, NOT_ENROLLED, ENROLLED};
static volatile long int g_domain_state = UNKNOWN;
diff --git a/chromium/base/win/win_util.h b/chromium/base/win/win_util.h
index 3c900ff9b0a..6162b51bb03 100644
--- a/chromium/base/win/win_util.h
+++ b/chromium/base/win/win_util.h
@@ -23,6 +23,7 @@
#define BASE_WIN_WIN_UTIL_H_
#include <windows.h>
+#include <stdint.h>
#include <string>
@@ -56,25 +57,19 @@ struct NONCLIENTMETRICS_XP {
namespace base {
namespace win {
+inline uint32_t HandleToUint32(HANDLE h) {
+ // Cast through uintptr_t and then unsigned int to make the truncation to
+ // 32 bits explicit. Handles are size of-pointer but are always 32-bit values.
+ // https://msdn.microsoft.com/en-us/library/aa384203(VS.85).aspx says:
+ // 64-bit versions of Windows use 32-bit handles for interoperability.
+ return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(h));
+}
+
BASE_EXPORT void GetNonClientMetrics(NONCLIENTMETRICS_XP* metrics);
// Returns the string representing the current user sid.
BASE_EXPORT bool GetUserSidString(std::wstring* user_sid);
-// Returns true if the shift key is currently pressed.
-BASE_EXPORT bool IsShiftPressed();
-
-// Returns true if the ctrl key is currently pressed.
-BASE_EXPORT bool IsCtrlPressed();
-
-// Returns true if the alt key is currently pressed.
-BASE_EXPORT bool IsAltPressed();
-
-// Returns true if the altgr key is currently pressed.
-// Windows does not have specific key code and modifier bit and Alt+Ctrl key is
-// used as AltGr key in Windows.
-BASE_EXPORT bool IsAltGrPressed();
-
// Returns false if user account control (UAC) has been disabled with the
// EnableLUA registry flag. Returns true if user account control is enabled.
// NOTE: The EnableLUA registry flag, which is ignored on Windows XP
@@ -128,9 +123,14 @@ BASE_EXPORT bool ShouldCrashOnProcessDetach();
BASE_EXPORT void SetAbortBehaviorForCrashReporting();
// A tablet is a device that is touch enabled and also is being used
-// "like a tablet". This is used primarily for metrics in order to gain some
-// insight into how users use Chrome.
-BASE_EXPORT bool IsTabletDevice();
+// "like a tablet". This is used by the following:-
+// 1. Metrics:- To gain insight into how users use Chrome.
+// 2. Physical keyboard presence :- If a device is in tablet mode, it means
+// that there is no physical keyboard attached.
+// This function optionally sets the |reason| parameter to determine as to why
+// or why not a device was deemed to be a tablet.
+// Returns true if the device is in tablet mode.
+BASE_EXPORT bool IsTabletDevice(std::string* reason);
// A slate is a touch device that may have a keyboard attached. This function
// returns true if a keyboard is attached and optionally will set the reason
diff --git a/chromium/base/win/win_util_unittest.cc b/chromium/base/win/win_util_unittest.cc
index 24141cd68a0..c121d7cd13a 100644
--- a/chromium/base/win/win_util_unittest.cc
+++ b/chromium/base/win/win_util_unittest.cc
@@ -4,7 +4,7 @@
#include <windows.h>
-#include "base/basictypes.h"
+#include "base/macros.h"
#include "base/strings/string_util.h"
#include "base/win/win_util.h"
#include "base/win/windows_version.h"
diff --git a/chromium/base/win/windows_version.h b/chromium/base/win/windows_version.h
index a52e64e0742..c9bbd4f3eb7 100644
--- a/chromium/base/win/windows_version.h
+++ b/chromium/base/win/windows_version.h
@@ -5,10 +5,12 @@
#ifndef BASE_WIN_WINDOWS_VERSION_H_
#define BASE_WIN_WINDOWS_VERSION_H_
+#include <stddef.h>
+
#include <string>
#include "base/base_export.h"
-#include "base/basictypes.h"
+#include "base/macros.h"
typedef void* HANDLE;