summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xCMakeLists.txt77
-rwxr-xr-xLICENSE27
-rw-r--r--NOTICE3
-rw-r--r--base/OWNERS6
-rw-r--r--base/atomic_ref_count.h81
-rw-r--r--base/atomic_sequence_num.h31
-rw-r--r--base/atomicops.h150
-rw-r--r--base/atomicops_internals_arm_gcc.h125
-rw-r--r--base/atomicops_internals_atomicword_compat.h101
-rw-r--r--base/atomicops_internals_x86_gcc.cc104
-rw-r--r--base/atomicops_internals_x86_gcc.h270
-rw-r--r--base/atomicops_internals_x86_macosx.h198
-rw-r--r--base/atomicops_internals_x86_msvc.h181
-rw-r--r--base/base_export.h26
-rw-r--r--base/basictypes.h367
-rw-r--r--base/compiler_specific.h140
-rw-r--r--base/file_descriptor_posix.h46
-rw-r--r--base/hash_tables.h120
-rw-r--r--base/logging.h952
-rw-r--r--base/memory/ref_counted.cc95
-rw-r--r--base/memory/ref_counted.h299
-rw-r--r--base/memory/ref_counted_memory.cc72
-rw-r--r--base/memory/ref_counted_memory.h119
-rw-r--r--base/memory/ref_counted_memory_unittest.cc45
-rw-r--r--base/memory/ref_counted_unittest.cc36
-rw-r--r--base/pickle.cc449
-rw-r--r--base/pickle.h249
-rw-r--r--base/platform_file_posix.cc200
-rw-r--r--base/port.h55
-rw-r--r--base/string16.cc80
-rw-r--r--base/string16.h178
-rw-r--r--base/string_number_conversions.cc545
-rw-r--r--base/string_number_conversions.h124
-rw-r--r--base/string_piece.cc214
-rw-r--r--base/string_piece.h349
-rw-r--r--base/synchronization/lock.h132
-rw-r--r--base/synchronization/lock_impl.h64
-rw-r--r--base/synchronization/waitable_event.h181
-rw-r--r--base/template_util.h109
-rw-r--r--base/third_party/dynamic_annotations/LICENSE28
-rw-r--r--base/third_party/dynamic_annotations/README.chromium11
-rw-r--r--base/third_party/dynamic_annotations/dynamic_annotations.c257
-rw-r--r--base/third_party/dynamic_annotations/dynamic_annotations.gyp45
-rw-r--r--base/third_party/dynamic_annotations/dynamic_annotations.h595
-rw-r--r--base/threading/platform_thread.h115
-rw-r--r--base/threading/platform_thread_posix.cc262
-rw-r--r--base/threading/thread.cc177
-rw-r--r--base/threading/thread.h191
-rw-r--r--base/threading/thread_collision_warner.cc64
-rw-r--r--base/threading/thread_collision_warner.h244
-rw-r--r--base/time.h566
-rw-r--r--base/tuple.h1056
-rw-r--r--base/values.cc905
-rw-r--r--base/values.h470
-rw-r--r--build/build_config.h151
-rw-r--r--chromium.manifest5
-rwxr-xr-xchromium.pc.in14
-rw-r--r--ipc/OWNERS7
-rw-r--r--ipc/file_descriptor_set_posix.cc136
-rw-r--r--ipc/file_descriptor_set_posix.h117
-rw-r--r--ipc/file_descriptor_set_posix_unittest.cc179
-rw-r--r--ipc/ipc.gyp90
-rw-r--r--ipc/ipc.gypi109
-rw-r--r--ipc/ipc_channel.h204
-rw-r--r--ipc/ipc_channel_handle.h52
-rw-r--r--ipc/ipc_channel_posix.cc1217
-rw-r--r--ipc/ipc_channel_posix.h161
-rw-r--r--ipc/ipc_channel_posix_unittest.cc389
-rw-r--r--ipc/ipc_channel_proxy.cc397
-rw-r--r--ipc/ipc_channel_proxy.h272
-rw-r--r--ipc/ipc_channel_win.cc430
-rw-r--r--ipc/ipc_channel_win.h91
-rw-r--r--ipc/ipc_descriptors.h15
-rw-r--r--ipc/ipc_export.h29
-rw-r--r--ipc/ipc_logging.cc251
-rw-r--r--ipc/ipc_logging.h112
-rw-r--r--ipc/ipc_message.cc128
-rw-r--r--ipc/ipc_message.h284
-rw-r--r--ipc/ipc_message_macros.h822
-rw-r--r--ipc/ipc_message_null_macros.h29
-rw-r--r--ipc/ipc_message_utils.cc485
-rwxr-xr-xipc/ipc_message_utils.h1238
-rw-r--r--ipc/ipc_message_utils_impl.h61
-rw-r--r--ipc/ipc_param_traits.h24
-rw-r--r--ipc/ipc_platform_file.cc43
-rw-r--r--ipc/ipc_platform_file.h51
-rw-r--r--ipc/ipc_switches.cc24
-rw-r--r--ipc/ipc_switches.h20
-rw-r--r--ipc/ipc_sync_channel.cc513
-rw-r--r--ipc/ipc_sync_channel.h200
-rw-r--r--ipc/ipc_sync_message.cc130
-rw-r--r--ipc/ipc_sync_message.h109
-rw-r--r--ipc/ipc_sync_message_filter.cc127
-rw-r--r--ipc/ipc_sync_message_filter.h70
-rw-r--r--ipc/param_traits_log_macros.h52
-rw-r--r--ipc/param_traits_macros.h39
-rw-r--r--ipc/param_traits_read_macros.h45
-rw-r--r--ipc/param_traits_write_macros.h38
-rw-r--r--ipc/struct_constructor_macros.h20
-rw-r--r--ipc/struct_destructor_macros.h16
-rw-r--r--ipc/sync_socket_unittest.cc250
-rw-r--r--log.h26
-rwxr-xr-xpackaging/chromium.spec54
103 files changed, 20912 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100755
index 000000000000..948b61fa490a
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,77 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+
+PROJECT(chromium)
+
+SET(CMAKE_INSTALL_PREFIX /usr)
+SET(PREFIX ${CMAKE_INSTALL_PREFIX})
+
+SET(LIBRARY_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/cmake_build_tmp/output)
+set(MODULE_DIR ${CMAKE_SOURCE_DIR})
+
+SET (${PROJECT_NAME}_SOURCE_FILES
+ ${MODULE_DIR}/base/pickle.cc
+ ${MODULE_DIR}/ipc/ipc_message.cc
+ ${MODULE_DIR}/ipc/ipc_message_utils.cc
+ ${MODULE_DIR}/ipc/ipc_sync_message.cc
+ )
+
+LIST (APPEND SRCS ${${PROJECT_NAME}_SOURCE_FILES})
+
+INCLUDE_DIRECTORIES(
+ ${MODULE_DIR}
+)
+
+add_library(${PROJECT_NAME} SHARED ${SRCS})
+
+#FIND_LIBRARY(MYAPILIB NAMES pthread PATHS /usr/lib)
+
+SET(CMAKE_C_FLAGS "${OSP_DEBUG_FLAGS} ${OSP_OPT_FLAGS} ${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} ${OSP_COMPILER_FLAGS}")
+SET(CMAKE_CXX_FLAGS "${OSP_DEBUG_FLAGS} ${OSP_OPT_FLAGS} ${CMAKE_CXX_FLAGS} ${EXTRA_CFLAGS} ${OSP_COMPILER_FLAGS}")
+
+
+SET_TARGET_PROPERTIES(${PROJECT_NAME}
+ PROPERTIES
+ VERSION ${FULLVER}
+ SOVERSION ${MAJORVER}
+ CLEAN_DIRECT_OUTPUT 1
+ )
+
+SET(PC_NAME ${PROJECT_NAME})
+SET(PC_REQUIRED ${pc_requires})
+SET(PC_LDFLAGS -l${PROJECT_NAME})
+
+CONFIGURE_FILE(
+ chromium.pc.in
+ ${CMAKE_SOURCE_DIR}/${PROJECT_NAME}.pc
+ @ONLY
+)
+
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/${PROJECT_NAME}.pc DESTINATION lib/pkgconfig)
+INSTALL(TARGETS ${PROJECT_NAME} DESTINATION lib)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/log.h DESTINATION include/${PROJECT_NAME})
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/base/atomic_ref_count.h DESTINATION include/${PROJECT_NAME}/base)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/base/atomicops.h DESTINATION include/${PROJECT_NAME}/base)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/base/atomicops_internals_arm_gcc.h DESTINATION include/${PROJECT_NAME}/base)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/base/atomicops_internals_atomicword_compat.h DESTINATION include/${PROJECT_NAME}/base)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/base/atomicops_internals_x86_gcc.h DESTINATION include/${PROJECT_NAME}/base)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/base/atomicops_internals_x86_macosx.h DESTINATION include/${PROJECT_NAME}/base)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/base/atomicops_internals_x86_msvc.h DESTINATION include/${PROJECT_NAME}/base)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/base/basictypes.h DESTINATION include/${PROJECT_NAME}/base)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/base/base_export.h DESTINATION include/${PROJECT_NAME}/base)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/base/compiler_specific.h DESTINATION include/${PROJECT_NAME}/base)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/base/file_descriptor_posix.h DESTINATION include/${PROJECT_NAME}/base)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/base/memory/ref_counted.h DESTINATION include/${PROJECT_NAME}/base/memory)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/base/third_party/dynamic_annotations/dynamic_annotations.h DESTINATION include/${PROJECT_NAME}/base/third_party/dynamic_annotations)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/base/threading/thread_collision_warner.h DESTINATION include/${PROJECT_NAME}/base/threading)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/base/hash_tables.h DESTINATION include/${PROJECT_NAME}/base)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/base/logging.h DESTINATION include/${PROJECT_NAME}/base)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/base/pickle.h DESTINATION include/${PROJECT_NAME}/base)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/base/port.h DESTINATION include/${PROJECT_NAME}/base)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/base/string16.h DESTINATION include/${PROJECT_NAME}/base)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/base/string_number_conversions.h DESTINATION include/${PROJECT_NAME}/base)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/base/string_piece.h DESTINATION include/${PROJECT_NAME}/base)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/base/time.h DESTINATION include/${PROJECT_NAME}/base)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/base/tuple.h DESTINATION include/${PROJECT_NAME}/base)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/base/values.h DESTINATION include/${PROJECT_NAME}/base)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/build/build_config.h DESTINATION include/${PROJECT_NAME}/build)
+INSTALL(DIRECTORY ${CMAKE_SOURCE_DIR}/ipc/ DESTINATION include/${PROJECT_NAME}/ipc FILES_MATCHING PATTERN "*.h")
diff --git a/LICENSE b/LICENSE
new file mode 100755
index 000000000000..2fe19f650fd2
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,27 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * 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.
+// * Neither the name of Google Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT
+// OWNER 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.
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 000000000000..5f4a4c5d12a2
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,3 @@
+Copyright (c) 2011 The Chromium Authors. All rights reserved.
+This software is excerpted from the Chromium project.
+Please, see the LICENSE file for licenses.
diff --git a/base/OWNERS b/base/OWNERS
new file mode 100644
index 000000000000..41dd3c96c64f
--- /dev/null
+++ b/base/OWNERS
@@ -0,0 +1,6 @@
+set noparent
+mark@chromium.org
+darin@chromium.org
+brettw@chromium.org
+evan@chromium.org
+willchan@chromium.org
diff --git a/base/atomic_ref_count.h b/base/atomic_ref_count.h
new file mode 100644
index 000000000000..985c42c32381
--- /dev/null
+++ b/base/atomic_ref_count.h
@@ -0,0 +1,81 @@
+// 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 is a low level implementation of atomic semantics for reference
+// counting. Please use base/memory/ref_counted.h directly instead.
+//
+// The implementation includes annotations to avoid some false positives
+// when using data race detection tools.
+
+#ifndef BASE_ATOMIC_REF_COUNT_H_
+#define BASE_ATOMIC_REF_COUNT_H_
+#pragma once
+
+#include "base/atomicops.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+
+namespace base {
+
+typedef subtle::Atomic32 AtomicRefCount;
+
+// Increment a reference count by "increment", which must exceed 0.
+inline void AtomicRefCountIncN(volatile AtomicRefCount *ptr,
+ AtomicRefCount increment) {
+ subtle::NoBarrier_AtomicIncrement(ptr, increment);
+}
+
+// Decrement a reference count by "decrement", which must exceed 0,
+// and return whether the result is non-zero.
+// Insert barriers to ensure that state written before the reference count
+// became zero will be visible to a thread that has just made the count zero.
+inline bool AtomicRefCountDecN(volatile AtomicRefCount *ptr,
+ AtomicRefCount decrement) {
+ ANNOTATE_HAPPENS_BEFORE(ptr);
+ bool res = (subtle::Barrier_AtomicIncrement(ptr, -decrement) != 0);
+ if (!res) {
+ ANNOTATE_HAPPENS_AFTER(ptr);
+ }
+ return res;
+}
+
+// Increment a reference count by 1.
+inline void AtomicRefCountInc(volatile AtomicRefCount *ptr) {
+ base::AtomicRefCountIncN(ptr, 1);
+}
+
+// Decrement a reference count by 1 and return whether the result is non-zero.
+// Insert barriers to ensure that state written before the reference count
+// became zero will be visible to a thread that has just made the count zero.
+inline bool AtomicRefCountDec(volatile AtomicRefCount *ptr) {
+ return base::AtomicRefCountDecN(ptr, 1);
+}
+
+// Return whether the reference count is one. If the reference count is used
+// in the conventional way, a refrerence count of 1 implies that the current
+// thread owns the reference and no other thread shares it. This call performs
+// the test for a reference count of one, and performs the memory barrier
+// needed for the owning thread to act on the object, knowing that it has
+// exclusive access to the object.
+inline bool AtomicRefCountIsOne(volatile AtomicRefCount *ptr) {
+ bool res = (subtle::Acquire_Load(ptr) == 1);
+ if (res) {
+ ANNOTATE_HAPPENS_AFTER(ptr);
+ }
+ return res;
+}
+
+// Return whether the reference count is zero. With conventional object
+// referencing counting, the object will be destroyed, so the reference count
+// should never be zero. Hence this is generally used for a debug check.
+inline bool AtomicRefCountIsZero(volatile AtomicRefCount *ptr) {
+ bool res = (subtle::Acquire_Load(ptr) == 0);
+ if (res) {
+ ANNOTATE_HAPPENS_AFTER(ptr);
+ }
+ return res;
+}
+
+} // namespace base
+
+#endif // BASE_ATOMIC_REF_COUNT_H_
diff --git a/base/atomic_sequence_num.h b/base/atomic_sequence_num.h
new file mode 100644
index 000000000000..11805a0ae501
--- /dev/null
+++ b/base/atomic_sequence_num.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_ATOMIC_SEQUENCE_NUM_H_
+#define BASE_ATOMIC_SEQUENCE_NUM_H_
+#pragma once
+
+#include "base/atomicops.h"
+#include "base/basictypes.h"
+
+namespace base {
+
+class AtomicSequenceNumber {
+ public:
+ AtomicSequenceNumber() : seq_(0) { }
+ explicit AtomicSequenceNumber(base::LinkerInitialized x) { /* seq_ is 0 */ }
+
+ int GetNext() {
+ return static_cast<int>(
+ base::subtle::NoBarrier_AtomicIncrement(&seq_, 1) - 1);
+ }
+
+ private:
+ base::subtle::Atomic32 seq_;
+ DISALLOW_COPY_AND_ASSIGN(AtomicSequenceNumber);
+};
+
+} // namespace base
+
+#endif // BASE_ATOMIC_SEQUENCE_NUM_H_
diff --git a/base/atomicops.h b/base/atomicops.h
new file mode 100644
index 000000000000..a087e3d09c9a
--- /dev/null
+++ b/base/atomicops.h
@@ -0,0 +1,150 @@
+// 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.
+
+// For atomic operations on reference counts, see atomic_refcount.h.
+// For atomic operations on sequence numbers, see atomic_sequence_num.h.
+
+// The routines exported by this module are subtle. If you use them, even if
+// you get the code right, it will depend on careful reasoning about atomicity
+// and memory ordering; it will be less readable, and harder to maintain. If
+// you plan to use these routines, you should have a good reason, such as solid
+// evidence that performance would otherwise suffer, or there being no
+// alternative. You should assume only properties explicitly guaranteed by the
+// specifications in this file. You are almost certainly _not_ writing code
+// just for the x86; if you assume x86 semantics, x86 hardware bugs and
+// implementations on other archtectures will cause your code to break. If you
+// do not know what you are doing, avoid these routines, and use a Mutex.
+//
+// It is incorrect to make direct assignments to/from an atomic variable.
+// You should use one of the Load or Store routines. The NoBarrier
+// versions are provided when no barriers are needed:
+// NoBarrier_Store()
+// NoBarrier_Load()
+// Although there are currently no compiler enforcement, you are encouraged
+// to use these.
+//
+
+#ifndef BASE_ATOMICOPS_H_
+#define BASE_ATOMICOPS_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "build/build_config.h"
+
+namespace base {
+namespace subtle {
+
+typedef int32 Atomic32;
+#ifdef ARCH_CPU_64_BITS
+// We need to be able to go between Atomic64 and AtomicWord implicitly. This
+// means Atomic64 and AtomicWord should be the same type on 64-bit.
+#if defined(OS_NACL)
+// NaCl's intptr_t is not actually 64-bits on 64-bit!
+// http://code.google.com/p/nativeclient/issues/detail?id=1162
+typedef int64_t Atomic64;
+#else
+typedef intptr_t Atomic64;
+#endif
+#endif
+
+// Use AtomicWord for a machine-sized pointer. It will use the Atomic32 or
+// Atomic64 routines below, depending on your architecture.
+typedef intptr_t AtomicWord;
+
+// Atomically execute:
+// result = *ptr;
+// if (*ptr == old_value)
+// *ptr = new_value;
+// return result;
+//
+// I.e., replace "*ptr" with "new_value" if "*ptr" used to be "old_value".
+// Always return the old value of "*ptr"
+//
+// This routine implies no memory barriers.
+Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value);
+
+// Atomically store new_value into *ptr, returning the previous value held in
+// *ptr. This routine implies no memory barriers.
+Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr, Atomic32 new_value);
+
+// Atomically increment *ptr by "increment". Returns the new value of
+// *ptr with the increment applied. This routine implies no memory barriers.
+Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr, Atomic32 increment);
+
+Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment);
+
+// These following lower-level operations are typically useful only to people
+// implementing higher-level synchronization operations like spinlocks,
+// mutexes, and condition-variables. They combine CompareAndSwap(), a load, or
+// a store with appropriate memory-ordering instructions. "Acquire" operations
+// ensure that no later memory access can be reordered ahead of the operation.
+// "Release" operations ensure that no previous memory access can be reordered
+// after the operation. "Barrier" operations have both "Acquire" and "Release"
+// semantics. A MemoryBarrier() has "Barrier" semantics, but does no memory
+// access.
+Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value);
+Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value);
+
+void MemoryBarrier();
+void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value);
+void Acquire_Store(volatile Atomic32* ptr, Atomic32 value);
+void Release_Store(volatile Atomic32* ptr, Atomic32 value);
+
+Atomic32 NoBarrier_Load(volatile const Atomic32* ptr);
+Atomic32 Acquire_Load(volatile const Atomic32* ptr);
+Atomic32 Release_Load(volatile const Atomic32* ptr);
+
+// 64-bit atomic operations (only available on 64-bit processors).
+#ifdef ARCH_CPU_64_BITS
+Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value);
+Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr, Atomic64 new_value);
+Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment);
+Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr, Atomic64 increment);
+
+Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value);
+Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value);
+void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value);
+void Acquire_Store(volatile Atomic64* ptr, Atomic64 value);
+void Release_Store(volatile Atomic64* ptr, Atomic64 value);
+Atomic64 NoBarrier_Load(volatile const Atomic64* ptr);
+Atomic64 Acquire_Load(volatile const Atomic64* ptr);
+Atomic64 Release_Load(volatile const Atomic64* ptr);
+#endif // ARCH_CPU_64_BITS
+
+} // namespace base::subtle
+} // namespace base
+
+// Include our platform specific implementation.
+#if defined(OS_WIN) && defined(COMPILER_MSVC) && defined(ARCH_CPU_X86_FAMILY)
+#include "base/atomicops_internals_x86_msvc.h"
+#elif defined(OS_MACOSX) && defined(ARCH_CPU_X86_FAMILY)
+#include "base/atomicops_internals_x86_macosx.h"
+#elif defined(COMPILER_GCC) && defined(ARCH_CPU_X86_FAMILY)
+#include "base/atomicops_internals_x86_gcc.h"
+#elif defined(COMPILER_GCC) && defined(ARCH_CPU_ARM_FAMILY)
+#include "base/atomicops_internals_arm_gcc.h"
+#else
+#error "Atomic operations are not supported on your platform"
+#endif
+
+// On some platforms we need additional declarations to make
+// AtomicWord compatible with our other Atomic* types.
+#if defined(OS_MACOSX) || defined(OS_OPENBSD)
+#include "base/atomicops_internals_atomicword_compat.h"
+#endif
+
+#endif // BASE_ATOMICOPS_H_
diff --git a/base/atomicops_internals_arm_gcc.h b/base/atomicops_internals_arm_gcc.h
new file mode 100644
index 000000000000..091b34d55ceb
--- /dev/null
+++ b/base/atomicops_internals_arm_gcc.h
@@ -0,0 +1,125 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is an internal atomic implementation, use base/atomicops.h instead.
+//
+// LinuxKernelCmpxchg and Barrier_AtomicIncrement are from Google Gears.
+
+#ifndef BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_
+#define BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_
+#pragma once
+
+namespace base {
+namespace subtle {
+
+// 0xffff0fc0 is the hard coded address of a function provided by
+// the kernel which implements an atomic compare-exchange. On older
+// ARM architecture revisions (pre-v6) this may be implemented using
+// a syscall. This address is stable, and in active use (hard coded)
+// by at least glibc-2.7 and the Android C library.
+typedef Atomic32 (*LinuxKernelCmpxchgFunc)(Atomic32 old_value,
+ Atomic32 new_value,
+ volatile Atomic32* ptr);
+LinuxKernelCmpxchgFunc pLinuxKernelCmpxchg __attribute__((weak)) =
+ (LinuxKernelCmpxchgFunc) 0xffff0fc0;
+
+typedef void (*LinuxKernelMemoryBarrierFunc)(void);
+LinuxKernelMemoryBarrierFunc pLinuxKernelMemoryBarrier __attribute__((weak)) =
+ (LinuxKernelMemoryBarrierFunc) 0xffff0fa0;
+
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ Atomic32 prev_value = *ptr;
+ do {
+ if (!pLinuxKernelCmpxchg(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 (pLinuxKernelCmpxchg(old_value, new_value,
+ const_cast<Atomic32*>(ptr)));
+ return old_value;
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment) {
+ return Barrier_AtomicIncrement(ptr, increment);
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment) {
+ for (;;) {
+ // Atomic exchange the old value with an incremented one.
+ Atomic32 old_value = *ptr;
+ Atomic32 new_value = old_value + increment;
+ if (pLinuxKernelCmpxchg(old_value, new_value,
+ const_cast<Atomic32*>(ptr)) == 0) {
+ // The exchange took place as expected.
+ return new_value;
+ }
+ // Otherwise, *ptr changed mid-loop and we need to retry.
+ }
+
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+ *ptr = value;
+}
+
+inline void MemoryBarrier() {
+ pLinuxKernelMemoryBarrier();
+}
+
+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;
+}
+
+} // namespace base::subtle
+} // namespace base
+
+#endif // BASE_ATOMICOPS_INTERNALS_ARM_GCC_H_
diff --git a/base/atomicops_internals_atomicword_compat.h b/base/atomicops_internals_atomicword_compat.h
new file mode 100644
index 000000000000..8382fe1bc970
--- /dev/null
+++ b/base/atomicops_internals_atomicword_compat.h
@@ -0,0 +1,101 @@
+// 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 an internal atomic implementation, use base/atomicops.h instead.
+
+#ifndef BASE_ATOMICOPS_INTERNALS_ATOMICWORD_COMPAT_H_
+#define BASE_ATOMICOPS_INTERNALS_ATOMICWORD_COMPAT_H_
+#pragma once
+
+// AtomicWord is a synonym for intptr_t, and Atomic32 is a synonym for int32,
+// 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.
+//
+// This file defines function overloads to allow both AtomicWord and Atomic32
+// data to be used with this interface.
+//
+// On LP64 platforms, AtomicWord and Atomic64 are both always long,
+// so this problem doesn't occur.
+
+#if !defined(ARCH_CPU_64_BITS)
+
+namespace base {
+namespace subtle {
+
+inline AtomicWord NoBarrier_CompareAndSwap(volatile AtomicWord* ptr,
+ AtomicWord old_value,
+ AtomicWord new_value) {
+ return NoBarrier_CompareAndSwap(
+ reinterpret_cast<volatile Atomic32*>(ptr), old_value, new_value);
+}
+
+inline AtomicWord NoBarrier_AtomicExchange(volatile AtomicWord* ptr,
+ AtomicWord new_value) {
+ return NoBarrier_AtomicExchange(
+ reinterpret_cast<volatile Atomic32*>(ptr), new_value);
+}
+
+inline AtomicWord NoBarrier_AtomicIncrement(volatile AtomicWord* ptr,
+ AtomicWord increment) {
+ return NoBarrier_AtomicIncrement(
+ reinterpret_cast<volatile Atomic32*>(ptr), increment);
+}
+
+inline AtomicWord Barrier_AtomicIncrement(volatile AtomicWord* ptr,
+ AtomicWord increment) {
+ return Barrier_AtomicIncrement(
+ reinterpret_cast<volatile Atomic32*>(ptr), increment);
+}
+
+inline AtomicWord Acquire_CompareAndSwap(volatile AtomicWord* ptr,
+ AtomicWord old_value,
+ AtomicWord new_value) {
+ return base::subtle::Acquire_CompareAndSwap(
+ reinterpret_cast<volatile Atomic32*>(ptr), old_value, new_value);
+}
+
+inline AtomicWord Release_CompareAndSwap(volatile AtomicWord* ptr,
+ AtomicWord old_value,
+ AtomicWord new_value) {
+ return base::subtle::Release_CompareAndSwap(
+ reinterpret_cast<volatile Atomic32*>(ptr), old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile AtomicWord *ptr, AtomicWord value) {
+ NoBarrier_Store(
+ reinterpret_cast<volatile Atomic32*>(ptr), value);
+}
+
+inline void Acquire_Store(volatile AtomicWord* ptr, AtomicWord value) {
+ return base::subtle::Acquire_Store(
+ reinterpret_cast<volatile Atomic32*>(ptr), value);
+}
+
+inline void Release_Store(volatile AtomicWord* ptr, AtomicWord value) {
+ return base::subtle::Release_Store(
+ reinterpret_cast<volatile Atomic32*>(ptr), value);
+}
+
+inline AtomicWord NoBarrier_Load(volatile const AtomicWord *ptr) {
+ return NoBarrier_Load(
+ reinterpret_cast<volatile const Atomic32*>(ptr));
+}
+
+inline AtomicWord Acquire_Load(volatile const AtomicWord* ptr) {
+ return base::subtle::Acquire_Load(
+ reinterpret_cast<volatile const Atomic32*>(ptr));
+}
+
+inline AtomicWord Release_Load(volatile const AtomicWord* ptr) {
+ return base::subtle::Release_Load(
+ reinterpret_cast<volatile const Atomic32*>(ptr));
+}
+
+} // namespace base::subtle
+} // namespace base
+
+#endif // !defined(ARCH_CPU_64_BITS)
+
+#endif // BASE_ATOMICOPS_INTERNALS_ATOMICWORD_COMPAT_H_
diff --git a/base/atomicops_internals_x86_gcc.cc b/base/atomicops_internals_x86_gcc.cc
new file mode 100644
index 000000000000..933ca51896df
--- /dev/null
+++ b/base/atomicops_internals_x86_gcc.cc
@@ -0,0 +1,104 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This module gets enough CPU information to optimize the
+// atomicops module on x86.
+
+#include <string.h>
+
+#include "base/atomicops.h"
+#include "base/basictypes.h"
+
+// This file only makes sense with atomicops_internals_x86_gcc.h -- it
+// depends on structs that are defined in that file. If atomicops.h
+// doesn't sub-include that file, then we aren't needed, and shouldn't
+// try to do anything.
+#ifdef BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
+
+// Inline cpuid instruction. In PIC compilations, %ebx contains the address
+// of the global offset table. To avoid breaking such executables, this code
+// must preserve that register's value across cpuid instructions.
+#if defined(__i386__)
+#define cpuid(a, b, c, d, inp) \
+ asm ("mov %%ebx, %%edi\n" \
+ "cpuid\n" \
+ "xchg %%edi, %%ebx\n" \
+ : "=a" (a), "=D" (b), "=c" (c), "=d" (d) : "a" (inp))
+#elif defined (__x86_64__)
+#define cpuid(a, b, c, d, inp) \
+ asm ("mov %%rbx, %%rdi\n" \
+ "cpuid\n" \
+ "xchg %%rdi, %%rbx\n" \
+ : "=a" (a), "=D" (b), "=c" (c), "=d" (d) : "a" (inp))
+#endif
+
+#if defined(cpuid) // initialize the struct only on x86
+
+// Set the flags so that code will run correctly and conservatively, so even
+// if we haven't been initialized yet, we're probably single threaded, and our
+// default values should hopefully be pretty safe.
+struct AtomicOps_x86CPUFeatureStruct AtomicOps_Internalx86CPUFeatures = {
+ false, // bug can't exist before process spawns multiple threads
+ false, // no SSE2
+};
+
+// Initialize the AtomicOps_Internalx86CPUFeatures struct.
+static void AtomicOps_Internalx86CPUFeaturesInit() {
+ uint32 eax;
+ uint32 ebx;
+ uint32 ecx;
+ uint32 edx;
+
+ // Get vendor string (issue CPUID with eax = 0)
+ cpuid(eax, ebx, ecx, edx, 0);
+ char vendor[13];
+ memcpy(vendor, &ebx, 4);
+ memcpy(vendor + 4, &edx, 4);
+ memcpy(vendor + 8, &ecx, 4);
+ vendor[12] = 0;
+
+ // get feature flags in ecx/edx, and family/model in eax
+ cpuid(eax, ebx, ecx, edx, 1);
+
+ int family = (eax >> 8) & 0xf; // family and model fields
+ int model = (eax >> 4) & 0xf;
+ if (family == 0xf) { // use extended family and model fields
+ family += (eax >> 20) & 0xff;
+ model += ((eax >> 16) & 0xf) << 4;
+ }
+
+ // Opteron Rev E has a bug in which on very rare occasions a locked
+ // instruction doesn't act as a read-acquire barrier if followed by a
+ // non-locked read-modify-write instruction. Rev F has this bug in
+ // pre-release versions, but not in versions released to customers,
+ // so we test only for Rev E, which is family 15, model 32..63 inclusive.
+ if (strcmp(vendor, "AuthenticAMD") == 0 && // AMD
+ family == 15 &&
+ 32 <= model && model <= 63) {
+ AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug = true;
+ } else {
+ AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug = false;
+ }
+
+ // edx bit 26 is SSE2 which we use to tell use whether we can use mfence
+ AtomicOps_Internalx86CPUFeatures.has_sse2 = ((edx >> 26) & 1);
+}
+
+namespace {
+
+class AtomicOpsx86Initializer {
+ public:
+ AtomicOpsx86Initializer() {
+ AtomicOps_Internalx86CPUFeaturesInit();
+ }
+};
+
+// A global to get use initialized on startup via static initialization :/
+AtomicOpsx86Initializer g_initer;
+
+} // namespace
+
+#endif // if x86
+
+#endif // ifdef BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
diff --git a/base/atomicops_internals_x86_gcc.h b/base/atomicops_internals_x86_gcc.h
new file mode 100644
index 000000000000..72fd35000e7a
--- /dev/null
+++ b/base/atomicops_internals_x86_gcc.h
@@ -0,0 +1,270 @@
+// 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 an internal atomic implementation, use base/atomicops.h instead.
+
+#ifndef BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
+#define BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
+#pragma once
+
+#include "base/base_export.h"
+
+// This struct is not part of the public API of this module; clients may not
+// use it. (However, it's exported via BASE_EXPORT because clients implicitly
+// do use it at link time by inlining these functions.)
+// Features of this x86. Values may not be correct before main() is run,
+// but are set conservatively.
+struct AtomicOps_x86CPUFeatureStruct {
+ bool has_amd_lock_mb_bug; // Processor has AMD memory-barrier bug; do lfence
+ // after acquire compare-and-swap.
+ bool has_sse2; // Processor has SSE2.
+};
+BASE_EXPORT extern struct AtomicOps_x86CPUFeatureStruct
+ AtomicOps_Internalx86CPUFeatures;
+
+#define ATOMICOPS_COMPILER_BARRIER() __asm__ __volatile__("" : : : "memory")
+
+namespace base {
+namespace subtle {
+
+// 32-bit low-level operations on any platform.
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ Atomic32 prev;
+ __asm__ __volatile__("lock; cmpxchgl %1,%2"
+ : "=a" (prev)
+ : "q" (new_value), "m" (*ptr), "0" (old_value)
+ : "memory");
+ return prev;
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+ Atomic32 new_value) {
+ __asm__ __volatile__("xchgl %1,%0" // The lock prefix is implicit for xchg.
+ : "=r" (new_value)
+ : "m" (*ptr), "0" (new_value)
+ : "memory");
+ return new_value; // Now it's the previous value.
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment) {
+ Atomic32 temp = increment;
+ __asm__ __volatile__("lock; xaddl %0,%1"
+ : "+r" (temp), "+m" (*ptr)
+ : : "memory");
+ // temp now holds the old value of *ptr
+ return temp + increment;
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment) {
+ Atomic32 temp = increment;
+ __asm__ __volatile__("lock; xaddl %0,%1"
+ : "+r" (temp), "+m" (*ptr)
+ : : "memory");
+ // temp now holds the old value of *ptr
+ if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
+ __asm__ __volatile__("lfence" : : : "memory");
+ }
+ return temp + increment;
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ Atomic32 x = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+ if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
+ __asm__ __volatile__("lfence" : : : "memory");
+ }
+ return x;
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline void NoBarrier_Store(volatile Atomic32* ptr, Atomic32 value) {
+ *ptr = value;
+}
+
+#if defined(__x86_64__)
+
+// 64-bit implementations of memory barrier can be simpler, because it
+// "mfence" is guaranteed to exist.
+inline void MemoryBarrier() {
+ __asm__ __volatile__("mfence" : : : "memory");
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+ *ptr = value;
+ MemoryBarrier();
+}
+
+#else
+
+inline void MemoryBarrier() {
+ if (AtomicOps_Internalx86CPUFeatures.has_sse2) {
+ __asm__ __volatile__("mfence" : : : "memory");
+ } else { // mfence is faster but not present on PIII
+ Atomic32 x = 0;
+ NoBarrier_AtomicExchange(&x, 0); // acts as a barrier on PIII
+ }
+}
+
+inline void Acquire_Store(volatile Atomic32* ptr, Atomic32 value) {
+ if (AtomicOps_Internalx86CPUFeatures.has_sse2) {
+ *ptr = value;
+ __asm__ __volatile__("mfence" : : : "memory");
+ } else {
+ NoBarrier_AtomicExchange(ptr, value);
+ // acts as a barrier on PIII
+ }
+}
+#endif
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+ ATOMICOPS_COMPILER_BARRIER();
+ *ptr = value; // An x86 store acts as a release barrier.
+ // See comments in Atomic64 version of Release_Store(), below.
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+ return *ptr;
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+ Atomic32 value = *ptr; // An x86 load acts as a acquire barrier.
+ // See comments in Atomic64 version of Release_Store(), below.
+ ATOMICOPS_COMPILER_BARRIER();
+ return value;
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+ MemoryBarrier();
+ return *ptr;
+}
+
+#if defined(__x86_64__)
+
+// 64-bit low-level operations on 64-bit platform.
+
+inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ Atomic64 prev;
+ __asm__ __volatile__("lock; cmpxchgq %1,%2"
+ : "=a" (prev)
+ : "q" (new_value), "m" (*ptr), "0" (old_value)
+ : "memory");
+ return prev;
+}
+
+inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
+ Atomic64 new_value) {
+ __asm__ __volatile__("xchgq %1,%0" // The lock prefix is implicit for xchg.
+ : "=r" (new_value)
+ : "m" (*ptr), "0" (new_value)
+ : "memory");
+ return new_value; // Now it's the previous value.
+}
+
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
+ Atomic64 increment) {
+ Atomic64 temp = increment;
+ __asm__ __volatile__("lock; xaddq %0,%1"
+ : "+r" (temp), "+m" (*ptr)
+ : : "memory");
+ // temp now contains the previous value of *ptr
+ return temp + increment;
+}
+
+inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
+ Atomic64 increment) {
+ Atomic64 temp = increment;
+ __asm__ __volatile__("lock; xaddq %0,%1"
+ : "+r" (temp), "+m" (*ptr)
+ : : "memory");
+ // temp now contains the previous value of *ptr
+ if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
+ __asm__ __volatile__("lfence" : : : "memory");
+ }
+ return temp + increment;
+}
+
+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) {
+ ATOMICOPS_COMPILER_BARRIER();
+
+ *ptr = value; // An x86 store acts as a release barrier
+ // for current AMD/Intel chips as of Jan 2008.
+ // See also Acquire_Load(), below.
+
+ // When new chips come out, check:
+ // IA-32 Intel Architecture Software Developer's Manual, Volume 3:
+ // System Programming Guide, Chatper 7: Multiple-processor management,
+ // Section 7.2, Memory Ordering.
+ // Last seen at:
+ // http://developer.intel.com/design/pentium4/manuals/index_new.htm
+ //
+ // x86 stores/loads fail to act as barriers for a few instructions (clflush
+ // maskmovdqu maskmovq movntdq movnti movntpd movntps movntq) but these are
+ // not generated by the compiler, and are rare. Users of these instructions
+ // need to know about cache behaviour in any case since all of these involve
+ // either flushing cache lines or non-temporal cache hints.
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
+ return *ptr;
+}
+
+inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
+ Atomic64 value = *ptr; // An x86 load acts as a acquire barrier,
+ // for current AMD/Intel chips as of Jan 2008.
+ // See also Release_Store(), above.
+ ATOMICOPS_COMPILER_BARRIER();
+ return value;
+}
+
+inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
+ MemoryBarrier();
+ return *ptr;
+}
+
+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ Atomic64 x = NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+ if (AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug) {
+ __asm__ __volatile__("lfence" : : : "memory");
+ }
+ return x;
+}
+
+inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+#endif // defined(__x86_64__)
+
+} // namespace base::subtle
+} // namespace base
+
+#undef ATOMICOPS_COMPILER_BARRIER
+
+#endif // BASE_ATOMICOPS_INTERNALS_X86_GCC_H_
diff --git a/base/atomicops_internals_x86_macosx.h b/base/atomicops_internals_x86_macosx.h
new file mode 100644
index 000000000000..4b7cec81d045
--- /dev/null
+++ b/base/atomicops_internals_x86_macosx.h
@@ -0,0 +1,198 @@
+// 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 an internal atomic implementation, use base/atomicops.h instead.
+
+#ifndef BASE_ATOMICOPS_INTERNALS_X86_MACOSX_H_
+#define BASE_ATOMICOPS_INTERNALS_X86_MACOSX_H_
+#pragma once
+
+#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 base::subtle
+} // namespace base
+
+#endif // BASE_ATOMICOPS_INTERNALS_X86_MACOSX_H_
diff --git a/base/atomicops_internals_x86_msvc.h b/base/atomicops_internals_x86_msvc.h
new file mode 100644
index 000000000000..15745288c3d4
--- /dev/null
+++ b/base/atomicops_internals_x86_msvc.h
@@ -0,0 +1,181 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is an internal atomic implementation, use base/atomicops.h instead.
+
+#ifndef BASE_ATOMICOPS_INTERNALS_X86_MSVC_H_
+#define BASE_ATOMICOPS_INTERNALS_X86_MSVC_H_
+#pragma once
+
+#include <windows.h>
+
+namespace base {
+namespace subtle {
+
+inline Atomic32 NoBarrier_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ LONG result = InterlockedCompareExchange(
+ reinterpret_cast<volatile LONG*>(ptr),
+ static_cast<LONG>(new_value),
+ static_cast<LONG>(old_value));
+ return static_cast<Atomic32>(result);
+}
+
+inline Atomic32 NoBarrier_AtomicExchange(volatile Atomic32* ptr,
+ Atomic32 new_value) {
+ LONG result = InterlockedExchange(
+ reinterpret_cast<volatile LONG*>(ptr),
+ static_cast<LONG>(new_value));
+ return static_cast<Atomic32>(result);
+}
+
+inline Atomic32 Barrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment) {
+ return InterlockedExchangeAdd(
+ reinterpret_cast<volatile LONG*>(ptr),
+ static_cast<LONG>(increment)) + increment;
+}
+
+inline Atomic32 NoBarrier_AtomicIncrement(volatile Atomic32* ptr,
+ Atomic32 increment) {
+ return Barrier_AtomicIncrement(ptr, increment);
+}
+
+#if !(defined(_MSC_VER) && _MSC_VER >= 1400)
+#error "We require at least vs2005 for MemoryBarrier"
+#endif
+inline void MemoryBarrier() {
+ // We use MemoryBarrier from WinNT.h
+ ::MemoryBarrier();
+}
+
+inline Atomic32 Acquire_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline Atomic32 Release_CompareAndSwap(volatile Atomic32* ptr,
+ Atomic32 old_value,
+ Atomic32 new_value) {
+ return NoBarrier_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) {
+ NoBarrier_AtomicExchange(ptr, value);
+ // acts as a barrier in this implementation
+}
+
+inline void Release_Store(volatile Atomic32* ptr, Atomic32 value) {
+ *ptr = value; // works w/o barrier for current Intel chips as of June 2005
+ // See comments in Atomic64 version of Release_Store() below.
+}
+
+inline Atomic32 NoBarrier_Load(volatile const Atomic32* ptr) {
+ return *ptr;
+}
+
+inline Atomic32 Acquire_Load(volatile const Atomic32* ptr) {
+ Atomic32 value = *ptr;
+ return value;
+}
+
+inline Atomic32 Release_Load(volatile const Atomic32* ptr) {
+ MemoryBarrier();
+ return *ptr;
+}
+
+#if defined(_WIN64)
+
+// 64-bit low-level operations on 64-bit platform.
+
+COMPILE_ASSERT(sizeof(Atomic64) == sizeof(PVOID), atomic_word_is_atomic);
+
+inline Atomic64 NoBarrier_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ PVOID result = InterlockedCompareExchangePointer(
+ reinterpret_cast<volatile PVOID*>(ptr),
+ reinterpret_cast<PVOID>(new_value), reinterpret_cast<PVOID>(old_value));
+ return reinterpret_cast<Atomic64>(result);
+}
+
+inline Atomic64 NoBarrier_AtomicExchange(volatile Atomic64* ptr,
+ Atomic64 new_value) {
+ PVOID result = InterlockedExchangePointer(
+ reinterpret_cast<volatile PVOID*>(ptr),
+ reinterpret_cast<PVOID>(new_value));
+ return reinterpret_cast<Atomic64>(result);
+}
+
+inline Atomic64 Barrier_AtomicIncrement(volatile Atomic64* ptr,
+ Atomic64 increment) {
+ return InterlockedExchangeAdd64(
+ reinterpret_cast<volatile LONGLONG*>(ptr),
+ static_cast<LONGLONG>(increment)) + increment;
+}
+
+inline Atomic64 NoBarrier_AtomicIncrement(volatile Atomic64* ptr,
+ Atomic64 increment) {
+ return Barrier_AtomicIncrement(ptr, increment);
+}
+
+inline void NoBarrier_Store(volatile Atomic64* ptr, Atomic64 value) {
+ *ptr = value;
+}
+
+inline void Acquire_Store(volatile Atomic64* ptr, Atomic64 value) {
+ NoBarrier_AtomicExchange(ptr, value);
+ // acts as a barrier in this implementation
+}
+
+inline void Release_Store(volatile Atomic64* ptr, Atomic64 value) {
+ *ptr = value; // works w/o barrier for current Intel chips as of June 2005
+
+ // When new chips come out, check:
+ // IA-32 Intel Architecture Software Developer's Manual, Volume 3:
+ // System Programming Guide, Chatper 7: Multiple-processor management,
+ // Section 7.2, Memory Ordering.
+ // Last seen at:
+ // http://developer.intel.com/design/pentium4/manuals/index_new.htm
+}
+
+inline Atomic64 NoBarrier_Load(volatile const Atomic64* ptr) {
+ return *ptr;
+}
+
+inline Atomic64 Acquire_Load(volatile const Atomic64* ptr) {
+ Atomic64 value = *ptr;
+ return value;
+}
+
+inline Atomic64 Release_Load(volatile const Atomic64* ptr) {
+ MemoryBarrier();
+ return *ptr;
+}
+
+inline Atomic64 Acquire_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+inline Atomic64 Release_CompareAndSwap(volatile Atomic64* ptr,
+ Atomic64 old_value,
+ Atomic64 new_value) {
+ return NoBarrier_CompareAndSwap(ptr, old_value, new_value);
+}
+
+
+#endif // defined(_WIN64)
+
+} // namespace base::subtle
+} // namespace base
+
+#endif // BASE_ATOMICOPS_INTERNALS_X86_MSVC_H_
diff --git a/base/base_export.h b/base/base_export.h
new file mode 100644
index 000000000000..c3bff9fae031
--- /dev/null
+++ b/base/base_export.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_BASE_OSP_EXPORT_
+#define BASE_BASE_OSP_EXPORT_
+#pragma once
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(BASE_IMPLEMENTATION)
+#define BASE_EXPORT __declspec(dllexport)
+#else
+#define BASE_EXPORT __declspec(dllimport)
+#endif // defined(BASE_IMPLEMENTATION)
+
+#else // defined(WIN32)
+#define BASE_EXPORT __attribute__((visibility("default")))
+#endif
+
+#else // defined(COMPONENT_BUILD)
+#define BASE_EXPORT
+#endif
+
+#endif // BASE_BASE_OSP_EXPORT_
diff --git a/base/basictypes.h b/base/basictypes.h
new file mode 100644
index 000000000000..c6f509785660
--- /dev/null
+++ b/base/basictypes.h
@@ -0,0 +1,367 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_BASICTYPES_H_
+#define BASE_BASICTYPES_H_
+#pragma once
+
+#include <limits.h> // So we can set the bounds of our types
+#include <stddef.h> // For size_t
+#include <string.h> // for memcpy
+
+#include "base/port.h" // Types that only need exist on certain systems
+
+#ifndef COMPILER_MSVC
+// stdint.h is part of C99 but MSVC doesn't have it.
+#include <stdint.h> // For intptr_t.
+#endif
+
+typedef signed char schar;
+typedef signed char int8;
+typedef short int16;
+// TODO: Remove these type guards. These are to avoid conflicts with
+// obsolete/protypes.h in the Gecko SDK.
+#ifndef _INT32
+#define _INT32
+typedef int int32;
+#endif
+
+// The NSPR system headers define 64-bit as |long| when possible, except on
+// Mac OS X. In order to not have typedef mismatches, we do the same on LP64.
+//
+// On Mac OS X, |long long| is used for 64-bit types for compatibility with
+// <inttypes.h> format macros even in the LP64 model.
+#if defined(__LP64__) && !defined(OS_MACOSX)
+typedef long int64;
+#else
+typedef long long int64;
+#endif
+
+// NOTE: unsigned types are DANGEROUS in loops and other arithmetical
+// places. Use the signed types unless your variable represents a bit
+// pattern (eg a hash value) or you really need the extra bit. Do NOT
+// use 'unsigned' to express "this value should always be positive";
+// use assertions for this.
+
+typedef unsigned char uint8;
+typedef unsigned short uint16;
+// TODO: Remove these type guards. These are to avoid conflicts with
+// obsolete/protypes.h in the Gecko SDK.
+#ifndef _UINT32
+#define _UINT32
+typedef unsigned int uint32;
+#endif
+
+// See the comment above about NSPR and 64-bit.
+#if defined(__LP64__) && !defined(OS_MACOSX)
+typedef unsigned long uint64;
+#else
+typedef unsigned long long uint64;
+#endif
+
+// A type to represent a Unicode code-point value. As of Unicode 4.0,
+// such values require up to 21 bits.
+// (For type-checking on pointers, make this explicitly signed,
+// and it should always be the signed version of whatever int32 is.)
+typedef signed int char32;
+
+const uint8 kuint8max = (( uint8) 0xFF);
+const uint16 kuint16max = ((uint16) 0xFFFF);
+const uint32 kuint32max = ((uint32) 0xFFFFFFFF);
+const uint64 kuint64max = ((uint64) GG_LONGLONG(0xFFFFFFFFFFFFFFFF));
+const int8 kint8min = (( int8) 0x80);
+const int8 kint8max = (( int8) 0x7F);
+const int16 kint16min = (( int16) 0x8000);
+const int16 kint16max = (( int16) 0x7FFF);
+const int32 kint32min = (( int32) 0x80000000);
+const int32 kint32max = (( int32) 0x7FFFFFFF);
+const int64 kint64min = (( int64) GG_LONGLONG(0x8000000000000000));
+const int64 kint64max = (( int64) GG_LONGLONG(0x7FFFFFFFFFFFFFFF));
+
+// A macro to disallow the copy constructor and operator= functions
+// This should be used in the private: declarations for a class
+#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
+ TypeName(const TypeName&); \
+ void operator=(const TypeName&)
+
+// An older, deprecated, politically incorrect name for the above.
+// NOTE: The usage of this macro was baned 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.
+//
+// This should be used in the private: declarations for a class
+// that wants to prevent anyone from instantiating it. This is
+// especially useful for classes containing only static methods.
+#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
+ TypeName(); \
+ 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.
+//
+// One caveat is that arraysize() doesn't accept any array of an
+// anonymous type or a type defined inside a function. In these rare
+// cases, you have to use the unsafe ARRAYSIZE_UNSAFE() macro below. This is
+// due to a limitation in C++'s template system. The limitation might
+// eventually be removed, but it hasn't happened yet.
+
+// This template function declaration is used in defining arraysize.
+// Note that the function doesn't need an implementation, as we only
+// use its type.
+template <typename T, size_t N>
+char (&ArraySizeHelper(T (&array)[N]))[N];
+
+// That gcc wants both of these prototypes seems mysterious. VC, for
+// its part, can't decide which to use (another mystery). Matching of
+// template overloads: the final frontier.
+#ifndef _MSC_VER
+template <typename T, size_t N>
+char (&ArraySizeHelper(const T (&array)[N]))[N];
+#endif
+
+#define arraysize(array) (sizeof(ArraySizeHelper(array)))
+
+// ARRAYSIZE_UNSAFE performs essentially the same calculation as arraysize,
+// but can be used on anonymous types or types defined inside
+// functions. It's less safe than arraysize as it accepts some
+// (although not all) pointers. Therefore, you should use arraysize
+// whenever possible.
+//
+// The expression ARRAYSIZE_UNSAFE(a) is a compile-time constant of type
+// size_t.
+//
+// ARRAYSIZE_UNSAFE catches a few type errors. If you see a compiler error
+//
+// "warning: division by zero in ..."
+//
+// when using ARRAYSIZE_UNSAFE, you are (wrongfully) giving it a pointer.
+// You should only use ARRAYSIZE_UNSAFE on statically allocated arrays.
+//
+// The following comments are on the implementation details, and can
+// be ignored by the users.
+//
+// ARRAYSIZE_UNSAFE(arr) works by inspecting sizeof(arr) (the # of bytes in
+// the array) and sizeof(*(arr)) (the # of bytes in one array
+// element). If the former is divisible by the latter, perhaps arr is
+// indeed an array, in which case the division result is the # of
+// elements in the array. Otherwise, arr cannot possibly be an array,
+// and we generate a compiler error to prevent the code from
+// compiling.
+//
+// Since the size of bool is implementation-defined, we need to cast
+// !(sizeof(a) & sizeof(*(a))) to size_t in order to ensure the final
+// result has type size_t.
+//
+// This macro is not perfect as it wrongfully accepts certain
+// pointers, namely where the pointer size is divisible by the pointee
+// size. Since all our code has to go through a 32-bit compiler,
+// where a pointer is 4 bytes, this means all pointers to a type whose
+// size is 3 or greater than 4 will be (righteously) rejected.
+
+#define ARRAYSIZE_UNSAFE(a) \
+ ((sizeof(a) / sizeof(*(a))) / \
+ static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
+
+
+// Use implicit_cast as a safe version of static_cast or const_cast
+// for upcasting in the type hierarchy (i.e. casting a pointer to Foo
+// to a pointer to SuperclassOfFoo or casting a pointer to Foo to
+// a const pointer to Foo).
+// When you use implicit_cast, the compiler checks that the cast is safe.
+// Such explicit implicit_casts are necessary in surprisingly many
+// situations where C++ demands an exact type match instead of an
+// argument type convertable to a target type.
+//
+// The From type can be inferred, so the preferred syntax for using
+// implicit_cast is the same as for static_cast etc.:
+//
+// implicit_cast<ToType>(expr)
+//
+// implicit_cast would have been part of the C++ standard library,
+// but the proposal was submitted too late. It will probably make
+// its way into the language in the future.
+template<typename To, typename From>
+inline To implicit_cast(From const &f) {
+ return f;
+}
+
+// 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_UNSAFE(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.
+
+template <bool>
+struct CompileAssert {
+};
+
+#undef COMPILE_ASSERT
+#define COMPILE_ASSERT(expr, msg) \
+ typedef CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1]
+
+// Implementation details of COMPILE_ASSERT:
+//
+// - COMPILE_ASSERT works by defining an array type that has -1
+// elements (and thus is invalid) when the expression is false.
+//
+// - The simpler definition
+//
+// #define COMPILE_ASSERT(expr, msg) typedef char msg[(expr) ? 1 : -1]
+//
+// does not work, as gcc supports variable-length arrays whose sizes
+// are determined at run-time (this is gcc's extension and not part
+// of the C++ standard). As a result, gcc fails to reject the
+// following code with the simple definition:
+//
+// int foo;
+// COMPILE_ASSERT(foo, msg); // not supposed to compile as foo is
+// // not a compile-time constant.
+//
+// - By using the type CompileAssert<(bool(expr))>, we ensures that
+// expr is a compile-time constant. (Template arguments must be
+// determined at compile-time.)
+//
+// - The outer parentheses in CompileAssert<(bool(expr))> are necessary
+// to work around a bug in gcc 3.4.4 and 4.0.1. If we had written
+//
+// CompileAssert<bool(expr)>
+//
+// instead, these compilers will refuse to compile
+//
+// COMPILE_ASSERT(5 > 0, some_message);
+//
+// (They seem to think the ">" in "5 > 0" marks the end of the
+// template argument list.)
+//
+// - The array size is (bool(expr) ? 1 : -1), instead of simply
+//
+// ((expr) ? 1 : -1).
+//
+// This is to avoid running into a bug in MS VC 7.1, which
+// causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1.
+
+
+// MetatagId refers to metatag-id that we assign to
+// each metatag <name, value> pair..
+typedef uint32 MetatagId;
+
+// Argument type used in interfaces that can optionally take ownership
+// of a passed in argument. If TAKE_OWNERSHIP is passed, the called
+// object takes ownership of the argument. Otherwise it does not.
+enum Ownership {
+ DO_NOT_TAKE_OWNERSHIP,
+ TAKE_OWNERSHIP
+};
+
+// 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 betweeen 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 time assertion: sizeof(Dest) == sizeof(Source)
+ // A compile error here means your Dest and Source have different sizes.
+ typedef char VerifySizesAreEqual [sizeof(Dest) == sizeof(Source) ? 1 : -1];
+
+ 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:
+//
+// scoped_ptr<MyType> my_var = ...;
+// if (TakeOwnership(my_var.get()) == SUCCESS)
+// ignore_result(my_var.release());
+//
+template<typename T>
+inline void ignore_result(const T& ignored) {
+}
+
+// The following enum should be used only as a constructor argument to indicate
+// that the variable has static storage class, and that the constructor should
+// do nothing to its state. It indicates to the reader that it is legal to
+// declare a static instance of the class, provided the constructor is given
+// the base::LINKER_INITIALIZED argument. Normally, it is unsafe to declare a
+// static variable that has a constructor or a destructor because invocation
+// order is undefined. However, IF the type can be initialized by filling with
+// zeroes (which the loader does for static variables), AND the destructor also
+// does nothing to the storage, AND there are no virtual methods, then a
+// constructor declared as
+// explicit MyClass(base::LinkerInitialized x) {}
+// and invoked as
+// static MyClass my_variable_name(base::LINKER_INITIALIZED);
+namespace base {
+enum LinkerInitialized { LINKER_INITIALIZED };
+} // base
+
+#endif // BASE_BASICTYPES_H_
diff --git a/base/compiler_specific.h b/base/compiler_specific.h
new file mode 100644
index 000000000000..0a6e05a6c679
--- /dev/null
+++ b/base/compiler_specific.h
@@ -0,0 +1,140 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_COMPILER_SPECIFIC_H_
+#define BASE_COMPILER_SPECIFIC_H_
+#pragma once
+
+#include "build/build_config.h"
+
+#if defined(COMPILER_MSVC)
+
+// Macros for suppressing and disabling warnings on MSVC.
+//
+// Warning numbers are enumerated at:
+// http://msdn.microsoft.com/en-us/library/8x5x43k7(VS.80).aspx
+//
+// The warning pragma:
+// http://msdn.microsoft.com/en-us/library/2c8f766e(VS.80).aspx
+//
+// Using __pragma instead of #pragma inside macros:
+// http://msdn.microsoft.com/en-us/library/d9x1s805.aspx
+
+// MSVC_SUPPRESS_WARNING disables warning |n| for the remainder of the line and
+// for the next line of the source file.
+#define MSVC_SUPPRESS_WARNING(n) __pragma(warning(suppress:n))
+
+// MSVC_PUSH_DISABLE_WARNING pushes |n| onto a stack of warnings to be disabled.
+// The warning remains disabled until popped by MSVC_POP_WARNING.
+#define MSVC_PUSH_DISABLE_WARNING(n) __pragma(warning(push)) \
+ __pragma(warning(disable:n))
+
+// MSVC_PUSH_WARNING_LEVEL pushes |n| as the global warning level. The level
+// remains in effect until popped by MSVC_POP_WARNING(). Use 0 to disable all
+// warnings.
+#define MSVC_PUSH_WARNING_LEVEL(n) __pragma(warning(push, n))
+
+// Pop effects of innermost MSVC_PUSH_* macro.
+#define MSVC_POP_WARNING() __pragma(warning(pop))
+
+#define MSVC_DISABLE_OPTIMIZE() __pragma(optimize("", off))
+#define MSVC_ENABLE_OPTIMIZE() __pragma(optimize("", on))
+
+// Allows |this| to be passed as an argument in constructor initializer lists.
+// This uses push/pop instead of the seemingly simpler suppress feature to avoid
+// having the warning be disabled for more than just |code|.
+//
+// Example usage:
+// Foo::Foo() : x(NULL), ALLOW_THIS_IN_INITIALIZER_LIST(y(this)), z(3) {}
+//
+// Compiler warning C4355: 'this': used in base member initializer list:
+// http://msdn.microsoft.com/en-us/library/3c594ae3(VS.80).aspx
+#define ALLOW_THIS_IN_INITIALIZER_LIST(code) MSVC_PUSH_DISABLE_WARNING(4355) \
+ code \
+ MSVC_POP_WARNING()
+
+// Allows exporting a class that inherits from a non-exported base class.
+// This uses suppress instead of push/pop because the delimiter after the
+// declaration (either "," or "{") has to be placed before the pop macro.
+//
+// Example usage:
+// class EXPORT_API Foo : NON_EXPORTED_BASE(public Bar) {
+//
+// MSVC Compiler warning C4275:
+// non dll-interface class 'Bar' used as base for dll-interface class 'Foo'.
+// Note that this is intended to be used only when no access to the base class
+// can be gained through the derived class. For more info, see
+// http://msdn.microsoft.com/en-us/library/3tdb471s(VS.80).aspx
+#define NON_EXPORTED_BASE(code) MSVC_SUPPRESS_WARNING(4275) \
+ code
+
+#else // Not MSVC
+
+#define MSVC_SUPPRESS_WARNING(n)
+#define MSVC_PUSH_DISABLE_WARNING(n)
+#define MSVC_PUSH_WARNING_LEVEL(n)
+#define MSVC_POP_WARNING()
+#define MSVC_DISABLE_OPTIMIZE()
+#define MSVC_ENABLE_OPTIMIZE()
+#define ALLOW_THIS_IN_INITIALIZER_LIST(code) code
+#define NON_EXPORTED_BASE(code) code
+
+#endif // COMPILER_MSVC
+
+
+// Annotate a variable indicating it's ok if the variable is not used.
+// (Typically used to silence a compiler warning when the assignment
+// is important for some other reason.)
+// Use like:
+// int x ALLOW_UNUSED = ...;
+#if defined(COMPILER_GCC)
+#define ALLOW_UNUSED __attribute__((unused))
+#define NOINLINE __attribute__((noinline))
+#else
+#define ALLOW_UNUSED
+#define NOINLINE
+#endif
+
+// Annotate a virtual method indicating it must be overriding a virtual
+// method in the parent class.
+// Use like:
+// virtual void foo() OVERRIDE;
+#if defined(COMPILER_MSVC)
+#define OVERRIDE override
+#elif defined(__clang__)
+#define OVERRIDE override
+#else
+#define OVERRIDE
+#endif
+
+// Annotate a function indicating the caller must examine the return value.
+// Use like:
+// int foo() WARN_UNUSED_RESULT;
+// To explicitly ignore a result, see |ignore_result()| in <base/basictypes.h>.
+#if defined(COMPILER_GCC)
+#define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
+#else
+#define WARN_UNUSED_RESULT
+#endif
+
+// Tell the compiler a function is using a printf-style format string.
+// |format_param| is the one-based index of the format string parameter;
+// |dots_param| is the one-based index of the "..." parameter.
+// For v*printf functions (which take a va_list), pass 0 for dots_param.
+// (This is undocumented but matches what the system C headers do.)
+#if defined(COMPILER_GCC)
+#define PRINTF_FORMAT(format_param, dots_param) \
+ __attribute__((format(printf, format_param, dots_param)))
+#else
+#define PRINTF_FORMAT(format_param, dots_param)
+#endif
+
+// WPRINTF_FORMAT is the same, but for wide format strings.
+// This doesn't appear to yet be implemented in any compiler.
+// See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=38308 .
+#define WPRINTF_FORMAT(format_param, dots_param)
+// If available, it would look like:
+// __attribute__((format(wprintf, format_param, dots_param)))
+
+#endif // BASE_COMPILER_SPECIFIC_H_
diff --git a/base/file_descriptor_posix.h b/base/file_descriptor_posix.h
new file mode 100644
index 000000000000..6f46ab4986cc
--- /dev/null
+++ b/base/file_descriptor_posix.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_FILE_DESCRIPTOR_POSIX_H_
+#define BASE_FILE_DESCRIPTOR_POSIX_H_
+#pragma once
+
+namespace base {
+
+// -----------------------------------------------------------------------------
+// We introduct a special structure for file descriptors in order that we are
+// able to use template specialisation to special-case their handling.
+//
+// WARNING: (Chromium only) There are subtleties to consider if serialising
+// these objects over IPC. See comments in ipc/ipc_message_utils.h
+// above the template specialisation for this structure.
+// -----------------------------------------------------------------------------
+struct FileDescriptor {
+ FileDescriptor()
+ : fd(-1),
+ auto_close(false) { }
+
+ FileDescriptor(int ifd, bool iauto_close)
+ : fd(ifd),
+ auto_close(iauto_close) { }
+
+ bool operator==(const FileDescriptor& other) const {
+ return (fd == other.fd && auto_close == other.auto_close);
+ }
+
+ // A comparison operator so that we can use these as keys in a std::map.
+ bool operator<(const FileDescriptor& other) const {
+ return other.fd < fd;
+ }
+
+ int fd;
+ // If true, this file descriptor should be closed after it has been used. For
+ // example an IPC system might interpret this flag as indicating that the
+ // file descriptor it has been given should be closed after use.
+ bool auto_close;
+};
+
+} // namespace base
+
+#endif // BASE_FILE_DESCRIPTOR_POSIX_H_
diff --git a/base/hash_tables.h b/base/hash_tables.h
new file mode 100644
index 000000000000..b91d5d48bb6f
--- /dev/null
+++ b/base/hash_tables.h
@@ -0,0 +1,120 @@
+// 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.
+//
+
+//
+// Deal with the differences between Microsoft and GNU implemenations
+// of hash_map. Allows all platforms to use |base::hash_map| and
+// |base::hash_set|.
+// eg:
+// base::hash_map<int> my_map;
+// base::hash_set<int> my_set;
+//
+// NOTE: It is an explicit non-goal of this class to provide a generic hash
+// function for pointers. If you want to hash a pointers to a particular class,
+// please define the template specialization elsewhere (for example, in its
+// header file) and keep it specific to just pointers to that class. This is
+// because identity hashes are not desirable for all types that might show up
+// in containers as pointers.
+
+#ifndef BASE_HASH_TABLES_H_
+#define BASE_HASH_TABLES_H_
+#pragma once
+
+#include "build/build_config.h"
+
+#include "base/string16.h"
+
+#if defined(COMPILER_MSVC)
+#include <hash_map>
+#include <hash_set>
+
+#define BASE_HASH_NAMESPACE stdext
+
+#elif defined(COMPILER_GCC)
+#if defined(OS_ANDROID)
+#define BASE_HASH_NAMESPACE std
+#else
+#define BASE_HASH_NAMESPACE __gnu_cxx
+#endif
+
+// This is a hack to disable the gcc 4.4 warning about hash_map and hash_set
+// being deprecated. We can get rid of this when we upgrade to VS2008 and we
+// can use <tr1/unordered_map> and <tr1/unordered_set>.
+#ifdef __DEPRECATED
+#define CHROME_OLD__DEPRECATED __DEPRECATED
+#undef __DEPRECATED
+#endif
+
+#if defined(OS_ANDROID)
+#include <hash_map>
+#include <hash_set>
+#else
+#include <ext/hash_map>
+#include <ext/hash_set>
+#endif
+
+#include <string>
+
+#ifdef CHROME_OLD__DEPRECATED
+#define __DEPRECATED CHROME_OLD__DEPRECATED
+#undef CHROME_OLD__DEPRECATED
+#endif
+
+namespace BASE_HASH_NAMESPACE {
+
+#if !defined(OS_ANDROID)
+// The GNU C++ library provides identity hash functions for many integral types,
+// but not for |long long|. This hash function will truncate if |size_t| is
+// narrower than |long long|. This is probably good enough for what we will
+// use it for.
+
+#define DEFINE_TRIVIAL_HASH(integral_type) \
+ template<> \
+ struct hash<integral_type> { \
+ std::size_t operator()(integral_type value) const { \
+ return static_cast<std::size_t>(value); \
+ } \
+ }
+
+DEFINE_TRIVIAL_HASH(long long);
+DEFINE_TRIVIAL_HASH(unsigned long long);
+
+#undef DEFINE_TRIVIAL_HASH
+#endif // !defined(OS_ANDROID)
+
+// Implement string hash functions so that strings of various flavors can
+// be used as keys in STL maps and sets. The hash algorithm comes from the
+// GNU C++ library, in <tr1/functional>. It is duplicated here because GCC
+// versions prior to 4.3.2 are unable to compile <tr1/functional> when RTTI
+// is disabled, as it is in our build.
+
+#define DEFINE_STRING_HASH(string_type) \
+ template<> \
+ struct hash<string_type> { \
+ std::size_t operator()(const string_type& s) const { \
+ std::size_t result = 0; \
+ for (string_type::const_iterator i = s.begin(); i != s.end(); ++i) \
+ result = (result * 131) + *i; \
+ return result; \
+ } \
+ }
+
+DEFINE_STRING_HASH(std::string);
+DEFINE_STRING_HASH(string16);
+
+#undef DEFINE_STRING_HASH
+
+} // namespace BASE_HASH_NAMESPACE
+
+#else // COMPILER
+#error define BASE_HASH_NAMESPACE for your compiler
+#endif // COMPILER
+
+namespace base {
+using BASE_HASH_NAMESPACE::hash_map;
+using BASE_HASH_NAMESPACE::hash_set;
+}
+
+#endif // BASE_HASH_TABLES_H_
diff --git a/base/logging.h b/base/logging.h
new file mode 100644
index 000000000000..c18fadadb6c4
--- /dev/null
+++ b/base/logging.h
@@ -0,0 +1,952 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_LOGGING_H_
+#define BASE_LOGGING_H_
+#pragma once
+
+#include <cassert>
+#include <string>
+#include <cstring>
+#include <sstream>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "build/build_config.h"
+
+//
+// Optional message capabilities
+// -----------------------------
+// Assertion failed messages and fatal errors are displayed in a dialog box
+// before the application exits. However, running this UI creates a message
+// loop, which causes application messages to be processed and potentially
+// dispatched to existing application windows. Since the application is in a
+// bad state when this assertion dialog is displayed, these messages may not
+// get processed and hang the dialog, or the application might go crazy.
+//
+// Therefore, it can be beneficial to display the error dialog in a separate
+// process from the main application. When the logging system needs to display
+// a fatal error dialog box, it will look for a program called
+// "DebugMessage.exe" in the same directory as the application executable. It
+// will run this application with the message as the command line, and will
+// not include the name of the application as is traditional for easier
+// parsing.
+//
+// The code for DebugMessage.exe is only one line. In WinMain, do:
+// MessageBox(NULL, GetCommandLineW(), L"Fatal Error", 0);
+//
+// If DebugMessage.exe is not found, the logging code will use a normal
+// MessageBox, potentially causing the problems discussed above.
+
+
+// Instructions
+// ------------
+//
+// Make a bunch of macros for logging. The way to log things is to stream
+// things to LOG(<a particular severity level>). E.g.,
+//
+// LOG(INFO) << "Found " << num_cookies << " cookies";
+//
+// You can also do conditional logging:
+//
+// LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
+//
+// The above will cause log messages to be output on the 1st, 11th, 21st, ...
+// times it is executed. Note that the special COUNTER value is used to
+// identify which repetition is happening.
+//
+// The CHECK(condition) macro is active in both debug and release builds and
+// effectively performs a LOG(FATAL) which terminates the process and
+// generates a crashdump unless a debugger is attached.
+//
+// There are also "debug mode" logging macros like the ones above:
+//
+// DLOG(INFO) << "Found cookies";
+//
+// DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
+//
+// All "debug mode" logging is compiled away to nothing for non-debug mode
+// compiles. LOG_IF and development flags also work well together
+// because the code can be compiled away sometimes.
+//
+// We also have
+//
+// LOG_ASSERT(assertion);
+// DLOG_ASSERT(assertion);
+//
+// which is syntactic sugar for {,D}LOG_IF(FATAL, assert fails) << assertion;
+//
+// There are "verbose level" logging macros. They look like
+//
+// VLOG(1) << "I'm printed when you run the program with --v=1 or more";
+// VLOG(2) << "I'm printed when you run the program with --v=2 or more";
+//
+// These always log at the INFO log level (when they log at all).
+// The verbose logging can also be turned on module-by-module. For instance,
+// --vmodule=profile=2,icon_loader=1,browser_*=3,*/chromeos/*=4 --v=0
+// will cause:
+// a. VLOG(2) and lower messages to be printed from profile.{h,cc}
+// b. VLOG(1) and lower messages to be printed from icon_loader.{h,cc}
+// c. VLOG(3) and lower messages to be printed from files prefixed with
+// "browser"
+// d. VLOG(4) and lower messages to be printed from files under a
+// "chromeos" directory.
+// e. VLOG(0) and lower messages to be printed from elsewhere
+//
+// The wildcarding functionality shown by (c) supports both '*' (match
+// 0 or more characters) and '?' (match any single character)
+// wildcards. Any pattern containing a forward or backward slash will
+// be tested against the whole pathname and not just the module.
+// E.g., "*/foo/bar/*=2" would change the logging level for all code
+// in source files under a "foo/bar" directory.
+//
+// There's also VLOG_IS_ON(n) "verbose level" condition macro. To be used as
+//
+// if (VLOG_IS_ON(2)) {
+// // do some logging preparation and logging
+// // that can't be accomplished with just VLOG(2) << ...;
+// }
+//
+// There is also a VLOG_IF "verbose level" condition macro for sample
+// cases, when some extra computation and preparation for logs is not
+// needed.
+//
+// VLOG_IF(1, (size > 1024))
+// << "I'm printed when size is more than 1024 and when you run the "
+// "program with --v=1 or more";
+//
+// We also override the standard 'assert' to use 'DLOG_ASSERT'.
+//
+// Lastly, there is:
+//
+// PLOG(ERROR) << "Couldn't do foo";
+// DPLOG(ERROR) << "Couldn't do foo";
+// PLOG_IF(ERROR, cond) << "Couldn't do foo";
+// DPLOG_IF(ERROR, cond) << "Couldn't do foo";
+// PCHECK(condition) << "Couldn't do foo";
+// DPCHECK(condition) << "Couldn't do foo";
+//
+// which append the last system error to the message in string form (taken from
+// GetLastError() on Windows and errno on POSIX).
+//
+// The supported severity levels for macros that allow you to specify one
+// are (in increasing order of severity) INFO, WARNING, ERROR, ERROR_REPORT,
+// and FATAL.
+//
+// Very important: logging a message at the FATAL severity level causes
+// the program to terminate (after the message is logged).
+//
+// Note the special severity of ERROR_REPORT only available/relevant in normal
+// mode, which displays error dialog without terminating the program. There is
+// no error dialog for severity ERROR or below in normal mode.
+//
+// There is also the special severity of DFATAL, which logs FATAL in
+// debug mode, ERROR in normal mode.
+
+namespace logging {
+
+// Where to record logging output? A flat file and/or system debug log via
+// OutputDebugString. Defaults on Windows to LOG_ONLY_TO_FILE, and on
+// POSIX to LOG_ONLY_TO_SYSTEM_DEBUG_LOG (aka stderr).
+enum LoggingDestination { LOG_NONE,
+ LOG_ONLY_TO_FILE,
+ LOG_ONLY_TO_SYSTEM_DEBUG_LOG,
+ LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG };
+
+// Indicates that the log file should be locked when being written to.
+// Often, there is no locking, which is fine for a single threaded program.
+// If logging is being done from multiple threads or there can be more than
+// one process doing the logging, the file should be locked during writes to
+// make each log outut atomic. Other writers will block.
+//
+// All processes writing to the log file must have their locking set for it to
+// work properly. Defaults to DONT_LOCK_LOG_FILE.
+enum LogLockingState { LOCK_LOG_FILE, DONT_LOCK_LOG_FILE };
+
+// On startup, should we delete or append to an existing log file (if any)?
+// Defaults to APPEND_TO_OLD_LOG_FILE.
+enum OldFileDeletionState { DELETE_OLD_LOG_FILE, APPEND_TO_OLD_LOG_FILE };
+
+enum DcheckState {
+ DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS,
+ ENABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS
+};
+
+// TODO(avi): do we want to do a unification of character types here?
+#if defined(OS_WIN)
+typedef wchar_t PathChar;
+#else
+typedef char PathChar;
+#endif
+
+// Define different names for the BaseInitLoggingImpl() function depending on
+// whether NDEBUG is defined or not so that we'll fail to link if someone tries
+// to compile logging.cc with NDEBUG but includes logging.h without defining it,
+// or vice versa.
+#if NDEBUG
+#define BaseInitLoggingImpl BaseInitLoggingImpl_built_with_NDEBUG
+#else
+#define BaseInitLoggingImpl BaseInitLoggingImpl_built_without_NDEBUG
+#endif
+
+// Implementation of the InitLogging() method declared below. We use a
+// more-specific name so we can #define it above without affecting other code
+// that has named stuff "InitLogging".
+BASE_EXPORT bool BaseInitLoggingImpl(const PathChar* log_file,
+ LoggingDestination logging_dest,
+ LogLockingState lock_log,
+ OldFileDeletionState delete_old,
+ DcheckState dcheck_state);
+
+// Sets the log file name and other global logging state. Calling this function
+// is recommended, and is normally done at the beginning of application init.
+// If you don't call it, all the flags will be initialized to their default
+// values, and there is a race condition that may leak a critical section
+// object if two threads try to do the first log at the same time.
+// See the definition of the enums above for descriptions and default values.
+//
+// The default log file is initialized to "debug.log" in the application
+// directory. You probably don't want this, especially since the program
+// directory may not be writable on an enduser's system.
+inline bool InitLogging(const PathChar* log_file,
+ LoggingDestination logging_dest,
+ LogLockingState lock_log,
+ OldFileDeletionState delete_old,
+ DcheckState dcheck_state) {
+ return BaseInitLoggingImpl(log_file, logging_dest, lock_log,
+ delete_old, dcheck_state);
+}
+
+// Sets the log level. Anything at or above this level will be written to the
+// log file/displayed to the user (if applicable). Anything below this level
+// will be silently ignored. The log level defaults to 0 (everything is logged
+// up to level INFO) if this function is not called.
+// Note that log messages for VLOG(x) are logged at level -x, so setting
+// the min log level to negative values enables verbose logging.
+BASE_EXPORT void SetMinLogLevel(int level);
+
+// Gets the current log level.
+BASE_EXPORT int GetMinLogLevel();
+
+// Gets the VLOG default verbosity level.
+BASE_EXPORT int GetVlogVerbosity();
+
+// Gets the current vlog level for the given file (usually taken from
+// __FILE__).
+
+// Note that |N| is the size *with* the null terminator.
+BASE_EXPORT int GetVlogLevelHelper(const char* file_start, size_t N);
+
+template <size_t N>
+int GetVlogLevel(const char (&file)[N]) {
+ return GetVlogLevelHelper(file, N);
+}
+
+// Sets the common items you want to be prepended to each log message.
+// process and thread IDs default to off, the timestamp defaults to on.
+// If this function is not called, logging defaults to writing the timestamp
+// only.
+BASE_EXPORT void SetLogItems(bool enable_process_id, bool enable_thread_id,
+ bool enable_timestamp, bool enable_tickcount);
+
+// Sets whether or not you'd like to see fatal debug messages popped up in
+// a dialog box or not.
+// Dialogs are not shown by default.
+BASE_EXPORT void SetShowErrorDialogs(bool enable_dialogs);
+
+// Sets the Log Assert Handler that will be used to notify of check failures.
+// The default handler shows a dialog box and then terminate the process,
+// however clients can use this function to override with their own handling
+// (e.g. a silent one for Unit Tests)
+typedef void (*LogAssertHandlerFunction)(const std::string& str);
+BASE_EXPORT void SetLogAssertHandler(LogAssertHandlerFunction handler);
+
+// Sets the Log Report Handler that will be used to notify of check failures
+// in non-debug mode. The default handler shows a dialog box and continues
+// the execution, however clients can use this function to override with their
+// own handling.
+typedef void (*LogReportHandlerFunction)(const std::string& str);
+BASE_EXPORT void SetLogReportHandler(LogReportHandlerFunction handler);
+
+// Sets the Log Message Handler that gets passed every log message before
+// it's sent to other log destinations (if any).
+// Returns true to signal that it handled the message and the message
+// should not be sent to other log destinations.
+typedef bool (*LogMessageHandlerFunction)(int severity,
+ const char* file, int line, size_t message_start, const std::string& str);
+BASE_EXPORT void SetLogMessageHandler(LogMessageHandlerFunction handler);
+BASE_EXPORT LogMessageHandlerFunction GetLogMessageHandler();
+
+typedef int LogSeverity;
+const LogSeverity LOG_VERBOSE = -1; // This is level 1 verbosity
+// Note: the log severities are used to index into the array of names,
+// see log_severity_names.
+const LogSeverity LOG_INFO = 0;
+const LogSeverity LOG_WARNING = 1;
+const LogSeverity LOG_ERROR = 2;
+const LogSeverity LOG_ERROR_REPORT = 3;
+const LogSeverity LOG_FATAL = 4;
+const LogSeverity LOG_NUM_SEVERITIES = 5;
+
+// LOG_DFATAL is LOG_FATAL in debug mode, ERROR in normal mode
+#ifdef NDEBUG
+const LogSeverity LOG_DFATAL = LOG_ERROR;
+#else
+const LogSeverity LOG_DFATAL = LOG_FATAL;
+#endif
+
+// A few definitions of macros that don't generate much code. These are used
+// by LOG() and LOG_IF, etc. Since these are used all over our code, it's
+// better to have compact code for these operations.
+#define COMPACT_GOOGLE_LOG_EX_INFO(ClassName, ...) \
+ logging::ClassName(__FILE__, __LINE__, logging::LOG_INFO , ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_EX_WARNING(ClassName, ...) \
+ logging::ClassName(__FILE__, __LINE__, logging::LOG_WARNING , ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_EX_ERROR(ClassName, ...) \
+ logging::ClassName(__FILE__, __LINE__, logging::LOG_ERROR , ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_EX_ERROR_REPORT(ClassName, ...) \
+ logging::ClassName(__FILE__, __LINE__, \
+ logging::LOG_ERROR_REPORT , ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_EX_FATAL(ClassName, ...) \
+ logging::ClassName(__FILE__, __LINE__, logging::LOG_FATAL , ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_EX_DFATAL(ClassName, ...) \
+ logging::ClassName(__FILE__, __LINE__, logging::LOG_DFATAL , ##__VA_ARGS__)
+
+#define COMPACT_GOOGLE_LOG_INFO \
+ COMPACT_GOOGLE_LOG_EX_INFO(LogMessage)
+#define COMPACT_GOOGLE_LOG_WARNING \
+ COMPACT_GOOGLE_LOG_EX_WARNING(LogMessage)
+#define COMPACT_GOOGLE_LOG_ERROR \
+ COMPACT_GOOGLE_LOG_EX_ERROR(LogMessage)
+#define COMPACT_GOOGLE_LOG_ERROR_REPORT \
+ COMPACT_GOOGLE_LOG_EX_ERROR_REPORT(LogMessage)
+#define COMPACT_GOOGLE_LOG_FATAL \
+ COMPACT_GOOGLE_LOG_EX_FATAL(LogMessage)
+#define COMPACT_GOOGLE_LOG_DFATAL \
+ COMPACT_GOOGLE_LOG_EX_DFATAL(LogMessage)
+
+// wingdi.h defines ERROR to be 0. When we call LOG(ERROR), it gets
+// substituted with 0, and it expands to COMPACT_GOOGLE_LOG_0. To allow us
+// to keep using this syntax, we define this macro to do the same thing
+// as COMPACT_GOOGLE_LOG_ERROR, and also define ERROR the same way that
+// the Windows SDK does for consistency.
+#define ERROR 0
+#define COMPACT_GOOGLE_LOG_EX_0(ClassName, ...) \
+ COMPACT_GOOGLE_LOG_EX_ERROR(ClassName , ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_0 COMPACT_GOOGLE_LOG_ERROR
+// Needed for LOG_IS_ON(ERROR).
+const LogSeverity LOG_0 = LOG_ERROR;
+
+// As special cases, we can assume that LOG_IS_ON(ERROR_REPORT) and
+// LOG_IS_ON(FATAL) always hold. Also, LOG_IS_ON(DFATAL) always holds
+// in debug mode. In particular, CHECK()s will always fire if they
+// fail.
+#define LOG_IS_ON(severity) \
+ ((::logging::LOG_ ## severity) >= ::logging::GetMinLogLevel())
+
+// We can't do any caching tricks with VLOG_IS_ON() like the
+// google-glog version since it requires GCC extensions. This means
+// that using the v-logging functions in conjunction with --vmodule
+// may be slow.
+#define VLOG_IS_ON(verboselevel) \
+ ((verboselevel) <= ::logging::GetVlogLevel(__FILE__))
+
+// Helper macro which avoids evaluating the arguments to a stream if
+// the condition doesn't hold.
+#define LAZY_STREAM(stream, condition) \
+ !(condition) ? (void) 0 : ::logging::LogMessageVoidify() & (stream)
+
+// We use the preprocessor's merging operator, "##", so that, e.g.,
+// LOG(INFO) becomes the token COMPACT_GOOGLE_LOG_INFO. There's some funny
+// subtle difference between ostream member streaming functions (e.g.,
+// ostream::operator<<(int) and ostream non-member streaming functions
+// (e.g., ::operator<<(ostream&, string&): it turns out that it's
+// impossible to stream something like a string directly to an unnamed
+// ostream. We employ a neat hack by calling the stream() member
+// function of LogMessage which seems to avoid the problem.
+#define LOG_STREAM(severity) COMPACT_GOOGLE_LOG_ ## severity.stream()
+
+#define LOG(severity) LAZY_STREAM(LOG_STREAM(severity), LOG_IS_ON(severity))
+#define LOG_IF(severity, condition) \
+ LAZY_STREAM(LOG_STREAM(severity), LOG_IS_ON(severity) && (condition))
+
+#define SYSLOG(severity) LOG(severity)
+#define SYSLOG_IF(severity, condition) LOG_IF(severity, condition)
+
+// The VLOG macros log with negative verbosities.
+#define VLOG_STREAM(verbose_level) \
+ logging::LogMessage(__FILE__, __LINE__, -verbose_level).stream()
+
+#define VLOG(verbose_level) \
+ LAZY_STREAM(VLOG_STREAM(verbose_level), VLOG_IS_ON(verbose_level))
+
+#define VLOG_IF(verbose_level, condition) \
+ LAZY_STREAM(VLOG_STREAM(verbose_level), \
+ VLOG_IS_ON(verbose_level) && (condition))
+
+#if defined (OS_WIN)
+#define VPLOG_STREAM(verbose_level) \
+ logging::Win32ErrorLogMessage(__FILE__, __LINE__, -verbose_level, \
+ ::logging::GetLastSystemErrorCode()).stream()
+#elif defined(OS_POSIX)
+#define VPLOG_STREAM(verbose_level) \
+ logging::ErrnoLogMessage(__FILE__, __LINE__, -verbose_level, \
+ ::logging::GetLastSystemErrorCode()).stream()
+#endif
+
+#define VPLOG(verbose_level) \
+ LAZY_STREAM(VPLOG_STREAM(verbose_level), VLOG_IS_ON(verbose_level))
+
+#define VPLOG_IF(verbose_level, condition) \
+ LAZY_STREAM(VPLOG_STREAM(verbose_level), \
+ VLOG_IS_ON(verbose_level) && (condition))
+
+// TODO(akalin): Add more VLOG variants, e.g. VPLOG.
+
+#define LOG_ASSERT(condition) \
+ LOG_IF(FATAL, !(condition)) << "Assert failed: " #condition ". "
+#define SYSLOG_ASSERT(condition) \
+ SYSLOG_IF(FATAL, !(condition)) << "Assert failed: " #condition ". "
+
+#if defined(OS_WIN)
+#define LOG_GETLASTERROR_STREAM(severity) \
+ COMPACT_GOOGLE_LOG_EX_ ## severity(Win32ErrorLogMessage, \
+ ::logging::GetLastSystemErrorCode()).stream()
+#define LOG_GETLASTERROR(severity) \
+ LAZY_STREAM(LOG_GETLASTERROR_STREAM(severity), LOG_IS_ON(severity))
+#define LOG_GETLASTERROR_MODULE_STREAM(severity, module) \
+ COMPACT_GOOGLE_LOG_EX_ ## severity(Win32ErrorLogMessage, \
+ ::logging::GetLastSystemErrorCode(), module).stream()
+#define LOG_GETLASTERROR_MODULE(severity, module) \
+ LAZY_STREAM(LOG_GETLASTERROR_STREAM(severity, module), \
+ LOG_IS_ON(severity))
+// PLOG_STREAM is used by PLOG, which is the usual error logging macro
+// for each platform.
+#define PLOG_STREAM(severity) LOG_GETLASTERROR_STREAM(severity)
+#elif defined(OS_POSIX)
+#define LOG_ERRNO_STREAM(severity) \
+ COMPACT_GOOGLE_LOG_EX_ ## severity(ErrnoLogMessage, \
+ ::logging::GetLastSystemErrorCode()).stream()
+#define LOG_ERRNO(severity) \
+ LAZY_STREAM(LOG_ERRNO_STREAM(severity), LOG_IS_ON(severity))
+// PLOG_STREAM is used by PLOG, which is the usual error logging macro
+// for each platform.
+#define PLOG_STREAM(severity) LOG_ERRNO_STREAM(severity)
+// TODO(tschmelcher): Should we add OSStatus logging for Mac?
+#endif
+
+#define PLOG(severity) \
+ LAZY_STREAM(PLOG_STREAM(severity), LOG_IS_ON(severity))
+
+#define PLOG_IF(severity, condition) \
+ LAZY_STREAM(PLOG_STREAM(severity), LOG_IS_ON(severity) && (condition))
+
+// CHECK dies with a fatal error if condition is not true. It is *not*
+// controlled by NDEBUG, so the check will be executed regardless of
+// compilation mode.
+//
+// We make sure CHECK et al. always evaluates their arguments, as
+// doing CHECK(FunctionWithSideEffect()) is a common idiom.
+#define CHECK(condition) \
+ LAZY_STREAM(LOG_STREAM(FATAL), !(condition)) \
+ << "Check failed: " #condition ". "
+
+#define PCHECK(condition) \
+ LAZY_STREAM(PLOG_STREAM(FATAL), !(condition)) \
+ << "Check failed: " #condition ". "
+
+// Build the error message string. This is separate from the "Impl"
+// function template because it is not performance critical and so can
+// be out of line, while the "Impl" code should be inline. Caller
+// takes ownership of the returned string.
+template<class t1, class t2>
+std::string* MakeCheckOpString(const t1& v1, const t2& v2, const char* names) {
+ std::ostringstream ss;
+ ss << names << " (" << v1 << " vs. " << v2 << ")";
+ std::string* msg = new std::string(ss.str());
+ return msg;
+}
+
+// MSVC doesn't like complex extern templates and DLLs.
+#if !defined(COMPILER_MSVC) && !defined(COMPONENT_BUILD)
+// Commonly used instantiations of MakeCheckOpString<>. Explicitly instantiated
+// in logging.cc.
+extern template std::string* MakeCheckOpString<int, int>(
+ const int&, const int&, const char* names);
+extern template std::string* MakeCheckOpString<unsigned long, unsigned long>(
+ const unsigned long&, const unsigned long&, const char* names);
+extern template std::string* MakeCheckOpString<unsigned long, unsigned int>(
+ const unsigned long&, const unsigned int&, const char* names);
+extern template std::string* MakeCheckOpString<unsigned int, unsigned long>(
+ const unsigned int&, const unsigned long&, const char* names);
+extern template std::string* MakeCheckOpString<std::string, std::string>(
+ const std::string&, const std::string&, const char* name);
+#endif
+
+// Helper macro for binary operators.
+// Don't use this macro directly in your code, use CHECK_EQ et al below.
+//
+// TODO(akalin): Rewrite this so that constructs like if (...)
+// CHECK_EQ(...) else { ... } work properly.
+#define CHECK_OP(name, op, val1, val2) \
+ if (std::string* _result = \
+ logging::Check##name##Impl((val1), (val2), \
+ #val1 " " #op " " #val2)) \
+ logging::LogMessage(__FILE__, __LINE__, _result).stream()
+
+// Helper functions for CHECK_OP macro.
+// The (int, int) specialization works around the issue that the compiler
+// will not instantiate the template version of the function on values of
+// unnamed enum type - see comment below.
+#define DEFINE_CHECK_OP_IMPL(name, op) \
+ template <class t1, class t2> \
+ inline std::string* Check##name##Impl(const t1& v1, const t2& v2, \
+ const char* names) { \
+ if (v1 op v2) return NULL; \
+ else return MakeCheckOpString(v1, v2, names); \
+ } \
+ inline std::string* Check##name##Impl(int v1, int v2, const char* names) { \
+ if (v1 op v2) return NULL; \
+ else return MakeCheckOpString(v1, v2, names); \
+ }
+DEFINE_CHECK_OP_IMPL(EQ, ==)
+DEFINE_CHECK_OP_IMPL(NE, !=)
+DEFINE_CHECK_OP_IMPL(LE, <=)
+DEFINE_CHECK_OP_IMPL(LT, < )
+DEFINE_CHECK_OP_IMPL(GE, >=)
+DEFINE_CHECK_OP_IMPL(GT, > )
+#undef DEFINE_CHECK_OP_IMPL
+
+#define CHECK_EQ(val1, val2) CHECK_OP(EQ, ==, val1, val2)
+#define CHECK_NE(val1, val2) CHECK_OP(NE, !=, val1, val2)
+#define CHECK_LE(val1, val2) CHECK_OP(LE, <=, val1, val2)
+#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)
+
+// http://crbug.com/16512 is open for a real fix for this. For now, Windows
+// uses OFFICIAL_BUILD and other platforms use the branding flag when NDEBUG is
+// defined.
+#if ( defined(OS_WIN) && defined(OFFICIAL_BUILD)) || \
+ (!defined(OS_WIN) && defined(NDEBUG) && defined(GOOGLE_CHROME_BUILD))
+// Used by unit tests.
+#define LOGGING_IS_OFFICIAL_BUILD
+
+// In order to have optimized code for official builds, remove DLOGs and
+// DCHECKs.
+#define ENABLE_DLOG 0
+#define ENABLE_DCHECK 0
+
+#elif defined(NDEBUG)
+// Otherwise, if we're a release build, remove DLOGs but not DCHECKs
+// (since those can still be turned on via a command-line flag).
+#define ENABLE_DLOG 0
+#define ENABLE_DCHECK 1
+
+#else
+// Otherwise, we're a debug build so enable DLOGs and DCHECKs.
+#define ENABLE_DLOG 1
+#define ENABLE_DCHECK 1
+#endif
+
+// Definitions for DLOG et al.
+
+#if ENABLE_DLOG
+
+#define DLOG_IS_ON(severity) LOG_IS_ON(severity)
+#define DLOG_IF(severity, condition) LOG_IF(severity, condition)
+#define DLOG_ASSERT(condition) LOG_ASSERT(condition)
+#define DPLOG_IF(severity, condition) PLOG_IF(severity, condition)
+#define DVLOG_IF(verboselevel, condition) VLOG_IF(verboselevel, condition)
+#define DVPLOG_IF(verboselevel, condition) VPLOG_IF(verboselevel, condition)
+
+#else // ENABLE_DLOG
+
+// If ENABLE_DLOG is off, we want to avoid emitting any references to
+// |condition| (which may reference a variable defined only if NDEBUG
+// is not defined). Contrast this with DCHECK et al., which has
+// different behavior.
+
+#define DLOG_EAT_STREAM_PARAMETERS \
+ true ? (void) 0 : ::logging::LogMessageVoidify() & LOG_STREAM(FATAL)
+
+#define DLOG_IS_ON(severity) false
+#define DLOG_IF(severity, condition) DLOG_EAT_STREAM_PARAMETERS
+#define DLOG_ASSERT(condition) DLOG_EAT_STREAM_PARAMETERS
+#define DPLOG_IF(severity, condition) DLOG_EAT_STREAM_PARAMETERS
+#define DVLOG_IF(verboselevel, condition) DLOG_EAT_STREAM_PARAMETERS
+#define DVPLOG_IF(verboselevel, condition) DLOG_EAT_STREAM_PARAMETERS
+
+#endif // ENABLE_DLOG
+
+// DEBUG_MODE is for uses like
+// if (DEBUG_MODE) foo.CheckThatFoo();
+// instead of
+// #ifndef NDEBUG
+// foo.CheckThatFoo();
+// #endif
+//
+// We tie its state to ENABLE_DLOG.
+enum { DEBUG_MODE = ENABLE_DLOG };
+
+#undef ENABLE_DLOG
+
+#define DLOG(severity) \
+ LAZY_STREAM(LOG_STREAM(severity), DLOG_IS_ON(severity))
+
+#if defined(OS_WIN)
+#define DLOG_GETLASTERROR(severity) \
+ LAZY_STREAM(LOG_GETLASTERROR_STREAM(severity), DLOG_IS_ON(severity))
+#define DLOG_GETLASTERROR_MODULE(severity, module) \
+ LAZY_STREAM(LOG_GETLASTERROR_STREAM(severity, module), \
+ DLOG_IS_ON(severity))
+#elif defined(OS_POSIX)
+#define DLOG_ERRNO(severity) \
+ LAZY_STREAM(LOG_ERRNO_STREAM(severity), DLOG_IS_ON(severity))
+#endif
+
+#define DPLOG(severity) \
+ LAZY_STREAM(PLOG_STREAM(severity), DLOG_IS_ON(severity))
+
+#define DVLOG(verboselevel) DLOG_IF(INFO, VLOG_IS_ON(verboselevel))
+
+#define DVPLOG(verboselevel) DVPLOG_IF(verboselevel, VLOG_IS_ON(verboselevel))
+
+// Definitions for DCHECK et al.
+
+#if ENABLE_DCHECK
+
+#if defined(NDEBUG)
+
+#define COMPACT_GOOGLE_LOG_EX_DCHECK(ClassName, ...) \
+ COMPACT_GOOGLE_LOG_EX_ERROR_REPORT(ClassName , ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_DCHECK COMPACT_GOOGLE_LOG_ERROR_REPORT
+const LogSeverity LOG_DCHECK = LOG_ERROR_REPORT;
+BASE_EXPORT extern DcheckState g_dcheck_state;
+#define DCHECK_IS_ON() \
+ ((::logging::g_dcheck_state == \
+ ::logging::ENABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS) && \
+ LOG_IS_ON(DCHECK))
+
+#else // defined(NDEBUG)
+
+// On a regular debug build, we want to have DCHECKs enabled.
+#define COMPACT_GOOGLE_LOG_EX_DCHECK(ClassName, ...) \
+ COMPACT_GOOGLE_LOG_EX_FATAL(ClassName , ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_DCHECK COMPACT_GOOGLE_LOG_FATAL
+const LogSeverity LOG_DCHECK = LOG_FATAL;
+#define DCHECK_IS_ON() true
+
+#endif // defined(NDEBUG)
+
+#else // ENABLE_DCHECK
+
+// These are just dummy values since DCHECK_IS_ON() is always false in
+// this case.
+#define COMPACT_GOOGLE_LOG_EX_DCHECK(ClassName, ...) \
+ COMPACT_GOOGLE_LOG_EX_INFO(ClassName , ##__VA_ARGS__)
+#define COMPACT_GOOGLE_LOG_DCHECK COMPACT_GOOGLE_LOG_INFO
+const LogSeverity LOG_DCHECK = LOG_INFO;
+#define DCHECK_IS_ON() false
+
+#endif // ENABLE_DCHECK
+#undef ENABLE_DCHECK
+
+// DCHECK et al. make sure to reference |condition| regardless of
+// whether DCHECKs are enabled; this is so that we don't get unused
+// variable warnings if the only use of a variable is in a DCHECK.
+// This behavior is different from DLOG_IF et al.
+
+#define DCHECK(condition) \
+ LAZY_STREAM(LOG_STREAM(DCHECK), DCHECK_IS_ON() && !(condition)) \
+ << "Check failed: " #condition ". "
+
+#define DPCHECK(condition) \
+ LAZY_STREAM(PLOG_STREAM(DCHECK), DCHECK_IS_ON() && !(condition)) \
+ << "Check failed: " #condition ". "
+
+// Helper macro for binary operators.
+// Don't use this macro directly in your code, use DCHECK_EQ et al below.
+#define DCHECK_OP(name, op, val1, val2) \
+ if (DCHECK_IS_ON()) \
+ if (std::string* _result = \
+ logging::Check##name##Impl((val1), (val2), \
+ #val1 " " #op " " #val2)) \
+ logging::LogMessage( \
+ __FILE__, __LINE__, ::logging::LOG_DCHECK, \
+ _result).stream()
+
+// Equality/Inequality checks - compare two values, and log a
+// LOG_DCHECK message including the two values when the result is not
+// as expected. The values must have operator<<(ostream, ...)
+// defined.
+//
+// You may append to the error message like so:
+// DCHECK_NE(1, 2) << ": The world must be ending!";
+//
+// We are very careful to ensure that each argument is evaluated exactly
+// once, and that anything which is legal to pass as a function argument is
+// legal here. In particular, the arguments may be temporary expressions
+// which will end up being destroyed at the end of the apparent statement,
+// for example:
+// DCHECK_EQ(string("abc")[1], 'b');
+//
+// WARNING: These may not compile correctly if one of the arguments is a pointer
+// and the other is NULL. To work around this, simply static_cast NULL to the
+// type of the desired pointer.
+
+#define DCHECK_EQ(val1, val2) DCHECK_OP(EQ, ==, val1, val2)
+#define DCHECK_NE(val1, val2) DCHECK_OP(NE, !=, val1, val2)
+#define DCHECK_LE(val1, val2) DCHECK_OP(LE, <=, val1, val2)
+#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)
+
+#if defined(OS_ANDROID) && !defined(OFFICIAL_BUILD)
+// TODO(port): fix once "enough" works
+#define NOTREACHED() LOG(ERROR) << "NOTREACHED()"
+#else
+#define NOTREACHED() DCHECK(false)
+#endif
+
+// Redefine the standard assert to use our nice log files
+#undef assert
+#define assert(x) DLOG_ASSERT(x)
+
+// This class more or less represents a particular log message. You
+// create an instance of LogMessage and then stream stuff to it.
+// When you finish streaming to it, ~LogMessage is called and the
+// full message gets streamed to the appropriate destination.
+//
+// You shouldn't actually use LogMessage's constructor to log things,
+// though. You should use the LOG() macro (and variants thereof)
+// above.
+class BASE_EXPORT LogMessage {
+ public:
+ LogMessage(const char* file, int line, LogSeverity severity, int ctr);
+
+ // Two special constructors that generate reduced amounts of code at
+ // LOG call sites for common cases.
+ //
+ // Used for LOG(INFO): Implied are:
+ // severity = LOG_INFO, ctr = 0
+ //
+ // Using this constructor instead of the more complex constructor above
+ // saves a couple of bytes per call site.
+ LogMessage(const char* file, int line);
+
+ // Used for LOG(severity) where severity != INFO. Implied
+ // are: ctr = 0
+ //
+ // Using this constructor instead of the more complex constructor above
+ // saves a couple of bytes per call site.
+ LogMessage(const char* file, int line, LogSeverity severity);
+
+ // A special constructor used for check failures. Takes ownership
+ // of the given string.
+ // Implied severity = LOG_FATAL
+ LogMessage(const char* file, int line, std::string* result);
+
+ // A special constructor used for check failures, with the option to
+ // specify severity. Takes ownership of the given string.
+ LogMessage(const char* file, int line, LogSeverity severity,
+ std::string* result);
+
+ ~LogMessage();
+
+ std::ostream& stream() { return stream_; }
+
+ private:
+ void Init(const char* file, int line);
+
+ LogSeverity severity_;
+ std::ostringstream stream_;
+ size_t message_start_; // Offset of the start of the message (past prefix
+ // info).
+ // The file and line information passed in to the constructor.
+ const char* file_;
+ const int line_;
+
+#if defined(OS_WIN)
+ // Stores the current value of GetLastError in the constructor and restores
+ // it in the destructor by calling SetLastError.
+ // This is useful since the LogMessage class uses a lot of Win32 calls
+ // that will lose the value of GLE and the code that called the log function
+ // will have lost the thread error value when the log call returns.
+ class SaveLastError {
+ public:
+ SaveLastError();
+ ~SaveLastError();
+
+ unsigned long get_error() const { return last_error_; }
+
+ protected:
+ unsigned long last_error_;
+ };
+
+ SaveLastError last_error_;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(LogMessage);
+};
+
+// A non-macro interface to the log facility; (useful
+// when the logging level is not a compile-time constant).
+inline void LogAtLevel(int const log_level, std::string const &msg) {
+ LogMessage(__FILE__, __LINE__, log_level).stream() << msg;
+}
+
+// This class is used to explicitly ignore values in the conditional
+// logging macros. This avoids compiler warnings like "value computed
+// is not used" and "statement has no effect".
+class LogMessageVoidify {
+ public:
+ LogMessageVoidify() { }
+ // This has to be an operator with a precedence lower than << but
+ // higher than ?:
+ void operator&(std::ostream&) { }
+};
+
+#if defined(OS_WIN)
+typedef unsigned long SystemErrorCode;
+#elif defined(OS_POSIX)
+typedef int SystemErrorCode;
+#endif
+
+// Alias for ::GetLastError() on Windows and errno on POSIX. Avoids having to
+// pull in windows.h just for GetLastError() and DWORD.
+BASE_EXPORT SystemErrorCode GetLastSystemErrorCode();
+
+#if defined(OS_WIN)
+// Appends a formatted system message of the GetLastError() type.
+class BASE_EXPORT Win32ErrorLogMessage {
+ public:
+ Win32ErrorLogMessage(const char* file,
+ int line,
+ LogSeverity severity,
+ SystemErrorCode err,
+ const char* module);
+
+ Win32ErrorLogMessage(const char* file,
+ int line,
+ LogSeverity severity,
+ SystemErrorCode err);
+
+ // Appends the error message before destructing the encapsulated class.
+ ~Win32ErrorLogMessage();
+
+ std::ostream& stream() { return log_message_.stream(); }
+
+ private:
+ SystemErrorCode err_;
+ // Optional name of the module defining the error.
+ const char* module_;
+ LogMessage log_message_;
+
+ DISALLOW_COPY_AND_ASSIGN(Win32ErrorLogMessage);
+};
+#elif defined(OS_POSIX)
+// Appends a formatted system message of the errno type
+class BASE_EXPORT ErrnoLogMessage {
+ public:
+ ErrnoLogMessage(const char* file,
+ int line,
+ LogSeverity severity,
+ SystemErrorCode err);
+
+ // Appends the error message before destructing the encapsulated class.
+ ~ErrnoLogMessage();
+
+ std::ostream& stream() { return log_message_.stream(); }
+
+ private:
+ SystemErrorCode err_;
+ LogMessage log_message_;
+
+ DISALLOW_COPY_AND_ASSIGN(ErrnoLogMessage);
+};
+#endif // OS_WIN
+
+// Closes the log file explicitly if open.
+// NOTE: Since the log file is opened as necessary by the action of logging
+// statements, there's no guarantee that it will stay closed
+// after this call.
+BASE_EXPORT void CloseLogFile();
+
+// Async signal safe logging mechanism.
+BASE_EXPORT void RawLog(int level, const char* message);
+
+#define RAW_LOG(level, message) logging::RawLog(logging::LOG_ ## level, message)
+
+#define RAW_CHECK(condition) \
+ do { \
+ if (!(condition)) \
+ logging::RawLog(logging::LOG_FATAL, "Check failed: " #condition "\n"); \
+ } while (0)
+
+} // namespace logging
+
+// These functions are provided as a convenience for logging, which is where we
+// use streams (it is against Google style to use streams in other places). It
+// is designed to allow you to emit non-ASCII Unicode strings to the log file,
+// which is normally ASCII. It is relatively slow, so try not to use it for
+// common cases. Non-ASCII characters will be converted to UTF-8 by these
+// operators.
+BASE_EXPORT std::ostream& operator<<(std::ostream& out, const wchar_t* wstr);
+inline std::ostream& operator<<(std::ostream& out, const std::wstring& wstr) {
+ return out << wstr.c_str();
+}
+
+// The NOTIMPLEMENTED() macro annotates codepaths which have
+// not been implemented yet.
+//
+// The implementation of this macro is controlled by NOTIMPLEMENTED_POLICY:
+// 0 -- Do nothing (stripped by compiler)
+// 1 -- Warn at compile time
+// 2 -- Fail at compile time
+// 3 -- Fail at runtime (DCHECK)
+// 4 -- [default] LOG(ERROR) at runtime
+// 5 -- LOG(ERROR) at runtime, only once per call-site
+
+#ifndef NOTIMPLEMENTED_POLICY
+// Select default policy: LOG(ERROR)
+#define NOTIMPLEMENTED_POLICY 4
+#endif
+
+#if defined(COMPILER_GCC)
+// On Linux, with GCC, we can use __PRETTY_FUNCTION__ to get the demangled name
+// of the current function in the NOTIMPLEMENTED message.
+#define NOTIMPLEMENTED_MSG "Not implemented reached in " << __PRETTY_FUNCTION__
+#else
+#define NOTIMPLEMENTED_MSG "NOT IMPLEMENTED"
+#endif
+
+#if NOTIMPLEMENTED_POLICY == 0
+#define NOTIMPLEMENTED() ;
+#elif NOTIMPLEMENTED_POLICY == 1
+// TODO, figure out how to generate a warning
+#define NOTIMPLEMENTED() COMPILE_ASSERT(false, NOT_IMPLEMENTED)
+#elif NOTIMPLEMENTED_POLICY == 2
+#define NOTIMPLEMENTED() COMPILE_ASSERT(false, NOT_IMPLEMENTED)
+#elif NOTIMPLEMENTED_POLICY == 3
+#define NOTIMPLEMENTED() NOTREACHED()
+#elif NOTIMPLEMENTED_POLICY == 4
+#define NOTIMPLEMENTED() LOG(ERROR) << NOTIMPLEMENTED_MSG
+#elif NOTIMPLEMENTED_POLICY == 5
+#define NOTIMPLEMENTED() do {\
+ static int count = 0;\
+ LOG_IF(ERROR, 0 == count++) << NOTIMPLEMENTED_MSG;\
+} while(0)
+#endif
+
+namespace base {
+
+class StringPiece;
+
+// Allows StringPiece to be logged.
+BASE_EXPORT std::ostream& operator<<(std::ostream& o, const StringPiece& piece);
+
+} // namespace base
+
+#endif // BASE_LOGGING_H_
diff --git a/base/memory/ref_counted.cc b/base/memory/ref_counted.cc
new file mode 100644
index 000000000000..31ad5098cd0f
--- /dev/null
+++ b/base/memory/ref_counted.cc
@@ -0,0 +1,95 @@
+// 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/memory/ref_counted.h"
+
+#include "base/logging.h"
+#include "base/threading/thread_collision_warner.h"
+
+namespace base {
+
+namespace subtle {
+
+RefCountedBase::RefCountedBase()
+ : ref_count_(0)
+#ifndef NDEBUG
+ , in_dtor_(false)
+#endif
+ {
+}
+
+RefCountedBase::~RefCountedBase() {
+#ifndef NDEBUG
+ DCHECK(in_dtor_) << "RefCounted object deleted without calling Release()";
+#endif
+}
+
+void RefCountedBase::AddRef() const {
+ // TODO(maruel): Add back once it doesn't assert 500 times/sec.
+ // Current thread books the critical section "AddRelease" without release it.
+ // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_);
+#ifndef NDEBUG
+ DCHECK(!in_dtor_);
+#endif
+ ++ref_count_;
+}
+
+bool RefCountedBase::Release() const {
+ // TODO(maruel): Add back once it doesn't assert 500 times/sec.
+ // Current thread books the critical section "AddRelease" without release it.
+ // DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_);
+#ifndef NDEBUG
+ DCHECK(!in_dtor_);
+#endif
+ if (--ref_count_ == 0) {
+#ifndef NDEBUG
+ in_dtor_ = true;
+#endif
+ return true;
+ }
+ return false;
+}
+
+bool RefCountedThreadSafeBase::HasOneRef() const {
+ return AtomicRefCountIsOne(
+ &const_cast<RefCountedThreadSafeBase*>(this)->ref_count_);
+}
+
+RefCountedThreadSafeBase::RefCountedThreadSafeBase() : ref_count_(0) {
+#ifndef NDEBUG
+ in_dtor_ = false;
+#endif
+}
+
+RefCountedThreadSafeBase::~RefCountedThreadSafeBase() {
+#ifndef NDEBUG
+ DCHECK(in_dtor_) << "RefCountedThreadSafe object deleted without "
+ "calling Release()";
+#endif
+}
+
+void RefCountedThreadSafeBase::AddRef() const {
+#ifndef NDEBUG
+ DCHECK(!in_dtor_);
+#endif
+ AtomicRefCountInc(&ref_count_);
+}
+
+bool RefCountedThreadSafeBase::Release() const {
+#ifndef NDEBUG
+ DCHECK(!in_dtor_);
+ DCHECK(!AtomicRefCountIsZero(&ref_count_));
+#endif
+ if (!AtomicRefCountDec(&ref_count_)) {
+#ifndef NDEBUG
+ in_dtor_ = true;
+#endif
+ return true;
+ }
+ return false;
+}
+
+} // namespace subtle
+
+} // namespace base
diff --git a/base/memory/ref_counted.h b/base/memory/ref_counted.h
new file mode 100644
index 000000000000..439fda44d1ad
--- /dev/null
+++ b/base/memory/ref_counted.h
@@ -0,0 +1,299 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_REF_COUNTED_H_
+#define BASE_MEMORY_REF_COUNTED_H_
+#pragma once
+
+#include "base/atomic_ref_count.h"
+#include "base/base_export.h"
+#include "base/threading/thread_collision_warner.h"
+
+namespace base {
+
+namespace subtle {
+
+class BASE_EXPORT RefCountedBase {
+ public:
+ static bool ImplementsThreadSafeReferenceCounting() { return false; }
+
+ bool HasOneRef() const { return ref_count_ == 1; }
+
+ protected:
+ RefCountedBase();
+ ~RefCountedBase();
+
+ void AddRef() const;
+
+ // Returns true if the object should self-delete.
+ bool Release() const;
+
+ private:
+ mutable int ref_count_;
+#ifndef NDEBUG
+ mutable bool in_dtor_;
+#endif
+
+ DFAKE_MUTEX(add_release_);
+
+ DISALLOW_COPY_AND_ASSIGN(RefCountedBase);
+};
+
+class BASE_EXPORT RefCountedThreadSafeBase {
+ public:
+ static bool ImplementsThreadSafeReferenceCounting() { return true; }
+
+ bool HasOneRef() const;
+
+ protected:
+ RefCountedThreadSafeBase();
+ ~RefCountedThreadSafeBase();
+
+ void AddRef() const;
+
+ // Returns true if the object should self-delete.
+ bool Release() const;
+
+ private:
+ mutable AtomicRefCount ref_count_;
+#ifndef NDEBUG
+ mutable bool in_dtor_;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafeBase);
+};
+
+} // namespace subtle
+
+//
+// A base class for reference counted classes. Otherwise, known as a cheap
+// knock-off of WebKit's RefCounted<T> class. To use this guy just extend your
+// class from it like so:
+//
+// class MyFoo : public base::RefCounted<MyFoo> {
+// ...
+// private:
+// friend class base::RefCounted<MyFoo>;
+// ~MyFoo();
+// };
+//
+// You should always make your destructor private, to avoid any code deleting
+// the object accidently while there are references to it.
+template <class T>
+class RefCounted : public subtle::RefCountedBase {
+ public:
+ RefCounted() { }
+ ~RefCounted() { }
+
+ void AddRef() const {
+ subtle::RefCountedBase::AddRef();
+ }
+
+ void Release() const {
+ if (subtle::RefCountedBase::Release()) {
+ delete static_cast<const T*>(this);
+ }
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(RefCounted<T>);
+};
+
+// Forward declaration.
+template <class T, typename Traits> class RefCountedThreadSafe;
+
+// Default traits for RefCountedThreadSafe<T>. Deletes the object when its ref
+// count reaches 0. Overload to delete it on a different thread etc.
+template<typename T>
+struct DefaultRefCountedThreadSafeTraits {
+ static void Destruct(const T* x) {
+ // Delete through RefCountedThreadSafe to make child classes only need to be
+ // friend with RefCountedThreadSafe instead of this struct, which is an
+ // implementation detail.
+ RefCountedThreadSafe<T,
+ DefaultRefCountedThreadSafeTraits>::DeleteInternal(x);
+ }
+};
+
+//
+// A thread-safe variant of RefCounted<T>
+//
+// class MyFoo : public base::RefCountedThreadSafe<MyFoo> {
+// ...
+// };
+//
+// If you're using the default trait, then you should add compile time
+// asserts that no one else is deleting your object. i.e.
+// private:
+// friend class base::RefCountedThreadSafe<MyFoo>;
+// ~MyFoo();
+template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T> >
+class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase {
+ public:
+ RefCountedThreadSafe() { }
+ ~RefCountedThreadSafe() { }
+
+ void AddRef() const {
+ subtle::RefCountedThreadSafeBase::AddRef();
+ }
+
+ void Release() const {
+ if (subtle::RefCountedThreadSafeBase::Release()) {
+ Traits::Destruct(static_cast<const T*>(this));
+ }
+ }
+
+ private:
+ friend struct DefaultRefCountedThreadSafeTraits<T>;
+ static void DeleteInternal(const T* x) { delete x; }
+
+ DISALLOW_COPY_AND_ASSIGN(RefCountedThreadSafe);
+};
+
+//
+// A wrapper for some piece of data so we can place other things in
+// scoped_refptrs<>.
+//
+template<typename T>
+class RefCountedData : public base::RefCounted< base::RefCountedData<T> > {
+ public:
+ RefCountedData() : data() {}
+ RefCountedData(const T& in_value) : data(in_value) {}
+
+ T data;
+};
+
+} // namespace base
+
+//
+// A smart pointer class for reference counted objects. Use this class instead
+// of calling AddRef and Release manually on a reference counted object to
+// avoid common memory leaks caused by forgetting to Release an object
+// reference. Sample usage:
+//
+// class MyFoo : public RefCounted<MyFoo> {
+// ...
+// };
+//
+// void some_function() {
+// scoped_refptr<MyFoo> foo = new MyFoo();
+// foo->Method(param);
+// // |foo| is released when this function returns
+// }
+//
+// void some_other_function() {
+// scoped_refptr<MyFoo> foo = new MyFoo();
+// ...
+// foo = NULL; // explicitly releases |foo|
+// ...
+// if (foo)
+// foo->Method(param);
+// }
+//
+// The above examples show how scoped_refptr<T> acts like a pointer to T.
+// Given two scoped_refptr<T> classes, it is also possible to exchange
+// references between the two objects, like so:
+//
+// {
+// scoped_refptr<MyFoo> a = new MyFoo();
+// scoped_refptr<MyFoo> b;
+//
+// b.swap(a);
+// // now, |b| references the MyFoo object, and |a| references NULL.
+// }
+//
+// To make both |a| and |b| in the above example reference the same MyFoo
+// object, simply use the assignment operator:
+//
+// {
+// scoped_refptr<MyFoo> a = new MyFoo();
+// scoped_refptr<MyFoo> b;
+//
+// b = a;
+// // now, |a| and |b| each own a reference to the same MyFoo object.
+// }
+//
+template <class T>
+class scoped_refptr {
+ public:
+ scoped_refptr() : ptr_(NULL) {
+ }
+
+ scoped_refptr(T* p) : ptr_(p) {
+ if (ptr_)
+ ptr_->AddRef();
+ }
+
+ scoped_refptr(const scoped_refptr<T>& r) : ptr_(r.ptr_) {
+ if (ptr_)
+ ptr_->AddRef();
+ }
+
+ template <typename U>
+ scoped_refptr(const scoped_refptr<U>& r) : ptr_(r.get()) {
+ if (ptr_)
+ ptr_->AddRef();
+ }
+
+ ~scoped_refptr() {
+ if (ptr_)
+ ptr_->Release();
+ }
+
+ T* get() const { return ptr_; }
+ operator T*() const { return ptr_; }
+ T* operator->() const { return ptr_; }
+
+ // Release a pointer.
+ // The return value is the current pointer held by this object.
+ // If this object holds a NULL pointer, the return value is NULL.
+ // After this operation, this object will hold a NULL pointer,
+ // and will not own the object any more.
+ T* release() {
+ T* retVal = ptr_;
+ ptr_ = NULL;
+ return retVal;
+ }
+
+ scoped_refptr<T>& operator=(T* p) {
+ // AddRef first so that self assignment should work
+ if (p)
+ p->AddRef();
+ if (ptr_ )
+ ptr_ ->Release();
+ ptr_ = p;
+ return *this;
+ }
+
+ scoped_refptr<T>& operator=(const scoped_refptr<T>& r) {
+ return *this = r.ptr_;
+ }
+
+ template <typename U>
+ scoped_refptr<T>& operator=(const scoped_refptr<U>& r) {
+ return *this = r.get();
+ }
+
+ void swap(T** pp) {
+ T* p = ptr_;
+ ptr_ = *pp;
+ *pp = p;
+ }
+
+ void swap(scoped_refptr<T>& r) {
+ swap(&r.ptr_);
+ }
+
+ protected:
+ T* ptr_;
+};
+
+// Handy utility for creating a scoped_refptr<T> out of a T* explicitly without
+// having to retype all the template arguments
+template <typename T>
+scoped_refptr<T> make_scoped_refptr(T* t) {
+ return scoped_refptr<T>(t);
+}
+
+#endif // BASE_MEMORY_REF_COUNTED_H_
diff --git a/base/memory/ref_counted_memory.cc b/base/memory/ref_counted_memory.cc
new file mode 100644
index 000000000000..7e034f91af62
--- /dev/null
+++ b/base/memory/ref_counted_memory.cc
@@ -0,0 +1,72 @@
+// 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/memory/ref_counted_memory.h"
+
+#include "base/logging.h"
+
+RefCountedMemory::RefCountedMemory() {
+}
+
+RefCountedMemory::~RefCountedMemory() {
+}
+
+const unsigned char* RefCountedStaticMemory::front() const {
+ return data_;
+}
+
+size_t RefCountedStaticMemory::size() const {
+ return length_;
+}
+
+RefCountedBytes::RefCountedBytes() {
+}
+
+RefCountedBytes::RefCountedBytes(const std::vector<unsigned char>& initializer)
+ : data_(initializer) {
+}
+
+RefCountedBytes* RefCountedBytes::TakeVector(
+ std::vector<unsigned char>* to_destroy) {
+ RefCountedBytes* bytes = new RefCountedBytes;
+ bytes->data_.swap(*to_destroy);
+ return bytes;
+}
+
+const unsigned char* RefCountedBytes::front() const {
+ // STL will assert if we do front() on an empty vector, but calling code
+ // expects a NULL.
+ return size() ? &data_.front() : NULL;
+}
+
+size_t RefCountedBytes::size() const {
+ return data_.size();
+}
+
+RefCountedBytes::~RefCountedBytes() {
+}
+
+namespace base {
+
+RefCountedString::RefCountedString() {}
+
+RefCountedString::~RefCountedString() {}
+
+// static
+RefCountedString* RefCountedString::TakeString(std::string* to_destroy) {
+ RefCountedString* self = new RefCountedString;
+ to_destroy->swap(self->data_);
+ return self;
+}
+
+const unsigned char* RefCountedString::front() const {
+ return data_.empty() ? NULL :
+ reinterpret_cast<const unsigned char*>(data_.data());
+}
+
+size_t RefCountedString::size() const {
+ return data_.size();
+}
+
+} // namespace base
diff --git a/base/memory/ref_counted_memory.h b/base/memory/ref_counted_memory.h
new file mode 100644
index 000000000000..7b55d145ec20
--- /dev/null
+++ b/base/memory/ref_counted_memory.h
@@ -0,0 +1,119 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_REF_COUNTED_MEMORY_H_
+#define BASE_MEMORY_REF_COUNTED_MEMORY_H_
+#pragma once
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+
+// TODO(erg): The contents of this file should be in a namespace. This would
+// require touching >100 files in chrome/ though.
+
+// A generic interface to memory. This object is reference counted because one
+// of its two subclasses own the data they carry, and we need to have
+// heterogeneous containers of these two types of memory.
+class BASE_EXPORT RefCountedMemory
+ : public base::RefCountedThreadSafe<RefCountedMemory> {
+ public:
+ // Retrieves a pointer to the beginning of the data we point to. If the data
+ // is empty, this will return NULL.
+ virtual const unsigned char* front() const = 0;
+
+ // Size of the memory pointed to.
+ virtual size_t size() const = 0;
+
+ protected:
+ friend class base::RefCountedThreadSafe<RefCountedMemory>;
+ RefCountedMemory();
+ virtual ~RefCountedMemory();
+};
+
+// An implementation of RefCountedMemory, where the ref counting does not
+// matter.
+class BASE_EXPORT RefCountedStaticMemory : public RefCountedMemory {
+ public:
+ RefCountedStaticMemory()
+ : data_(NULL), length_(0) {}
+ RefCountedStaticMemory(const unsigned char* data, size_t length)
+ : data_(length ? data : NULL), length_(length) {}
+
+ // Overridden from RefCountedMemory:
+ virtual const unsigned char* front() const OVERRIDE;
+ virtual size_t size() const OVERRIDE;
+
+ private:
+ const unsigned char* data_;
+ size_t length_;
+
+ DISALLOW_COPY_AND_ASSIGN(RefCountedStaticMemory);
+};
+
+// An implementation of RefCountedMemory, where we own our the data in a
+// vector.
+class BASE_EXPORT RefCountedBytes : public RefCountedMemory {
+ public:
+ RefCountedBytes();
+
+ // Constructs a RefCountedBytes object by _copying_ from |initializer|.
+ RefCountedBytes(const std::vector<unsigned char>& initializer);
+
+ // Constructs a RefCountedBytes object by performing a swap. (To non
+ // destructively build a RefCountedBytes, use the constructor that takes a
+ // vector.)
+ static RefCountedBytes* TakeVector(std::vector<unsigned char>* to_destroy);
+
+ // Overridden from RefCountedMemory:
+ virtual const unsigned char* front() const OVERRIDE;
+ virtual size_t size() const OVERRIDE;
+
+ const std::vector<unsigned char>& data() const { return data_; }
+ std::vector<unsigned char>& data() { return data_; }
+
+ private:
+ friend class base::RefCountedThreadSafe<RefCountedBytes>;
+ virtual ~RefCountedBytes();
+
+ std::vector<unsigned char> data_;
+
+ DISALLOW_COPY_AND_ASSIGN(RefCountedBytes);
+};
+
+namespace base {
+
+// An implementation of RefCountedMemory, where the bytes are stored in an STL
+// string. Use this if your data naturally arrives in that format.
+class BASE_EXPORT RefCountedString : public RefCountedMemory {
+ public:
+ RefCountedString();
+
+ // 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);
+
+ // Overridden from RefCountedMemory:
+ virtual const unsigned char* front() const OVERRIDE;
+ virtual size_t size() const OVERRIDE;
+
+ const std::string& data() const { return data_; }
+ std::string& data() { return data_; }
+
+ private:
+ friend class base::RefCountedThreadSafe<RefCountedString>;
+ virtual ~RefCountedString();
+
+ std::string data_;
+
+ DISALLOW_COPY_AND_ASSIGN(RefCountedString);
+};
+
+} // namespace base
+
+#endif // BASE_MEMORY_REF_COUNTED_MEMORY_H_
diff --git a/base/memory/ref_counted_memory_unittest.cc b/base/memory/ref_counted_memory_unittest.cc
new file mode 100644
index 000000000000..19360400c14a
--- /dev/null
+++ b/base/memory/ref_counted_memory_unittest.cc
@@ -0,0 +1,45 @@
+// 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/memory/ref_counted_memory.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+TEST(RefCountedMemoryUnitTest, RefCountedStaticMemory) {
+ scoped_refptr<RefCountedMemory> mem = new RefCountedStaticMemory(
+ reinterpret_cast<const uint8*>("static mem00"), 10);
+
+ EXPECT_EQ(10U, mem->size());
+ EXPECT_EQ("static mem",
+ std::string(reinterpret_cast<const char*>(mem->front()),
+ mem->size()));
+}
+
+TEST(RefCountedMemoryUnitTest, RefCountedBytes) {
+ std::vector<uint8> data;
+ data.push_back(45);
+ data.push_back(99);
+ scoped_refptr<RefCountedMemory> mem = RefCountedBytes::TakeVector(&data);
+
+ EXPECT_EQ(0U, data.size());
+
+ EXPECT_EQ(2U, mem->size());
+ EXPECT_EQ(45U, mem->front()[0]);
+ EXPECT_EQ(99U, mem->front()[1]);
+}
+
+TEST(RefCountedMemoryUnitTest, RefCountedString) {
+ std::string s("destroy me");
+ scoped_refptr<RefCountedMemory> mem = RefCountedString::TakeString(&s);
+
+ EXPECT_EQ(0U, s.size());
+
+ EXPECT_EQ(10U, mem->size());
+ EXPECT_EQ('d', mem->front()[0]);
+ EXPECT_EQ('e', mem->front()[1]);
+}
+
+} // namespace base
diff --git a/base/memory/ref_counted_unittest.cc b/base/memory/ref_counted_unittest.cc
new file mode 100644
index 000000000000..dcc292f00ddf
--- /dev/null
+++ b/base/memory/ref_counted_unittest.cc
@@ -0,0 +1,36 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/ref_counted.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class SelfAssign : public base::RefCounted<SelfAssign> {
+ friend class base::RefCounted<SelfAssign>;
+
+ ~SelfAssign() {}
+};
+
+class CheckDerivedMemberAccess : public scoped_refptr<SelfAssign> {
+ public:
+ CheckDerivedMemberAccess() {
+ // This shouldn't compile if we don't have access to the member variable.
+ SelfAssign** pptr = &ptr_;
+ EXPECT_EQ(*pptr, ptr_);
+ }
+};
+
+} // end namespace
+
+TEST(RefCountedUnitTest, TestSelfAssignment) {
+ SelfAssign* p = new SelfAssign;
+ scoped_refptr<SelfAssign> var(p);
+ var = var;
+ EXPECT_EQ(var.get(), p);
+}
+
+TEST(RefCountedUnitTest, ScopedRefPtrMemberAccess) {
+ CheckDerivedMemberAccess check;
+}
diff --git a/base/pickle.cc b/base/pickle.cc
new file mode 100644
index 000000000000..f42f249bb274
--- /dev/null
+++ b/base/pickle.cc
@@ -0,0 +1,449 @@
+// 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/pickle.h"
+
+#include <stdlib.h>
+
+#include <algorithm> // for max()
+#include <limits>
+
+//------------------------------------------------------------------------------
+
+// static
+const int Pickle::kPayloadUnit = 64;
+
+// We mark a read only pickle with a special capacity_.
+static const size_t kCapacityReadOnly = std::numeric_limits<size_t>::max();
+
+// Payload is uint32 aligned.
+
+Pickle::Pickle()
+ : header_(NULL),
+ header_size_(sizeof(Header)),
+ capacity_(0),
+ variable_buffer_offset_(0) {
+ Resize(kPayloadUnit);
+ header_->payload_size = 0;
+}
+
+Pickle::Pickle(int header_size)
+ : header_(NULL),
+ header_size_(AlignInt(header_size, sizeof(uint32))),
+ capacity_(0),
+ variable_buffer_offset_(0) {
+ DCHECK_GE(static_cast<size_t>(header_size), sizeof(Header));
+ DCHECK_LE(header_size, kPayloadUnit);
+ Resize(kPayloadUnit);
+ header_->payload_size = 0;
+}
+
+Pickle::Pickle(const char* data, int data_len)
+ : header_(reinterpret_cast<Header*>(const_cast<char*>(data))),
+ header_size_(0),
+ capacity_(kCapacityReadOnly),
+ variable_buffer_offset_(0)
+{
+
+ if (data_len >= static_cast<int>(sizeof(Header)))
+ {
+ header_size_ = data_len - header_->payload_size;
+ }
+
+ if (header_size_ > static_cast<unsigned int>(data_len))
+ {
+ header_size_ = 0;
+ }
+
+
+ if (header_size_ != AlignInt(header_size_, sizeof(uint32)))
+ {
+ header_size_ = 0;
+ }
+
+
+ // If there is anything wrong with the data, we're not going to use it.
+ if (!header_size_)
+ header_ = NULL;
+}
+
+Pickle::Pickle(const Pickle& other)
+ : header_(NULL),
+ header_size_(other.header_size_),
+ capacity_(0),
+ variable_buffer_offset_(other.variable_buffer_offset_) {
+ size_t payload_size = header_size_ + other.header_->payload_size;
+ bool resized = Resize(payload_size);
+ CHECK(resized); // Realloc failed.
+ memcpy(header_, other.header_, payload_size);
+}
+
+Pickle::~Pickle() {
+ if (capacity_ != kCapacityReadOnly)
+ free(header_);
+}
+
+Pickle& Pickle::operator=(const Pickle& other) {
+ if (this == &other) {
+ NOTREACHED();
+ return *this;
+ }
+ if (capacity_ == kCapacityReadOnly) {
+ header_ = NULL;
+ capacity_ = 0;
+ }
+ if (header_size_ != other.header_size_) {
+ free(header_);
+ header_ = NULL;
+ header_size_ = other.header_size_;
+ }
+ bool resized = Resize(other.header_size_ + other.header_->payload_size);
+ CHECK(resized); // Realloc failed.
+ memcpy(header_, other.header_,
+ other.header_size_ + other.header_->payload_size);
+ variable_buffer_offset_ = other.variable_buffer_offset_;
+ return *this;
+}
+
+bool Pickle::ReadBool(void** iter, bool* result) const {
+ DCHECK(iter);
+
+ int tmp;
+ if (!ReadInt(iter, &tmp))
+ return false;
+ DCHECK(0 == tmp || 1 == tmp);
+ *result = tmp ? true : false;
+ return true;
+}
+
+bool Pickle::ReadInt(void** iter, int* result) const {
+ DCHECK(iter);
+ if (!*iter)
+ *iter = const_cast<char*>(payload());
+
+ if (!IteratorHasRoomFor(*iter, sizeof(*result)))
+ return false;
+
+ // TODO(jar): http://crbug.com/13108 Pickle should be cleaned up, and not
+ // dependent on alignment.
+ // Next line is otherwise the same as: memcpy(result, *iter, sizeof(*result));
+ *result = *reinterpret_cast<int*>(*iter);
+
+ UpdateIter(iter, sizeof(*result));
+ return true;
+}
+
+bool Pickle::ReadLong(void** iter, long* result) const {
+ DCHECK(iter);
+ if (!*iter)
+ *iter = const_cast<char*>(payload());
+
+ if (!IteratorHasRoomFor(*iter, sizeof(*result)))
+ return false;
+
+ // TODO(jar): http://crbug.com/13108 Pickle should be cleaned up, and not
+ // dependent on alignment.
+ memcpy(result, *iter, sizeof(*result));
+
+ UpdateIter(iter, sizeof(*result));
+ return true;
+}
+
+bool Pickle::ReadSize(void** iter, size_t* result) const {
+ DCHECK(iter);
+ if (!*iter)
+ *iter = const_cast<char*>(payload());
+
+ if (!IteratorHasRoomFor(*iter, sizeof(*result)))
+ return false;
+
+ // TODO(jar): http://crbug.com/13108 Pickle should be cleaned up, and not
+ // dependent on alignment.
+ // Next line is otherwise the same as: memcpy(result, *iter, sizeof(*result));
+ *result = *reinterpret_cast<size_t*>(*iter);
+
+ UpdateIter(iter, sizeof(*result));
+ return true;
+}
+
+bool Pickle::ReadUInt16(void** iter, uint16* result) const {
+ DCHECK(iter);
+ if (!*iter)
+ *iter = const_cast<char*>(payload());
+
+ if (!IteratorHasRoomFor(*iter, sizeof(*result)))
+ return false;
+
+ memcpy(result, *iter, sizeof(*result));
+
+ UpdateIter(iter, sizeof(*result));
+ return true;
+}
+
+bool Pickle::ReadUInt32(void** iter, uint32* result) const {
+ DCHECK(iter);
+ if (!*iter)
+ *iter = const_cast<char*>(payload());
+
+ if (!IteratorHasRoomFor(*iter, sizeof(*result)))
+ return false;
+
+ memcpy(result, *iter, sizeof(*result));
+
+ UpdateIter(iter, sizeof(*result));
+ return true;
+}
+
+bool Pickle::ReadInt64(void** iter, int64* result) const {
+ DCHECK(iter);
+ if (!*iter)
+ *iter = const_cast<char*>(payload());
+
+ if (!IteratorHasRoomFor(*iter, sizeof(*result)))
+ return false;
+
+ memcpy(result, *iter, sizeof(*result));
+
+ UpdateIter(iter, sizeof(*result));
+ return true;
+}
+
+bool Pickle::ReadUInt64(void** iter, uint64* result) const {
+ DCHECK(iter);
+ if (!*iter)
+ *iter = const_cast<char*>(payload());
+
+ if (!IteratorHasRoomFor(*iter, sizeof(*result)))
+ return false;
+
+ memcpy(result, *iter, sizeof(*result));
+
+ UpdateIter(iter, sizeof(*result));
+ return true;
+}
+
+
+bool Pickle::ReadString(void** iter, std::string* result) const {
+ DCHECK(iter);
+
+ int len;
+ if (!ReadLength(iter, &len))
+ return false;
+ if (!IteratorHasRoomFor(*iter, len))
+ return false;
+
+ char* chars = reinterpret_cast<char*>(*iter);
+ result->assign(chars, len);
+
+ UpdateIter(iter, len);
+ return true;
+}
+
+/*
+bool Pickle::ReadWString(void** iter, std::wstring* result) const {
+ DCHECK(iter);
+
+ int len;
+ if (!ReadLength(iter, &len))
+ return false;
+ // Avoid integer overflow.
+ if (len > INT_MAX / static_cast<int>(sizeof(wchar_t)))
+ return false;
+ if (!IteratorHasRoomFor(*iter, len * sizeof(wchar_t)))
+ return false;
+
+ wchar_t* chars = reinterpret_cast<wchar_t*>(*iter);
+ result->assign(chars, len);
+
+ UpdateIter(iter, len * sizeof(wchar_t));
+ return true;
+}
+
+bool Pickle::ReadString16(void** iter, string16* result) const {
+ DCHECK(iter);
+
+ int len;
+ if (!ReadLength(iter, &len))
+ return false;
+ if (!IteratorHasRoomFor(*iter, len * sizeof(char16)))
+ return false;
+
+ char16* chars = reinterpret_cast<char16*>(*iter);
+ result->assign(chars, len);
+
+ UpdateIter(iter, len * sizeof(char16));
+ return true;
+}
+*/
+
+bool Pickle::ReadData(void** iter, const char** data, int* length) const {
+ DCHECK(iter);
+ DCHECK(data);
+ DCHECK(length);
+ *length = 0;
+ *data = 0;
+
+ if (!ReadLength(iter, length))
+ return false;
+
+ return ReadBytes(iter, data, *length);
+}
+
+bool Pickle::ReadBytes(void** iter, const char** data, int length) const {
+ DCHECK(iter);
+ DCHECK(data);
+ *data = 0;
+ if (!*iter)
+ *iter = const_cast<char*>(payload());
+
+ if (!IteratorHasRoomFor(*iter, length))
+ return false;
+
+ *data = reinterpret_cast<const char*>(*iter);
+
+ UpdateIter(iter, length);
+ return true;
+}
+
+bool Pickle::ReadLength(void** iter, int* result) const {
+ if (!ReadInt(iter, result))
+ return false;
+ return ((*result) >= 0);
+}
+
+
+bool Pickle::WriteString(const std::string& value) {
+ if (!WriteInt(static_cast<int>(value.size())))
+ return false;
+
+ return WriteBytes(value.data(), static_cast<int>(value.size()));
+}
+
+/*
+bool Pickle::WriteWString(const std::wstring& value) {
+ if (!WriteInt(static_cast<int>(value.size())))
+ return false;
+
+ return WriteBytes(value.data(),
+ static_cast<int>(value.size() * sizeof(wchar_t)));
+}
+
+bool Pickle::WriteString16(const string16& value) {
+ if (!WriteInt(static_cast<int>(value.size())))
+ return false;
+
+ return WriteBytes(value.data(),
+ static_cast<int>(value.size()) * sizeof(char16));
+}
+*/
+
+bool Pickle::WriteData(const char* data, int length) {
+ return length >= 0 && WriteInt(length) && WriteBytes(data, length);
+}
+
+bool Pickle::WriteBytes(const void* data, int data_len) {
+ DCHECK_NE(kCapacityReadOnly, capacity_) << "oops: pickle is readonly";
+
+ char* dest = BeginWrite(data_len);
+ if (!dest)
+ return false;
+
+ memcpy(dest, data, data_len);
+
+ EndWrite(dest, data_len);
+ return true;
+}
+
+char* Pickle::BeginWriteData(int length) {
+ DCHECK_EQ(variable_buffer_offset_, 0U) <<
+ "There can only be one variable buffer in a Pickle";
+
+ if (length < 0 || !WriteInt(length))
+ return NULL;
+
+ char *data_ptr = BeginWrite(length);
+ if (!data_ptr)
+ return NULL;
+
+ variable_buffer_offset_ =
+ data_ptr - reinterpret_cast<char*>(header_) - sizeof(int);
+
+ // EndWrite doesn't necessarily have to be called after the write operation,
+ // so we call it here to pad out what the caller will eventually write.
+ EndWrite(data_ptr, length);
+ return data_ptr;
+}
+
+void Pickle::TrimWriteData(int new_length) {
+ DCHECK_NE(variable_buffer_offset_, 0U);
+
+ // Fetch the the variable buffer size
+ int* cur_length = reinterpret_cast<int*>(
+ reinterpret_cast<char*>(header_) + variable_buffer_offset_);
+
+ if (new_length < 0 || new_length > *cur_length) {
+ NOTREACHED() << "Invalid length in TrimWriteData.";
+ return;
+ }
+
+ // Update the payload size and variable buffer size
+ header_->payload_size -= (*cur_length - new_length);
+ *cur_length = new_length;
+}
+
+char* Pickle::BeginWrite(size_t length) {
+ // write at a uint32-aligned offset from the beginning of the header
+ size_t offset = AlignInt(header_->payload_size, sizeof(uint32));
+
+ size_t new_size = offset + length;
+ size_t needed_size = header_size_ + new_size;
+ if (needed_size > capacity_ && !Resize(std::max(capacity_ * 2, needed_size)))
+ return NULL;
+
+#ifdef ARCH_CPU_64_BITS
+ DCHECK_LE(length, std::numeric_limits<uint32>::max());
+#endif
+
+ header_->payload_size = static_cast<uint32>(new_size);
+ return payload() + offset;
+}
+
+void Pickle::EndWrite(char* dest, int length) {
+ // Zero-pad to keep tools like purify from complaining about uninitialized
+ // memory.
+ if (length % sizeof(uint32))
+ memset(dest + length, 0, sizeof(uint32) - (length % sizeof(uint32)));
+}
+
+bool Pickle::Resize(size_t new_capacity) {
+ new_capacity = AlignInt(new_capacity, kPayloadUnit);
+
+ CHECK_NE(capacity_, kCapacityReadOnly);
+ void* p = realloc(header_, new_capacity);
+ if (!p)
+ return false;
+
+ header_ = reinterpret_cast<Header*>(p);
+ capacity_ = new_capacity;
+ return true;
+}
+
+// static
+const char* Pickle::FindNext(size_t header_size,
+ const char* start,
+ const char* end) {
+ DCHECK_EQ(header_size, AlignInt(header_size, sizeof(uint32)));
+ DCHECK_LE(header_size, static_cast<size_t>(kPayloadUnit));
+
+ if (static_cast<size_t>(end - start) < sizeof(Header))
+ return NULL;
+
+ const Header* hdr = reinterpret_cast<const Header*>(start);
+ const char* payload_base = start + header_size;
+ const char* payload_end = payload_base + hdr->payload_size;
+ if (payload_end < payload_base)
+ return NULL;
+
+ return (payload_end > end) ? NULL : payload_end;
+}
diff --git a/base/pickle.h b/base/pickle.h
new file mode 100644
index 000000000000..e7ececff42cd
--- /dev/null
+++ b/base/pickle.h
@@ -0,0 +1,249 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PICKLE_H__
+#define BASE_PICKLE_H__
+#pragma once
+
+#include <string>
+#include <iostream>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+//#include "base/gtest_prod_util.h" // jaehwa
+//#include "base/logging.h" // jaehwa
+#include "log.h" // jaehwa
+//#include "base/string16.h" // jaehwa
+
+// This class provides facilities for basic binary value packing and unpacking.
+//
+// The Pickle class supports appending primitive values (ints, strings, etc.)
+// to a pickle instance. The Pickle instance grows its internal memory buffer
+// dynamically to hold the sequence of primitive values. The internal memory
+// buffer is exposed as the "data" of the Pickle. This "data" can be passed
+// to a Pickle object to initialize it for reading.
+//
+// When reading from a Pickle object, it is important for the consumer to know
+// what value types to read and in what order to read them as the Pickle does
+// not keep track of the type of data written to it.
+//
+// The Pickle's data has a header which contains the size of the Pickle's
+// payload. It can optionally support additional space in the header. That
+// space is controlled by the header_size parameter passed to the Pickle
+// constructor.
+//
+class BASE_EXPORT Pickle {
+ public:
+ // Initialize a Pickle object using the default header size.
+ Pickle();
+
+ // Initialize a Pickle object with the specified header size in bytes, which
+ // must be greater-than-or-equal-to sizeof(Pickle::Header). The header size
+ // will be rounded up to ensure that the header size is 32bit-aligned.
+ explicit Pickle(int header_size);
+
+ // Initializes a Pickle from a const block of data. The data is not copied;
+ // instead the data is merely referenced by this Pickle. Only const methods
+ // should be used on the Pickle when initialized this way. The header
+ // padding size is deduced from the data length.
+ Pickle(const char* data, int data_len);
+
+ // Initializes a Pickle as a deep copy of another Pickle.
+ Pickle(const Pickle& other);
+
+ virtual ~Pickle();
+
+ // Performs a deep copy.
+ Pickle& operator=(const Pickle& other);
+
+ // Returns the size of the Pickle's data.
+ size_t size() const { return header_size_ + header_->payload_size; }
+
+ // Returns the data for this Pickle.
+ const void* data() const { return header_; }
+
+ // Methods for reading the payload of the Pickle. To read from the start of
+ // the Pickle, initialize *iter to NULL. If successful, these methods return
+ // true. Otherwise, false is returned to indicate that the result could not
+ // be extracted.
+ bool ReadBool(void** iter, bool* result) const;
+ bool ReadInt(void** iter, int* result) const;
+ bool ReadLong(void** iter, long* result) const;
+ bool ReadSize(void** iter, size_t* result) const;
+ bool ReadUInt16(void** iter, uint16* result) const;
+ bool ReadUInt32(void** iter, uint32* result) const;
+ bool ReadInt64(void** iter, int64* result) const;
+ bool ReadUInt64(void** iter, uint64* result) const;
+ bool ReadString(void** iter, std::string* result) const;
+// bool ReadWString(void** iter, std::wstring* result) const;
+// bool ReadString16(void** iter, string16* result) const;
+ bool ReadData(void** iter, const char** data, int* length) const;
+ bool ReadBytes(void** iter, const char** data, int length) const;
+
+ // Safer version of ReadInt() checks for the result not being negative.
+ // Use it for reading the object sizes.
+ bool ReadLength(void** iter, int* result) const;
+
+ // Methods for adding to the payload of the Pickle. These values are
+ // appended to the end of the Pickle's payload. When reading values from a
+ // Pickle, it is important to read them in the order in which they were added
+ // to the Pickle.
+ bool WriteBool(bool value) {
+ return WriteInt(value ? 1 : 0);
+ }
+ bool WriteInt(int value) {
+ return WriteBytes(&value, sizeof(value));
+ }
+ bool WriteLong(long value) {
+ return WriteBytes(&value, sizeof(value));
+ }
+ bool WriteSize(size_t value) {
+ return WriteBytes(&value, sizeof(value));
+ }
+ bool WriteUInt16(uint16 value) {
+ return WriteBytes(&value, sizeof(value));
+ }
+ bool WriteUInt32(uint32 value) {
+ return WriteBytes(&value, sizeof(value));
+ }
+ bool WriteInt64(int64 value) {
+ return WriteBytes(&value, sizeof(value));
+ }
+ bool WriteUInt64(uint64 value) {
+ return WriteBytes(&value, sizeof(value));
+ }
+ bool WriteString(const std::string& value);
+// bool WriteWString(const std::wstring& value);
+// bool WriteString16(const string16& value);
+ bool WriteData(const char* data, int length);
+ bool WriteBytes(const void* data, int data_len);
+
+ // Same as WriteData, but allows the caller to write directly into the
+ // Pickle. This saves a copy in cases where the data is not already
+ // available in a buffer. The caller should take care to not write more
+ // than the length it declares it will. Use ReadData to get the data.
+ // Returns NULL on failure.
+ //
+ // The returned pointer will only be valid until the next write operation
+ // on this Pickle.
+ char* BeginWriteData(int length);
+
+ // For Pickles which contain variable length buffers (e.g. those created
+ // with BeginWriteData), the Pickle can
+ // be 'trimmed' if the amount of data required is less than originally
+ // requested. For example, you may have created a buffer with 10K of data,
+ // but decided to only fill 10 bytes of that data. Use this function
+ // to trim the buffer so that we don't send 9990 bytes of unused data.
+ // You cannot increase the size of the variable buffer; only shrink it.
+ // This function assumes that the length of the variable buffer has
+ // not been changed.
+ void TrimWriteData(int length);
+
+ // Payload follows after allocation of Header (header size is customizable).
+ struct Header {
+ uint32 payload_size; // Specifies the size of the payload.
+ };
+
+ // Returns the header, cast to a user-specified type T. The type T must be a
+ // subclass of Header and its size must correspond to the header_size passed
+ // to the Pickle constructor.
+ template <class T>
+ T* headerT() {
+ DCHECK_EQ(header_size_, sizeof(T));
+ return static_cast<T*>(header_);
+ }
+ template <class T>
+ const T* headerT() const {
+ DCHECK_EQ(header_size_, sizeof(T));
+ return static_cast<const T*>(header_);
+ }
+
+ // Returns true if the given iterator could point to data with the given
+ // length. If there is no room for the given data before the end of the
+ // payload, returns false.
+ bool IteratorHasRoomFor(const void* iter, int len) const {
+ if ((len < 0) || (iter < header_) || iter > end_of_payload())
+ return false;
+ const char* end_of_region = reinterpret_cast<const char*>(iter) + len;
+ // Watch out for overflow in pointer calculation, which wraps.
+ return (iter <= end_of_region) && (end_of_region <= end_of_payload());
+ }
+
+ protected:
+ size_t payload_size() const { return header_->payload_size; }
+
+ char* payload() {
+ return reinterpret_cast<char*>(header_) + header_size_;
+ }
+ const char* payload() const {
+ return reinterpret_cast<const char*>(header_) + header_size_;
+ }
+
+ // Returns the address of the byte immediately following the currently valid
+ // header + payload.
+ char* end_of_payload() {
+ // We must have a valid header_.
+ return payload() + payload_size();
+ }
+ const char* end_of_payload() const {
+ // This object may be invalid.
+ return header_ ? payload() + payload_size() : NULL;
+ }
+
+ size_t capacity() const {
+ return capacity_;
+ }
+
+ // Resizes the buffer for use when writing the specified amount of data. The
+ // location that the data should be written at is returned, or NULL if there
+ // was an error. Call EndWrite with the returned offset and the given length
+ // to pad out for the next write.
+ char* BeginWrite(size_t length);
+
+ // Completes the write operation by padding the data with NULL bytes until it
+ // is padded. Should be paired with BeginWrite, but it does not necessarily
+ // have to be called after the data is written.
+ void EndWrite(char* dest, int length);
+
+ // Resize the capacity, note that the input value should include the size of
+ // the header: new_capacity = sizeof(Header) + desired_payload_capacity.
+ // A realloc() failure will cause a Resize failure... and caller should check
+ // the return result for true (i.e., successful resizing).
+ bool Resize(size_t new_capacity);
+
+ // Aligns 'i' by rounding it up to the next multiple of 'alignment'
+ static size_t AlignInt(size_t i, int alignment) {
+ return i + (alignment - (i % alignment)) % alignment;
+ }
+
+ // Moves the iterator by the given number of bytes, making sure it is aligned.
+ // Pointer (iterator) is NOT aligned, but the change in the pointer
+ // is guaranteed to be a multiple of sizeof(uint32).
+ static void UpdateIter(void** iter, int bytes) {
+ *iter = static_cast<char*>(*iter) + AlignInt(bytes, sizeof(uint32));
+ }
+
+ // 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,
+ const char* range_start,
+ const char* range_end);
+
+ // The allocation granularity of the payload.
+ static const int kPayloadUnit;
+
+ private:
+ Header* header_;
+ size_t header_size_; // Supports extra data between header and payload.
+ // Allocation size of payload (or -1 if allocation is const).
+ size_t capacity_;
+ size_t variable_buffer_offset_; // IF non-zero, then offset to a buffer.
+
+// FRIEND_TEST_ALL_PREFIXES(PickleTest, Resize);
+// FRIEND_TEST_ALL_PREFIXES(PickleTest, FindNext);
+// FRIEND_TEST_ALL_PREFIXES(PickleTest, FindNextWithIncompleteHeader);
+// FRIEND_TEST_ALL_PREFIXES(PickleTest, IteratorHasRoom);
+};
+
+#endif // BASE_PICKLE_H__
diff --git a/base/platform_file_posix.cc b/base/platform_file_posix.cc
new file mode 100644
index 000000000000..fed36966a97c
--- /dev/null
+++ b/base/platform_file_posix.cc
@@ -0,0 +1,200 @@
+// 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/platform_file.h"
+
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "base/eintr_wrapper.h"
+#include "base/file_path.h"
+#include "base/logging.h"
+#include "base/utf_string_conversions.h"
+
+#if defined(OS_ANDROID)
+#include "base/os_compat_android.h"
+#endif
+
+namespace base {
+
+#if defined(OS_OPENBSD) || defined(OS_FREEBSD) || \
+ (defined(OS_MACOSX) && \
+ MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5)
+typedef struct stat stat_wrapper_t;
+static int CallFstat(int fd, stat_wrapper_t *sb) {
+ return fstat(fd, sb);
+}
+#else
+typedef struct stat64 stat_wrapper_t;
+static int CallFstat(int fd, stat_wrapper_t *sb) {
+ return fstat64(fd, sb);
+}
+#endif
+
+// TODO(erikkay): does it make sense to support PLATFORM_FILE_EXCLUSIVE_* here?
+PlatformFile CreatePlatformFile(const FilePath& name, int flags,
+ bool* created, PlatformFileError* error_code) {
+ int open_flags = 0;
+ if (flags & PLATFORM_FILE_CREATE)
+ open_flags = O_CREAT | O_EXCL;
+
+ if (created)
+ *created = false;
+
+ if (flags & PLATFORM_FILE_CREATE_ALWAYS) {
+ DCHECK(!open_flags);
+ open_flags = O_CREAT | O_TRUNC;
+ }
+
+ if (flags & PLATFORM_FILE_OPEN_TRUNCATED) {
+ DCHECK(!open_flags);
+ DCHECK(flags & PLATFORM_FILE_WRITE);
+ open_flags = O_TRUNC;
+ }
+
+ if (!open_flags && !(flags & PLATFORM_FILE_OPEN) &&
+ !(flags & PLATFORM_FILE_OPEN_ALWAYS)) {
+ NOTREACHED();
+ errno = EOPNOTSUPP;
+ if (error_code)
+ *error_code = PLATFORM_FILE_ERROR_FAILED;
+ return kInvalidPlatformFileValue;
+ }
+
+ if (flags & PLATFORM_FILE_WRITE && flags & PLATFORM_FILE_READ) {
+ open_flags |= O_RDWR;
+ } else if (flags & PLATFORM_FILE_WRITE) {
+ open_flags |= O_WRONLY;
+ } else if (!(flags & PLATFORM_FILE_READ) &&
+ !(flags & PLATFORM_FILE_WRITE_ATTRIBUTES) &&
+ !(flags & PLATFORM_FILE_OPEN_ALWAYS)) {
+ NOTREACHED();
+ }
+
+ COMPILE_ASSERT(O_RDONLY == 0, O_RDONLY_must_equal_zero);
+
+ int descriptor =
+ HANDLE_EINTR(open(name.value().c_str(), open_flags, S_IRUSR | S_IWUSR));
+
+ if (flags & PLATFORM_FILE_OPEN_ALWAYS) {
+ if (descriptor <= 0) {
+ open_flags |= O_CREAT;
+ if (flags & PLATFORM_FILE_EXCLUSIVE_READ ||
+ flags & PLATFORM_FILE_EXCLUSIVE_WRITE) {
+ open_flags |= O_EXCL; // together with O_CREAT implies O_NOFOLLOW
+ }
+ descriptor = HANDLE_EINTR(
+ open(name.value().c_str(), open_flags, S_IRUSR | S_IWUSR));
+ if (created && descriptor > 0)
+ *created = true;
+ }
+ }
+
+ if (created && (descriptor > 0) &&
+ (flags & (PLATFORM_FILE_CREATE_ALWAYS | PLATFORM_FILE_CREATE)))
+ *created = true;
+
+ if ((descriptor > 0) && (flags & PLATFORM_FILE_DELETE_ON_CLOSE)) {
+ unlink(name.value().c_str());
+ }
+
+ if (error_code) {
+ if (descriptor >= 0)
+ *error_code = PLATFORM_FILE_OK;
+ else {
+ switch (errno) {
+ case EACCES:
+ case EISDIR:
+ case EROFS:
+ case EPERM:
+ *error_code = PLATFORM_FILE_ERROR_ACCESS_DENIED;
+ break;
+ case ETXTBSY:
+ *error_code = PLATFORM_FILE_ERROR_IN_USE;
+ break;
+ case EEXIST:
+ *error_code = PLATFORM_FILE_ERROR_EXISTS;
+ break;
+ case ENOENT:
+ *error_code = PLATFORM_FILE_ERROR_NOT_FOUND;
+ break;
+ case EMFILE:
+ *error_code = PLATFORM_FILE_ERROR_TOO_MANY_OPENED;
+ break;
+ case ENOMEM:
+ *error_code = PLATFORM_FILE_ERROR_NO_MEMORY;
+ break;
+ case ENOSPC:
+ *error_code = PLATFORM_FILE_ERROR_NO_SPACE;
+ break;
+ case ENOTDIR:
+ *error_code = PLATFORM_FILE_ERROR_NOT_A_DIRECTORY;
+ break;
+ default:
+ *error_code = PLATFORM_FILE_ERROR_FAILED;
+ }
+ }
+ }
+
+ return descriptor;
+}
+
+bool ClosePlatformFile(PlatformFile file) {
+ return !HANDLE_EINTR(close(file));
+}
+
+int ReadPlatformFile(PlatformFile file, int64 offset, char* data, int size) {
+ if (file < 0)
+ return -1;
+
+ return HANDLE_EINTR(pread(file, data, size, offset));
+}
+
+int WritePlatformFile(PlatformFile file, int64 offset,
+ const char* data, int size) {
+ if (file < 0)
+ return -1;
+
+ return HANDLE_EINTR(pwrite(file, data, size, offset));
+}
+
+bool TruncatePlatformFile(PlatformFile file, int64 length) {
+ return ((file >= 0) && !HANDLE_EINTR(ftruncate(file, length)));
+}
+
+bool FlushPlatformFile(PlatformFile file) {
+ return !HANDLE_EINTR(fsync(file));
+}
+
+bool TouchPlatformFile(PlatformFile file, const base::Time& last_access_time,
+ const base::Time& last_modified_time) {
+ if (file < 0)
+ return false;
+
+ timeval times[2];
+ times[0] = last_access_time.ToTimeVal();
+ times[1] = last_modified_time.ToTimeVal();
+ return !futimes(file, times);
+}
+
+bool GetPlatformFileInfo(PlatformFile file, PlatformFileInfo* info) {
+ if (!info)
+ return false;
+
+ stat_wrapper_t file_info;
+ if (CallFstat(file, &file_info))
+ return false;
+
+ info->is_directory = S_ISDIR(file_info.st_mode);
+ info->is_symbolic_link = S_ISLNK(file_info.st_mode);
+ info->size = file_info.st_size;
+ info->last_modified = base::Time::FromTimeT(file_info.st_mtime);
+ info->last_accessed = base::Time::FromTimeT(file_info.st_atime);
+ info->creation_time = base::Time::FromTimeT(file_info.st_ctime);
+ return true;
+}
+
+} // namespace base
diff --git a/base/port.h b/base/port.h
new file mode 100644
index 000000000000..2e66057aeeaf
--- /dev/null
+++ b/base/port.h
@@ -0,0 +1,55 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PORT_H_
+#define BASE_PORT_H_
+#pragma once
+
+#include <stdarg.h>
+#include "build/build_config.h"
+
+#ifdef COMPILER_MSVC
+#define GG_LONGLONG(x) x##I64
+#define GG_ULONGLONG(x) x##UI64
+#else
+#define GG_LONGLONG(x) x##LL
+#define GG_ULONGLONG(x) x##ULL
+#endif
+
+// Per C99 7.8.14, define __STDC_CONSTANT_MACROS before including <stdint.h>
+// to get the INTn_C and UINTn_C macros for integer constants. It's difficult
+// to guarantee any specific ordering of header includes, so it's difficult to
+// guarantee that the INTn_C macros can be defined by including <stdint.h> at
+// any specific point. Provide GG_INTn_C macros instead.
+
+#define GG_INT8_C(x) (x)
+#define GG_INT16_C(x) (x)
+#define GG_INT32_C(x) (x)
+#define GG_INT64_C(x) GG_LONGLONG(x)
+
+#define GG_UINT8_C(x) (x ## U)
+#define GG_UINT16_C(x) (x ## U)
+#define GG_UINT32_C(x) (x ## U)
+#define GG_UINT64_C(x) GG_ULONGLONG(x)
+
+// It's possible for functions that use a va_list, such as StringPrintf, to
+// invalidate the data in it upon use. The fix is to make a copy of the
+// structure before using it and use that copy instead. va_copy is provided
+// for this purpose. MSVC does not provide va_copy, so define an
+// implementation here. It is not guaranteed that assignment is a copy, so the
+// StringUtil.VariableArgsFunc unit test tests this capability.
+#if defined(COMPILER_GCC)
+#define GG_VA_COPY(a, b) (va_copy(a, b))
+#elif defined(COMPILER_MSVC)
+#define GG_VA_COPY(a, b) (a = b)
+#endif
+
+// Define an OS-neutral wrapper for shared library entry points
+#if defined(OS_WIN)
+#define API_CALL __stdcall
+#else
+#define API_CALL
+#endif
+
+#endif // BASE_PORT_H_
diff --git a/base/string16.cc b/base/string16.cc
new file mode 100644
index 000000000000..6fc38ce7cb09
--- /dev/null
+++ b/base/string16.cc
@@ -0,0 +1,80 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/string16.h"
+
+#if defined(WCHAR_T_IS_UTF16)
+
+#error This file should not be used on 2-byte wchar_t systems
+// If this winds up being needed on 2-byte wchar_t systems, either the
+// definitions below can be used, or the host system's wide character
+// functions like wmemcmp can be wrapped.
+
+#elif defined(WCHAR_T_IS_UTF32)
+
+#include <ostream>
+
+#include "base/utf_string_conversions.h"
+
+namespace base {
+
+int c16memcmp(const char16* s1, const char16* s2, size_t n) {
+ // We cannot call memcmp because that changes the semantics.
+ while (n-- > 0) {
+ if (*s1 != *s2) {
+ // We cannot use (*s1 - *s2) because char16 is unsigned.
+ return ((*s1 < *s2) ? -1 : 1);
+ }
+ ++s1;
+ ++s2;
+ }
+ return 0;
+}
+
+size_t c16len(const char16* s) {
+ const char16 *s_orig = s;
+ while (*s) {
+ ++s;
+ }
+ return s - s_orig;
+}
+
+const char16* c16memchr(const char16* s, char16 c, size_t n) {
+ while (n-- > 0) {
+ if (*s == c) {
+ return s;
+ }
+ ++s;
+ }
+ return 0;
+}
+
+char16* c16memmove(char16* s1, const char16* s2, size_t n) {
+ return reinterpret_cast<char16*>(memmove(s1, s2, n * sizeof(char16)));
+}
+
+char16* c16memcpy(char16* s1, const char16* s2, size_t n) {
+ return reinterpret_cast<char16*>(memcpy(s1, s2, n * sizeof(char16)));
+}
+
+char16* c16memset(char16* s, char16 c, size_t n) {
+ char16 *s_orig = s;
+ while (n-- > 0) {
+ *s = c;
+ ++s;
+ }
+ return s_orig;
+}
+
+} // namespace base
+
+template class std::basic_string<char16, base::string16_char_traits>;
+
+namespace base {
+std::ostream& operator<<(std::ostream& out, const string16& str) {
+ return out << UTF16ToUTF8(str);
+}
+}
+
+#endif // WCHAR_T_IS_UTF32
diff --git a/base/string16.h b/base/string16.h
new file mode 100644
index 000000000000..4c7b21f8a0eb
--- /dev/null
+++ b/base/string16.h
@@ -0,0 +1,178 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRING16_H_
+#define BASE_STRING16_H_
+#pragma once
+
+// WHAT:
+// A version of std::basic_string that provides 2-byte characters even when
+// wchar_t is not implemented as a 2-byte type. You can access this class as
+// string16. We also define char16, which string16 is based upon.
+//
+// WHY:
+// On Windows, wchar_t is 2 bytes, and it can conveniently handle UTF-16/UCS-2
+// data. Plenty of existing code operates on strings encoded as UTF-16.
+//
+// On many other platforms, sizeof(wchar_t) is 4 bytes by default. We can make
+// it 2 bytes by using the GCC flag -fshort-wchar. But then std::wstring fails
+// at run time, because it calls some functions (like wcslen) that come from
+// the system's native C library -- which was built with a 4-byte wchar_t!
+// It's wasteful to use 4-byte wchar_t strings to carry UTF-16 data, and it's
+// entirely improper on those systems where the encoding of wchar_t is defined
+// as UTF-32.
+//
+// Here, we define string16, which is similar to std::wstring but replaces all
+// libc functions with custom, 2-byte-char compatible routines. It is capable
+// of carrying UTF-16-encoded data.
+
+#include <stdio.h>
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+#if defined(WCHAR_T_IS_UTF16)
+
+typedef wchar_t char16;
+typedef std::wstring string16;
+
+#elif defined(WCHAR_T_IS_UTF32)
+
+typedef uint16 char16;
+
+namespace base {
+
+// char16 versions of the functions required by string16_char_traits; these
+// are based on the wide character functions of similar names ("w" or "wcs"
+// instead of "c16").
+BASE_EXPORT int c16memcmp(const char16* s1, const char16* s2, size_t n);
+BASE_EXPORT size_t c16len(const char16* s);
+BASE_EXPORT const char16* c16memchr(const char16* s, char16 c, size_t n);
+BASE_EXPORT char16* c16memmove(char16* s1, const char16* s2, size_t n);
+BASE_EXPORT char16* c16memcpy(char16* s1, const char16* s2, size_t n);
+BASE_EXPORT char16* c16memset(char16* s, char16 c, size_t n);
+
+struct string16_char_traits {
+ typedef char16 char_type;
+ typedef int int_type;
+
+ // 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);
+
+ typedef std::streamoff off_type;
+ typedef mbstate_t state_type;
+ typedef std::fpos<state_type> pos_type;
+
+ static void assign(char_type& c1, const char_type& c2) {
+ c1 = c2;
+ }
+
+ static bool eq(const char_type& c1, const char_type& c2) {
+ return c1 == c2;
+ }
+ static bool lt(const char_type& c1, const char_type& c2) {
+ return c1 < c2;
+ }
+
+ static int compare(const char_type* s1, const char_type* s2, size_t n) {
+ return c16memcmp(s1, s2, n);
+ }
+
+ static size_t length(const char_type* s) {
+ return c16len(s);
+ }
+
+ static const char_type* find(const char_type* s, size_t n,
+ const char_type& a) {
+ return c16memchr(s, a, n);
+ }
+
+ static char_type* move(char_type* s1, const char_type* s2, int_type n) {
+ return c16memmove(s1, s2, n);
+ }
+
+ static char_type* copy(char_type* s1, const char_type* s2, size_t n) {
+ return c16memcpy(s1, s2, n);
+ }
+
+ static char_type* assign(char_type* s, size_t n, char_type a) {
+ return c16memset(s, a, n);
+ }
+
+ static int_type not_eof(const int_type& c) {
+ return eq_int_type(c, eof()) ? 0 : c;
+ }
+
+ static char_type to_char_type(const int_type& c) {
+ return char_type(c);
+ }
+
+ static int_type to_int_type(const char_type& c) {
+ return int_type(c);
+ }
+
+ static bool eq_int_type(const int_type& c1, const int_type& c2) {
+ return c1 == c2;
+ }
+
+ static int_type eof() {
+ return static_cast<int_type>(EOF);
+ }
+};
+
+} // namespace base
+
+// The string class will be explicitly instantiated only once, in string16.cc.
+//
+// std::basic_string<> in GNU libstdc++ contains a static data member,
+// _S_empty_rep_storage, to represent empty strings. When an operation such
+// as assignment or destruction is performed on a string, causing its existing
+// data member to be invalidated, it must not be freed if this static data
+// member is being used. Otherwise, it counts as an attempt to free static
+// (and not allocated) data, which is a memory error.
+//
+// Generally, due to C++ template magic, _S_empty_rep_storage will be marked
+// as a coalesced symbol, meaning that the linker will combine multiple
+// instances into a single one when generating output.
+//
+// If a string class is used by multiple shared libraries, a problem occurs.
+// Each library will get its own copy of _S_empty_rep_storage. When strings
+// are passed across a library boundary for alteration or destruction, memory
+// errors will result. GNU libstdc++ contains a configuration option,
+// --enable-fully-dynamic-string (_GLIBCXX_FULLY_DYNAMIC_STRING), which
+// disables the static data member optimization, but it's a good optimization
+// and non-STL code is generally at the mercy of the system's STL
+// configuration. Fully-dynamic strings are not the default for GNU libstdc++
+// libstdc++ itself or for the libstdc++ installations on the systems we care
+// about, such as Mac OS X and relevant flavors of Linux.
+//
+// See also http://gcc.gnu.org/bugzilla/show_bug.cgi?id=24196 .
+//
+// To avoid problems, string classes need to be explicitly instantiated only
+// once, in exactly one library. All other string users see it via an "extern"
+// declaration. This is precisely how GNU libstdc++ handles
+// std::basic_string<char> (string) and std::basic_string<wchar_t> (wstring).
+//
+// This also works around a Mac OS X linker bug in ld64-85.2.1 (Xcode 3.1.2),
+// in which the linker does not fully coalesce symbols when dead code
+// stripping is enabled. This bug causes the memory errors described above
+// to occur even when a std::basic_string<> does not cross shared library
+// boundaries, such as in statically-linked executables.
+//
+// TODO(mark): File this bug with Apple and update this note with a bug number.
+
+extern template class std::basic_string<char16, base::string16_char_traits>;
+
+typedef std::basic_string<char16, base::string16_char_traits> string16;
+
+namespace base {
+BASE_EXPORT extern std::ostream& operator<<(std::ostream& out,
+ const string16& str);
+}
+
+#endif // WCHAR_T_IS_UTF32
+
+#endif // BASE_STRING16_H_
diff --git a/base/string_number_conversions.cc b/base/string_number_conversions.cc
new file mode 100644
index 000000000000..54eca17511c1
--- /dev/null
+++ b/base/string_number_conversions.cc
@@ -0,0 +1,545 @@
+// 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/string_number_conversions.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <wctype.h>
+
+#include <limits>
+
+#include "base/logging.h"
+#include "base/third_party/dmg_fp/dmg_fp.h"
+#include "base/utf_string_conversions.h"
+
+namespace base {
+
+namespace {
+
+template <typename STR, typename INT, typename UINT, bool NEG>
+struct IntToStringT {
+ // This is to avoid a compiler warning about unary minus on unsigned type.
+ // For example, say you had the following code:
+ // template <typename INT>
+ // INT abs(INT value) { return value < 0 ? -value : value; }
+ // Even though if INT is unsigned, it's impossible for value < 0, so the
+ // unary minus will never be taken, the compiler will still generate a
+ // warning. We do a little specialization dance...
+ template <typename INT2, typename UINT2, bool NEG2>
+ struct ToUnsignedT {};
+
+ template <typename INT2, typename UINT2>
+ struct ToUnsignedT<INT2, UINT2, false> {
+ static UINT2 ToUnsigned(INT2 value) {
+ return static_cast<UINT2>(value);
+ }
+ };
+
+ template <typename INT2, typename UINT2>
+ struct ToUnsignedT<INT2, UINT2, true> {
+ static UINT2 ToUnsigned(INT2 value) {
+ return static_cast<UINT2>(value < 0 ? -value : value);
+ }
+ };
+
+ // This set of templates is very similar to the above templates, but
+ // for testing whether an integer is negative.
+ template <typename INT2, bool NEG2>
+ struct TestNegT {};
+ template <typename INT2>
+ struct TestNegT<INT2, false> {
+ static bool TestNeg(INT2 value) {
+ // value is unsigned, and can never be negative.
+ return false;
+ }
+ };
+ template <typename INT2>
+ struct TestNegT<INT2, true> {
+ static bool TestNeg(INT2 value) {
+ return value < 0;
+ }
+ };
+
+ static STR IntToString(INT value) {
+ // log10(2) ~= 0.3 bytes needed per bit or per byte log10(2**8) ~= 2.4.
+ // So round up to allocate 3 output characters per byte, plus 1 for '-'.
+ const int kOutputBufSize = 3 * sizeof(INT) + 1;
+
+ // Allocate the whole string right away, we will right back to front, and
+ // then return the substr of what we ended up using.
+ STR outbuf(kOutputBufSize, 0);
+
+ bool is_neg = TestNegT<INT, NEG>::TestNeg(value);
+ // Even though is_neg will never be true when INT is parameterized as
+ // unsigned, even the presence of the unary operation causes a warning.
+ UINT res = ToUnsignedT<INT, UINT, NEG>::ToUnsigned(value);
+
+ for (typename STR::iterator it = outbuf.end();;) {
+ --it;
+ DCHECK(it != outbuf.begin());
+ *it = static_cast<typename STR::value_type>((res % 10) + '0');
+ res /= 10;
+
+ // We're done..
+ if (res == 0) {
+ if (is_neg) {
+ --it;
+ DCHECK(it != outbuf.begin());
+ *it = static_cast<typename STR::value_type>('-');
+ }
+ return STR(it, outbuf.end());
+ }
+ }
+ NOTREACHED();
+ return STR();
+ }
+};
+
+// Utility to convert a character to a digit in a given base
+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) {
+ if (c >= '0' && c < '0' + BASE) {
+ *digit = c - '0';
+ return true;
+ }
+ return false;
+ }
+};
+
+// 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) {
+ if (c >= '0' && c <= '9') {
+ *digit = c - '0';
+ } else if (c >= 'a' && c < 'a' + BASE - 10) {
+ *digit = c - 'a' + 10;
+ } else if (c >= 'A' && c < 'A' + BASE - 10) {
+ *digit = c - 'A' + 10;
+ } else {
+ return false;
+ }
+ return true;
+ }
+};
+
+template<int BASE, typename CHAR> bool CharToDigit(CHAR c, uint8* digit) {
+ return BaseCharToDigit<CHAR, BASE, BASE <= 10>::Convert(c, digit);
+}
+
+// There is an IsWhitespace for wchars defined in string_util.h, but it is
+// locale independent, whereas the functions we are replacing were
+// locale-dependent. TBD what is desired, but for the moment let's not introduce
+// a change in behaviour.
+template<typename CHAR> class WhitespaceHelper {
+};
+
+template<> class WhitespaceHelper<char> {
+ public:
+ static bool Invoke(char c) {
+ return 0 != isspace(static_cast<unsigned char>(c));
+ }
+};
+
+template<> class WhitespaceHelper<char16> {
+ public:
+ static bool Invoke(char16 c) {
+ return 0 != iswspace(c);
+ }
+};
+
+template<typename CHAR> bool LocalIsWhitespace(CHAR c) {
+ return WhitespaceHelper<CHAR>::Invoke(c);
+}
+
+// IteratorRangeToNumberTraits should provide:
+// - a typedef for iterator_type, the iterator type used as input.
+// - a typedef for value_type, the target numeric type.
+// - static functions min, max (returning the minimum and maximum permitted
+// values)
+// - constant kBase, the base in which to interpret the input
+template<typename IteratorRangeToNumberTraits>
+class IteratorRangeToNumber {
+ public:
+ typedef IteratorRangeToNumberTraits traits;
+ typedef typename traits::iterator_type const_iterator;
+ typedef typename traits::value_type value_type;
+
+ // Generalized iterator-range-to-number conversion.
+ //
+ static bool Invoke(const_iterator begin,
+ const_iterator end,
+ value_type* output) {
+ bool valid = true;
+
+ while (begin != end && LocalIsWhitespace(*begin)) {
+ valid = false;
+ ++begin;
+ }
+
+ if (begin != end && *begin == '-') {
+ if (!Negative::Invoke(begin + 1, end, output)) {
+ valid = false;
+ }
+ } else {
+ if (begin != end && *begin == '+') {
+ ++begin;
+ }
+ if (!Positive::Invoke(begin, end, output)) {
+ valid = false;
+ }
+ }
+
+ return valid;
+ }
+
+ private:
+ // Sign provides:
+ // - a static function, CheckBounds, that determines whether the next digit
+ // causes an overflow/underflow
+ // - a static function, Increment, that appends the next digit appropriately
+ // according to the sign of the number being parsed.
+ template<typename Sign>
+ class Base {
+ public:
+ static bool Invoke(const_iterator begin, const_iterator end,
+ typename traits::value_type* output) {
+ *output = 0;
+
+ if (begin == end) {
+ return false;
+ }
+
+ // Note: no performance difference was found when using template
+ // specialization to remove this check in bases other than 16
+ if (traits::kBase == 16 && end - begin > 2 && *begin == '0' &&
+ (*(begin + 1) == 'x' || *(begin + 1) == 'X')) {
+ begin += 2;
+ }
+
+ for (const_iterator current = begin; current != end; ++current) {
+ uint8 new_digit = 0;
+
+ if (!CharToDigit<traits::kBase>(*current, &new_digit)) {
+ return false;
+ }
+
+ if (current != begin) {
+ if (!Sign::CheckBounds(output, new_digit)) {
+ return false;
+ }
+ *output *= traits::kBase;
+ }
+
+ Sign::Increment(new_digit, output);
+ }
+ return true;
+ }
+ };
+
+ class Positive : public Base<Positive> {
+ public:
+ static bool CheckBounds(value_type* output, uint8 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)) {
+ *output = traits::max();
+ return false;
+ }
+ return true;
+ }
+ static void Increment(uint8 increment, value_type* output) {
+ *output += increment;
+ }
+ };
+
+ class Negative : public Base<Negative> {
+ public:
+ static bool CheckBounds(value_type* output, uint8 new_digit) {
+ if (*output < traits::min() / traits::kBase ||
+ (*output == traits::min() / traits::kBase &&
+ new_digit > 0 - traits::min() % traits::kBase)) {
+ *output = traits::min();
+ return false;
+ }
+ return true;
+ }
+ static void Increment(uint8 increment, value_type* output) {
+ *output -= increment;
+ }
+ };
+};
+
+template<typename ITERATOR, typename VALUE, int BASE>
+class BaseIteratorRangeToNumberTraits {
+ public:
+ typedef ITERATOR iterator_type;
+ typedef VALUE value_type;
+ static value_type min() {
+ return std::numeric_limits<value_type>::min();
+ }
+ static value_type max() {
+ return std::numeric_limits<value_type>::max();
+ }
+ static const int kBase = BASE;
+};
+
+typedef BaseIteratorRangeToNumberTraits<std::string::const_iterator, int, 10>
+ IteratorRangeToIntTraits;
+typedef BaseIteratorRangeToNumberTraits<string16::const_iterator, int, 10>
+ WideIteratorRangeToIntTraits;
+typedef BaseIteratorRangeToNumberTraits<std::string::const_iterator, int64, 10>
+ IteratorRangeToInt64Traits;
+typedef BaseIteratorRangeToNumberTraits<string16::const_iterator, int64, 10>
+ WideIteratorRangeToInt64Traits;
+
+typedef BaseIteratorRangeToNumberTraits<const char*, int, 10>
+ CharBufferToIntTraits;
+typedef BaseIteratorRangeToNumberTraits<const char16*, int, 10>
+ WideCharBufferToIntTraits;
+typedef BaseIteratorRangeToNumberTraits<const char*, int64, 10>
+ CharBufferToInt64Traits;
+typedef BaseIteratorRangeToNumberTraits<const char16*, int64, 10>
+ WideCharBufferToInt64Traits;
+
+template<typename ITERATOR>
+class BaseHexIteratorRangeToIntTraits
+ : public BaseIteratorRangeToNumberTraits<ITERATOR, int, 16> {
+ public:
+ // Allow parsing of 0xFFFFFFFF, which is technically an overflow
+ static unsigned int max() {
+ return std::numeric_limits<unsigned int>::max();
+ }
+};
+
+typedef BaseHexIteratorRangeToIntTraits<std::string::const_iterator>
+ HexIteratorRangeToIntTraits;
+typedef BaseHexIteratorRangeToIntTraits<const char*>
+ HexCharBufferToIntTraits;
+
+template<typename STR>
+bool HexStringToBytesT(const STR& input, std::vector<uint8>* 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
+ if (!CharToDigit<16>(input[i * 2], &msb) ||
+ !CharToDigit<16>(input[i * 2 + 1], &lsb))
+ return false;
+ output->push_back((msb << 4) | lsb);
+ }
+ return true;
+}
+
+} // namespace
+
+std::string IntToString(int value) {
+ return IntToStringT<std::string, int, unsigned int, true>::
+ IntToString(value);
+}
+
+string16 IntToString16(int value) {
+ return IntToStringT<string16, int, unsigned int, true>::
+ IntToString(value);
+}
+
+std::string UintToString(unsigned int value) {
+ return IntToStringT<std::string, unsigned int, unsigned int, false>::
+ IntToString(value);
+}
+
+string16 UintToString16(unsigned int value) {
+ return IntToStringT<string16, unsigned int, unsigned int, false>::
+ IntToString(value);
+}
+
+std::string Int64ToString(int64 value) {
+ return IntToStringT<std::string, int64, uint64, true>::
+ IntToString(value);
+}
+
+string16 Int64ToString16(int64 value) {
+ return IntToStringT<string16, int64, uint64, true>::IntToString(value);
+}
+
+std::string Uint64ToString(uint64 value) {
+ return IntToStringT<std::string, uint64, uint64, false>::
+ IntToString(value);
+}
+
+string16 Uint64ToString16(uint64 value) {
+ return IntToStringT<string16, uint64, uint64, false>::
+ IntToString(value);
+}
+
+std::string DoubleToString(double value) {
+ // According to g_fmt.cc, it is sufficient to declare a buffer of size 32.
+ char buffer[32];
+ dmg_fp::g_fmt(buffer, value);
+ return std::string(buffer);
+}
+
+bool StringToInt(const std::string& input, int* output) {
+ return IteratorRangeToNumber<IteratorRangeToIntTraits>::Invoke(input.begin(),
+ input.end(),
+ output);
+}
+
+bool StringToInt(std::string::const_iterator begin,
+ std::string::const_iterator end,
+ int* output) {
+ return IteratorRangeToNumber<IteratorRangeToIntTraits>::Invoke(begin,
+ end,
+ output);
+}
+
+#if !defined(STD_STRING_ITERATOR_IS_CHAR_POINTER)
+bool StringToInt(const char* begin, const char* end, int* output) {
+ return IteratorRangeToNumber<CharBufferToIntTraits>::Invoke(begin,
+ end,
+ output);
+}
+#endif
+
+bool StringToInt(const string16& input, int* output) {
+ return IteratorRangeToNumber<WideIteratorRangeToIntTraits>::Invoke(
+ input.begin(), input.end(), output);
+}
+
+bool StringToInt(string16::const_iterator begin,
+ string16::const_iterator end,
+ int* output) {
+ return IteratorRangeToNumber<WideIteratorRangeToIntTraits>::Invoke(begin,
+ end,
+ output);
+}
+
+#if !defined(BASE_STRING16_ITERATOR_IS_CHAR16_POINTER)
+bool StringToInt(const char16* begin, const char16* end, int* output) {
+ return IteratorRangeToNumber<WideCharBufferToIntTraits>::Invoke(begin,
+ end,
+ output);
+}
+#endif
+
+bool StringToInt64(const std::string& input, int64* output) {
+ return IteratorRangeToNumber<IteratorRangeToInt64Traits>::Invoke(
+ input.begin(), input.end(), output);
+}
+
+bool StringToInt64(std::string::const_iterator begin,
+ std::string::const_iterator end,
+ int64* output) {
+ return IteratorRangeToNumber<IteratorRangeToInt64Traits>::Invoke(begin,
+ end,
+ output);
+}
+
+#if !defined(STD_STRING_ITERATOR_IS_CHAR_POINTER)
+bool StringToInt64(const char* begin, const char* end, int64* output) {
+ return IteratorRangeToNumber<CharBufferToInt64Traits>::Invoke(begin,
+ end,
+ output);
+}
+#endif
+
+bool StringToInt64(const string16& input, int64* output) {
+ return IteratorRangeToNumber<WideIteratorRangeToInt64Traits>::Invoke(
+ input.begin(), input.end(), output);
+}
+
+bool StringToInt64(string16::const_iterator begin,
+ string16::const_iterator end,
+ int64* output) {
+ return IteratorRangeToNumber<WideIteratorRangeToInt64Traits>::Invoke(begin,
+ end,
+ output);
+}
+
+#if !defined(BASE_STRING16_ITERATOR_IS_CHAR16_POINTER)
+bool StringToInt64(const char16* begin, const char16* end, int64* output) {
+ return IteratorRangeToNumber<WideCharBufferToInt64Traits>::Invoke(begin,
+ end,
+ output);
+}
+#endif
+
+bool StringToDouble(const std::string& input, double* output) {
+ errno = 0; // Thread-safe? It is on at least Mac, Linux, and Windows.
+ char* endptr = NULL;
+ *output = dmg_fp::strtod(input.c_str(), &endptr);
+
+ // Cases to return false:
+ // - If errno is ERANGE, there was an overflow or underflow.
+ // - If the input string is empty, there was nothing to parse.
+ // - If endptr does not point to the end of the string, there are either
+ // characters remaining in the string after a parsed number, or the string
+ // does not begin with a parseable number. endptr is compared to the
+ // expected end given the string's stated length to correctly catch cases
+ // where the string contains embedded NUL characters.
+ // - If the first character is a space, there was leading whitespace
+ return errno == 0 &&
+ !input.empty() &&
+ input.c_str() + input.length() == endptr &&
+ !isspace(input[0]);
+}
+
+// Note: if you need to add String16ToDouble, first ask yourself if it's
+// really necessary. If it is, probably the best implementation here is to
+// convert to 8-bit and then use the 8-bit version.
+
+// Note: if you need to add an iterator range version of StringToDouble, first
+// ask yourself if it's really necessary. If it is, probably the best
+// implementation here is to instantiate a string and use the string version.
+
+std::string HexEncode(const void* bytes, size_t size) {
+ static const char kHexChars[] = "0123456789ABCDEF";
+
+ // Each input byte creates two output hex characters.
+ std::string ret(size * 2, '\0');
+
+ for (size_t i = 0; i < size; ++i) {
+ char b = reinterpret_cast<const char*>(bytes)[i];
+ ret[(i * 2)] = kHexChars[(b >> 4) & 0xf];
+ ret[(i * 2) + 1] = kHexChars[b & 0xf];
+ }
+ return ret;
+}
+
+bool HexStringToInt(const std::string& input, int* output) {
+ return IteratorRangeToNumber<HexIteratorRangeToIntTraits>::Invoke(
+ input.begin(), input.end(), output);
+}
+
+bool HexStringToInt(std::string::const_iterator begin,
+ std::string::const_iterator end,
+ int* output) {
+ return IteratorRangeToNumber<HexIteratorRangeToIntTraits>::Invoke(begin,
+ end,
+ output);
+}
+
+#if !defined(STD_STRING_ITERATOR_IS_CHAR_POINTER)
+bool HexStringToInt(const char* begin, const char* end, int* output) {
+ return IteratorRangeToNumber<HexCharBufferToIntTraits>::Invoke(begin,
+ end,
+ output);
+}
+#endif
+
+bool HexStringToBytes(const std::string& input, std::vector<uint8>* output) {
+ return HexStringToBytesT(input, output);
+}
+
+} // namespace base
diff --git a/base/string_number_conversions.h b/base/string_number_conversions.h
new file mode 100644
index 000000000000..6cf6a76b80d2
--- /dev/null
+++ b/base/string_number_conversions.h
@@ -0,0 +1,124 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_STRING_NUMBER_CONVERSIONS_H_
+#define BASE_STRING_NUMBER_CONVERSIONS_H_
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/string16.h"
+
+// ----------------------------------------------------------------------------
+// IMPORTANT MESSAGE FROM YOUR SPONSOR
+//
+// This file contains no "wstring" variants. New code should use string16. If
+// you need to make old code work, use the UTF8 version and convert. Please do
+// not add wstring variants.
+//
+// Please do not add "convenience" functions for converting strings to integers
+// that return the value and ignore success/failure. That encourages people to
+// write code that doesn't properly handle the error conditions.
+// ----------------------------------------------------------------------------
+
+namespace base {
+
+// Number -> string conversions ------------------------------------------------
+
+BASE_EXPORT std::string IntToString(int value);
+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 Uint64ToString(uint64 value);
+BASE_EXPORT string16 Uint64ToString16(uint64 value);
+
+// DoubleToString converts the double to a string format that ignores the
+// locale. If you want to use locale specific formatting, use ICU.
+BASE_EXPORT std::string DoubleToString(double value);
+
+// String -> number conversions ------------------------------------------------
+
+// Perform a best-effort conversion of the input string to a numeric type,
+// setting |*output| to the result of the conversion. Returns true for
+// "perfect" conversions; returns false in the following cases:
+// - Overflow/underflow. |*output| will be set to the maximum value supported
+// by the data type.
+// - Trailing characters in the string after parsing the number. |*output|
+// will be set to the value of the number that was parsed.
+// - Leading whitespace in the string before parsing the number. |*output| will
+// be set to the value of the number that was parsed.
+// - No characters parseable as a number at the beginning of the string.
+// |*output| will be set to 0.
+// - Empty string. |*output| will be set to 0.
+BASE_EXPORT bool StringToInt(const std::string& input, int* output);
+BASE_EXPORT bool StringToInt(std::string::const_iterator begin,
+ std::string::const_iterator end,
+ int* output);
+BASE_EXPORT bool StringToInt(const char* begin, const char* end, int* output);
+
+BASE_EXPORT bool StringToInt(const string16& input, int* output);
+BASE_EXPORT bool StringToInt(string16::const_iterator begin,
+ string16::const_iterator end,
+ int* output);
+BASE_EXPORT bool StringToInt(const char16* begin, const char16* end,
+ int* output);
+
+BASE_EXPORT bool StringToInt64(const std::string& input, int64* output);
+BASE_EXPORT bool StringToInt64(std::string::const_iterator begin,
+ std::string::const_iterator end,
+ int64* output);
+BASE_EXPORT bool StringToInt64(const char* begin, const char* end,
+ int64* output);
+
+BASE_EXPORT bool StringToInt64(const string16& input, int64* output);
+BASE_EXPORT bool StringToInt64(string16::const_iterator begin,
+ string16::const_iterator end,
+ int64* output);
+BASE_EXPORT bool StringToInt64(const char16* begin, const char16* end,
+ int64* output);
+
+// For floating-point conversions, only conversions of input strings in decimal
+// form are defined to work. Behavior with strings representing floating-point
+// numbers in hexadecimal, and strings representing non-fininte values (such as
+// NaN and inf) is undefined. Otherwise, these behave the same as the integral
+// variants. This expects the input string to NOT be specific to the locale.
+// If your input is locale specific, use ICU to read the number.
+BASE_EXPORT bool StringToDouble(const std::string& input, double* output);
+
+// Hex encoding ----------------------------------------------------------------
+
+// Returns a hex string representation of a binary buffer. The returned hex
+// string will be in upper case. This function does not check if |size| is
+// within reasonable limits since it's written with trusted data in mind. If
+// you suspect that the data you want to format might be large, the absolute
+// max size for |size| should be is
+// std::numeric_limits<size_t>::max() / 2
+BASE_EXPORT std::string HexEncode(const void* bytes, size_t size);
+
+// Best effort conversion, see StringToInt above for restrictions.
+BASE_EXPORT bool HexStringToInt(const std::string& input, int* output);
+BASE_EXPORT bool HexStringToInt(std::string::const_iterator begin,
+ std::string::const_iterator end,
+ int* output);
+BASE_EXPORT bool HexStringToInt(const char* begin, const char* end,
+ int* 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);
+
+} // namespace base
+
+#endif // BASE_STRING_NUMBER_CONVERSIONS_H_
+
diff --git a/base/string_piece.cc b/base/string_piece.cc
new file mode 100644
index 000000000000..bf6291c28075
--- /dev/null
+++ b/base/string_piece.cc
@@ -0,0 +1,214 @@
+// 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.
+// Copied from strings/stringpiece.cc with modifications
+
+#include <algorithm>
+#include <ostream>
+
+#include "base/string_piece.h"
+
+namespace base {
+
+typedef StringPiece::size_type size_type;
+
+bool operator==(const StringPiece& x, const StringPiece& y) {
+ if (x.size() != y.size())
+ return false;
+
+ return StringPiece::wordmemcmp(x.data(), y.data(), x.size()) == 0;
+}
+
+void StringPiece::CopyToString(std::string* target) const {
+ target->assign(!empty() ? data() : "", size());
+}
+
+void StringPiece::AppendToString(std::string* target) const {
+ if (!empty())
+ target->append(data(), size());
+}
+
+size_type StringPiece::copy(char* buf, size_type n, size_type pos) const {
+ size_type ret = std::min(length_ - pos, n);
+ memcpy(buf, ptr_ + pos, ret);
+ return ret;
+}
+
+size_type StringPiece::find(const StringPiece& s, size_type pos) const {
+ if (pos > length_)
+ return npos;
+
+ const char* result = std::search(ptr_ + pos, ptr_ + length_,
+ s.ptr_, s.ptr_ + s.length_);
+ const size_type xpos = result - ptr_;
+ return xpos + s.length_ <= length_ ? xpos : npos;
+}
+
+size_type StringPiece::find(char c, size_type pos) const {
+ if (pos >= length_)
+ return npos;
+
+ const char* result = std::find(ptr_ + pos, ptr_ + length_, c);
+ return result != ptr_ + length_ ? static_cast<size_t>(result - ptr_) : npos;
+}
+
+size_type StringPiece::rfind(const StringPiece& s, size_type pos) const {
+ if (length_ < s.length_)
+ return npos;
+
+ if (s.empty())
+ return std::min(length_, pos);
+
+ const char* last = ptr_ + std::min(length_ - s.length_, pos) + s.length_;
+ const char* result = std::find_end(ptr_, last, s.ptr_, s.ptr_ + s.length_);
+ return result != last ? static_cast<size_t>(result - ptr_) : npos;
+}
+
+size_type StringPiece::rfind(char c, size_type pos) const {
+ if (length_ == 0)
+ return npos;
+
+ for (size_type i = std::min(pos, length_ - 1); ; --i) {
+ if (ptr_[i] == c)
+ return i;
+ if (i == 0)
+ break;
+ }
+ return npos;
+}
+
+// For each character in characters_wanted, sets the index corresponding
+// to the ASCII code of that character to 1 in table. This is used by
+// the find_.*_of methods below to tell whether or not a character is in
+// the lookup table in constant time.
+// The argument `table' must be an array that is large enough to hold all
+// the possible values of an unsigned char. Thus it should be be declared
+// as follows:
+// bool table[UCHAR_MAX + 1]
+static inline void BuildLookupTable(const StringPiece& characters_wanted,
+ bool* table) {
+ const size_type length = characters_wanted.length();
+ const char* const data = characters_wanted.data();
+ for (size_type i = 0; i < length; ++i) {
+ table[static_cast<unsigned char>(data[i])] = true;
+ }
+}
+
+size_type StringPiece::find_first_of(const StringPiece& s,
+ size_type pos) const {
+ if (length_ == 0 || s.length_ == 0)
+ return npos;
+
+ // Avoid the cost of BuildLookupTable() for a single-character search.
+ if (s.length_ == 1)
+ return find_first_of(s.ptr_[0], pos);
+
+ bool lookup[UCHAR_MAX + 1] = { false };
+ BuildLookupTable(s, lookup);
+ for (size_type i = pos; i < length_; ++i) {
+ if (lookup[static_cast<unsigned char>(ptr_[i])]) {
+ return i;
+ }
+ }
+ return npos;
+}
+
+size_type StringPiece::find_first_not_of(const StringPiece& s,
+ size_type pos) const {
+ if (length_ == 0)
+ return npos;
+
+ if (s.length_ == 0)
+ return 0;
+
+ // Avoid the cost of BuildLookupTable() for a single-character search.
+ if (s.length_ == 1)
+ return find_first_not_of(s.ptr_[0], pos);
+
+ bool lookup[UCHAR_MAX + 1] = { false };
+ BuildLookupTable(s, lookup);
+ for (size_type i = pos; i < length_; ++i) {
+ if (!lookup[static_cast<unsigned char>(ptr_[i])]) {
+ return i;
+ }
+ }
+ return npos;
+}
+
+size_type StringPiece::find_first_not_of(char c, size_type pos) const {
+ if (length_ == 0)
+ return npos;
+
+ for (; pos < length_; ++pos) {
+ if (ptr_[pos] != c) {
+ return pos;
+ }
+ }
+ return npos;
+}
+
+size_type StringPiece::find_last_of(const StringPiece& s, size_type pos) const {
+ if (length_ == 0 || s.length_ == 0)
+ return npos;
+
+ // Avoid the cost of BuildLookupTable() for a single-character search.
+ if (s.length_ == 1)
+ return find_last_of(s.ptr_[0], pos);
+
+ bool lookup[UCHAR_MAX + 1] = { false };
+ BuildLookupTable(s, lookup);
+ for (size_type i = std::min(pos, length_ - 1); ; --i) {
+ if (lookup[static_cast<unsigned char>(ptr_[i])])
+ return i;
+ if (i == 0)
+ break;
+ }
+ return npos;
+}
+
+size_type StringPiece::find_last_not_of(const StringPiece& s,
+ size_type pos) const {
+ if (length_ == 0)
+ return npos;
+
+ size_type i = std::min(pos, length_ - 1);
+ if (s.length_ == 0)
+ return i;
+
+ // Avoid the cost of BuildLookupTable() for a single-character search.
+ if (s.length_ == 1)
+ return find_last_not_of(s.ptr_[0], pos);
+
+ bool lookup[UCHAR_MAX + 1] = { false };
+ BuildLookupTable(s, lookup);
+ for (; ; --i) {
+ if (!lookup[static_cast<unsigned char>(ptr_[i])])
+ return i;
+ if (i == 0)
+ break;
+ }
+ return npos;
+}
+
+size_type StringPiece::find_last_not_of(char c, size_type pos) const {
+ if (length_ == 0)
+ return npos;
+
+ for (size_type i = std::min(pos, length_ - 1); ; --i) {
+ if (ptr_[i] != c)
+ return i;
+ if (i == 0)
+ break;
+ }
+ return npos;
+}
+
+StringPiece StringPiece::substr(size_type pos, size_type n) const {
+ if (pos > length_) pos = length_;
+ if (n > length_ - pos) n = length_ - pos;
+ return StringPiece(ptr_ + pos, n);
+}
+
+const StringPiece::size_type StringPiece::npos = size_type(-1);
+
+} // namespace base
diff --git a/base/string_piece.h b/base/string_piece.h
new file mode 100644
index 000000000000..278c7b692ae4
--- /dev/null
+++ b/base/string_piece.h
@@ -0,0 +1,349 @@
+// 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.
+// Copied from strings/stringpiece.h with modifications
+//
+// A string-like object that points to a sized piece of memory.
+//
+// Functions or methods may use const StringPiece& parameters to accept either
+// a "const char*" or a "string" value that will be implicitly converted to
+// a StringPiece. The implicit conversion means that it is often appropriate
+// to include this .h file in other files rather than forward-declaring
+// StringPiece as would be appropriate for most other Google classes.
+//
+// Systematic usage of StringPiece is encouraged as it will reduce unnecessary
+// conversions from "const char*" to "string" and back again.
+//
+// StringPiece16 is similar to StringPiece but for base::string16 instead of
+// std::string. We do not define as large of a subset of the STL functions
+// from basic_string as in StringPiece, but this can be changed if these
+// functions (find, find_first_of, etc.) are found to be useful in this context.
+//
+
+#ifndef BASE_STRING_PIECE_H_
+#define BASE_STRING_PIECE_H_
+#pragma once
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/hash_tables.h"
+#include "base/string16.h"
+
+namespace base {
+
+class BASE_EXPORT StringPiece {
+ public:
+ // standard STL container boilerplate
+ typedef size_t size_type;
+ typedef char value_type;
+ typedef const char* pointer;
+ typedef const char& reference;
+ typedef const char& const_reference;
+ typedef ptrdiff_t difference_type;
+ typedef const char* const_iterator;
+ typedef const char* iterator;
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+
+ static const size_type npos;
+
+ public:
+ // We provide non-explicit singleton constructors so users can pass
+ // in a "const char*" or a "string" wherever a "StringPiece" is
+ // expected.
+ StringPiece() : ptr_(NULL), length_(0) { }
+ StringPiece(const char* str)
+ : ptr_(str), length_((str == NULL) ? 0 : strlen(str)) { }
+ StringPiece(const std::string& str)
+ : ptr_(str.data()), length_(str.size()) { }
+ StringPiece(const char* offset, size_type len)
+ : ptr_(offset), length_(len) { }
+
+ // data() may return a pointer to a buffer with embedded NULs, and the
+ // returned buffer may or may not be null terminated. Therefore it is
+ // typically a mistake to pass data() to a routine that expects a NUL
+ // terminated string.
+ const char* data() const { return ptr_; }
+ size_type size() const { return length_; }
+ size_type length() const { return length_; }
+ bool empty() const { return length_ == 0; }
+
+ void clear() {
+ ptr_ = NULL;
+ length_ = 0;
+ }
+ void set(const char* data, size_type len) {
+ ptr_ = data;
+ length_ = len;
+ }
+ void set(const char* str) {
+ ptr_ = str;
+ length_ = str ? strlen(str) : 0;
+ }
+ void set(const void* data, size_type len) {
+ ptr_ = reinterpret_cast<const char*>(data);
+ length_ = len;
+ }
+
+ char operator[](size_type i) const { return ptr_[i]; }
+
+ void remove_prefix(size_type n) {
+ ptr_ += n;
+ length_ -= n;
+ }
+
+ void remove_suffix(size_type n) {
+ length_ -= n;
+ }
+
+ int compare(const StringPiece& x) const {
+ int r = wordmemcmp(
+ ptr_, x.ptr_, (length_ < x.length_ ? length_ : x.length_));
+ if (r == 0) {
+ if (length_ < x.length_) r = -1;
+ else if (length_ > x.length_) r = +1;
+ }
+ return r;
+ }
+
+ std::string as_string() const {
+ // std::string doesn't like to take a NULL pointer even with a 0 size.
+ return std::string(!empty() ? data() : "", size());
+ }
+
+ void CopyToString(std::string* target) const;
+ void AppendToString(std::string* target) const;
+
+ // Does "this" start with "x"
+ bool starts_with(const StringPiece& x) const {
+ return ((length_ >= x.length_) &&
+ (wordmemcmp(ptr_, x.ptr_, x.length_) == 0));
+ }
+
+ // Does "this" end with "x"
+ bool ends_with(const StringPiece& x) const {
+ return ((length_ >= x.length_) &&
+ (wordmemcmp(ptr_ + (length_-x.length_), x.ptr_, x.length_) == 0));
+ }
+
+ iterator begin() const { return ptr_; }
+ iterator end() const { return ptr_ + length_; }
+ const_reverse_iterator rbegin() const {
+ return const_reverse_iterator(ptr_ + length_);
+ }
+ const_reverse_iterator rend() const {
+ return const_reverse_iterator(ptr_);
+ }
+
+ size_type max_size() const { return length_; }
+ size_type capacity() const { return length_; }
+
+ size_type copy(char* buf, size_type n, size_type pos = 0) const;
+
+ size_type find(const StringPiece& s, size_type pos = 0) const;
+ size_type find(char c, size_type pos = 0) const;
+ size_type rfind(const StringPiece& s, size_type pos = npos) const;
+ size_type rfind(char c, size_type pos = npos) const;
+
+ size_type find_first_of(const StringPiece& s, size_type pos = 0) const;
+ size_type find_first_of(char c, size_type pos = 0) const {
+ return find(c, pos);
+ }
+ size_type find_first_not_of(const StringPiece& s, size_type pos = 0) const;
+ size_type find_first_not_of(char c, size_type pos = 0) const;
+ size_type find_last_of(const StringPiece& s, size_type pos = npos) const;
+ size_type find_last_of(char c, size_type pos = npos) const {
+ return rfind(c, pos);
+ }
+ size_type find_last_not_of(const StringPiece& s, size_type pos = npos) const;
+ size_type find_last_not_of(char c, size_type pos = npos) const;
+
+ StringPiece substr(size_type pos, size_type n = npos) const;
+
+ static int wordmemcmp(const char* p, const char* p2, size_type N) {
+ return memcmp(p, p2, N);
+ }
+
+ private:
+ const char* ptr_;
+ size_type length_;
+};
+
+class BASE_EXPORT StringPiece16 {
+ public:
+ // standard STL container boilerplate
+ typedef size_t size_type;
+ typedef char16 value_type;
+ typedef const char16* pointer;
+ typedef const char16& reference;
+ typedef const char16& const_reference;
+ typedef ptrdiff_t difference_type;
+ typedef const char16* const_iterator;
+ typedef const char16* iterator;
+ typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+ typedef std::reverse_iterator<iterator> reverse_iterator;
+
+ public:
+ // We provide non-explicit singleton constructors so users can pass
+ // in a "const char16*" or a "string16" wherever a "StringPiece16" is
+ // expected.
+ StringPiece16() : ptr_(NULL), length_(0) { }
+ StringPiece16(const char16* str)
+ : ptr_(str),
+ length_((str == NULL) ? 0 : string16::traits_type::length(str)) { }
+ StringPiece16(const string16& str)
+ : ptr_(str.data()), length_(str.size()) { }
+ StringPiece16(const char16* offset, size_type len)
+ : ptr_(offset), length_(len) { }
+
+ // data() may return a pointer to a buffer with embedded NULs, and the
+ // returned buffer may or may not be null terminated. Therefore it is
+ // typically a mistake to pass data() to a routine that expects a NUL
+ // terminated string.
+ const char16* data() const { return ptr_; }
+ size_type size() const { return length_; }
+ size_type length() const { return length_; }
+ bool empty() const { return length_ == 0; }
+
+ void clear() {
+ ptr_ = NULL;
+ length_ = 0;
+ }
+ void set(const char16* data, size_type len) {
+ ptr_ = data;
+ length_ = len;
+ }
+ void set(const char16* str) {
+ ptr_ = str;
+ length_ = str ? string16::traits_type::length(str) : 0;
+ }
+
+ char16 operator[](size_type i) const { return ptr_[i]; }
+
+ string16 as_string16() const {
+ // StringPiece claims that this is bad when data() is NULL, but unittesting
+ // seems to say otherwise.
+ return string16(data(), size());
+ }
+
+ iterator begin() const { return ptr_; }
+ iterator end() const { return ptr_ + length_; }
+ const_reverse_iterator rbegin() const {
+ return const_reverse_iterator(ptr_ + length_);
+ }
+ const_reverse_iterator rend() const {
+ return const_reverse_iterator(ptr_);
+ }
+
+ size_type max_size() const { return length_; }
+ size_type capacity() const { return length_; }
+
+ static int wordmemcmp(const char16* p, const char16* p2, size_type N) {
+ return string16::traits_type::compare(p, p2, N);
+ }
+
+ private:
+ const char16* ptr_;
+ size_type length_;
+};
+
+BASE_EXPORT bool operator==(const StringPiece& x, const StringPiece& y);
+
+inline bool operator!=(const StringPiece& x, const StringPiece& y) {
+ return !(x == y);
+}
+
+inline bool operator<(const StringPiece& x, const StringPiece& y) {
+ const int r = StringPiece::wordmemcmp(
+ x.data(), y.data(), (x.size() < y.size() ? x.size() : y.size()));
+ return ((r < 0) || ((r == 0) && (x.size() < y.size())));
+}
+
+inline bool operator>(const StringPiece& x, const StringPiece& y) {
+ return y < x;
+}
+
+inline bool operator<=(const StringPiece& x, const StringPiece& y) {
+ return !(x > y);
+}
+
+inline bool operator>=(const StringPiece& x, const StringPiece& y) {
+ return !(x < y);
+}
+
+inline bool operator==(const StringPiece16& x, const StringPiece16& y) {
+ if (x.size() != y.size())
+ return false;
+
+ return StringPiece16::wordmemcmp(x.data(), y.data(), x.size()) == 0;
+}
+
+inline bool operator!=(const StringPiece16& x, const StringPiece16& y) {
+ return !(x == y);
+}
+
+inline bool operator<(const StringPiece16& x, const StringPiece16& y) {
+ const int r = StringPiece16::wordmemcmp(
+ x.data(), y.data(), (x.size() < y.size() ? x.size() : y.size()));
+ return ((r < 0) || ((r == 0) && (x.size() < y.size())));
+}
+
+inline bool operator>(const StringPiece16& x, const StringPiece16& y) {
+ return y < x;
+}
+
+inline bool operator<=(const StringPiece16& x, const StringPiece16& y) {
+ return !(x > y);
+}
+
+inline bool operator>=(const StringPiece16& x, const StringPiece16& y) {
+ return !(x < y);
+}
+
+} // namespace base
+
+// We provide appropriate hash functions so StringPiece and StringPiece16 can
+// be used as keys in hash sets and maps.
+
+// This hash function is copied from base/hash_tables.h. We don't use the
+// ones already defined for string and string16 directly because it would
+// require the string constructors to be called, which we don't want.
+#define HASH_STRING_PIECE(StringPieceType, string_piece) \
+ std::size_t result = 0; \
+ for (StringPieceType::const_iterator i = string_piece.begin(); \
+ i != string_piece.end(); ++i) \
+ result = (result * 131) + *i; \
+ return result; \
+
+namespace BASE_HASH_NAMESPACE {
+#if defined(COMPILER_GCC)
+
+template<>
+struct hash<base::StringPiece> {
+ std::size_t operator()(const base::StringPiece& sp) const {
+ HASH_STRING_PIECE(base::StringPiece, sp);
+ }
+};
+template<>
+struct hash<base::StringPiece16> {
+ std::size_t operator()(const base::StringPiece16& sp16) const {
+ HASH_STRING_PIECE(base::StringPiece16, sp16);
+ }
+};
+
+#elif defined(COMPILER_MSVC)
+
+inline size_t hash_value(const base::StringPiece& sp) {
+ HASH_STRING_PIECE(base::StringPiece, sp);
+}
+inline size_t hash_value(const base::StringPiece16& sp16) {
+ HASH_STRING_PIECE(base::StringPiece16, sp16);
+}
+
+#endif // COMPILER
+
+} // namespace BASE_HASH_NAMESPACE
+
+#endif // BASE_STRING_PIECE_H_
diff --git a/base/synchronization/lock.h b/base/synchronization/lock.h
new file mode 100644
index 000000000000..f3a685e4ed0b
--- /dev/null
+++ b/base/synchronization/lock.h
@@ -0,0 +1,132 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SYNCHRONIZATION_LOCK_H_
+#define BASE_SYNCHRONIZATION_LOCK_H_
+#pragma once
+
+#include "base/base_export.h"
+#include "base/synchronization/lock_impl.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+// A convenient wrapper for an OS specific critical section. The only real
+// intelligence in this class is in debug mode for the support for the
+// AssertAcquired() method.
+class BASE_EXPORT Lock {
+ public:
+#if defined(NDEBUG) // Optimized wrapper implementation
+ Lock() : lock_() {}
+ ~Lock() {}
+ void Acquire() { lock_.Lock(); }
+ void Release() { lock_.Unlock(); }
+
+ // If the lock is not held, take it and return true. If the lock is already
+ // held by another thread, immediately return false. This must not be called
+ // by a thread already holding the lock (what happens is undefined and an
+ // assertion may fail).
+ bool Try() { return lock_.Try(); }
+
+ // Null implementation if not debug.
+ void AssertAcquired() const {}
+#else
+ Lock();
+ ~Lock() {}
+
+ // NOTE: Although windows critical sections support recursive locks, we do not
+ // allow this, and we will commonly fire a DCHECK() if a thread attempts to
+ // acquire the lock a second time (while already holding it).
+ void Acquire() {
+ lock_.Lock();
+ CheckUnheldAndMark();
+ }
+ void Release() {
+ CheckHeldAndUnmark();
+ lock_.Unlock();
+ }
+
+ bool Try() {
+ bool rv = lock_.Try();
+ if (rv) {
+ CheckUnheldAndMark();
+ }
+ return rv;
+ }
+
+ void AssertAcquired() const;
+#endif // NDEBUG
+
+#if defined(OS_POSIX)
+ // The posix implementation of ConditionVariable needs to be able
+ // to see our lock and tweak our debugging counters, as it releases
+ // and acquires locks inside of pthread_cond_{timed,}wait.
+ // Windows doesn't need to do this as it calls the Lock::* methods.
+ friend class ConditionVariable;
+#endif
+
+ private:
+#if !defined(NDEBUG)
+ // Members and routines taking care of locks assertions.
+ // Note that this checks for recursive locks and allows them
+ // if the variable is set. This is allowed by the underlying implementation
+ // on windows but not on Posix, so we're doing unneeded checks on Posix.
+ // It's worth it to share the code.
+ void CheckHeldAndUnmark();
+ void CheckUnheldAndMark();
+
+ // All private data is implicitly protected by lock_.
+ // Be VERY careful to only access members under that lock.
+
+ // Determines validity of owning_thread_id_. Needed as we don't have
+ // a null owning_thread_id_ value.
+ bool owned_by_thread_;
+ base::PlatformThreadId owning_thread_id_;
+#endif // NDEBUG
+
+ // Platform specific underlying lock implementation.
+ internal::LockImpl lock_;
+
+ DISALLOW_COPY_AND_ASSIGN(Lock);
+};
+
+// A helper class that acquires the given Lock while the AutoLock is in scope.
+class AutoLock {
+ public:
+ explicit AutoLock(Lock& lock) : lock_(lock) {
+ lock_.Acquire();
+ }
+
+ ~AutoLock() {
+ lock_.AssertAcquired();
+ lock_.Release();
+ }
+
+ private:
+ Lock& lock_;
+ DISALLOW_COPY_AND_ASSIGN(AutoLock);
+};
+
+// AutoUnlock is a helper that will Release() the |lock| argument in the
+// constructor, and re-Acquire() it in the destructor.
+class AutoUnlock {
+ public:
+ explicit AutoUnlock(Lock& lock) : lock_(lock) {
+ // We require our caller to have the lock.
+ lock_.AssertAcquired();
+ lock_.Release();
+ }
+
+ ~AutoUnlock() {
+ lock_.Acquire();
+ }
+
+ private:
+ Lock& lock_;
+ DISALLOW_COPY_AND_ASSIGN(AutoUnlock);
+};
+
+} // namespace base
+
+#endif // BASE_SYNCHRONIZATION_LOCK_H_
diff --git a/base/synchronization/lock_impl.h b/base/synchronization/lock_impl.h
new file mode 100644
index 000000000000..63efc5ff4ed1
--- /dev/null
+++ b/base/synchronization/lock_impl.h
@@ -0,0 +1,64 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SYNCHRONIZATION_LOCK_IMPL_H_
+#define BASE_SYNCHRONIZATION_LOCK_IMPL_H_
+#pragma once
+
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#elif defined(OS_POSIX)
+#include <pthread.h>
+#endif
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace internal {
+
+// This class implements the underlying platform-specific spin-lock mechanism
+// used for the Lock class. Most users should not use LockImpl directly, but
+// should instead use Lock.
+class BASE_EXPORT LockImpl {
+ public:
+#if defined(OS_WIN)
+ typedef CRITICAL_SECTION OSLockType;
+#elif defined(OS_POSIX)
+ typedef pthread_mutex_t OSLockType;
+#endif
+
+ LockImpl();
+ ~LockImpl();
+
+ // If the lock is not held, take it and return true. If the lock is already
+ // held by something else, immediately return false.
+ bool Try();
+
+ // Take the lock, blocking until it is available if necessary.
+ void Lock();
+
+ // Release the lock. This must only be called by the lock's holder: after
+ // a successful call to Try, or a call to Lock.
+ void Unlock();
+
+ // Return the native underlying lock. Not supported for Windows builds.
+ // TODO(awalker): refactor lock and condition variables so that this is
+ // unnecessary.
+#if !defined(OS_WIN)
+ OSLockType* os_lock() { return &os_lock_; }
+#endif
+
+ private:
+ OSLockType os_lock_;
+
+ DISALLOW_COPY_AND_ASSIGN(LockImpl);
+};
+
+} // namespace internal
+} // namespace base
+
+#endif // BASE_SYNCHRONIZATION_LOCK_IMPL_H_
diff --git a/base/synchronization/waitable_event.h b/base/synchronization/waitable_event.h
new file mode 100644
index 000000000000..62712edd9244
--- /dev/null
+++ b/base/synchronization/waitable_event.h
@@ -0,0 +1,181 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SYNCHRONIZATION_WAITABLE_EVENT_H_
+#define BASE_SYNCHRONIZATION_WAITABLE_EVENT_H_
+#pragma once
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+
+#if defined(OS_POSIX)
+#include <list>
+#include <utility>
+#include "base/memory/ref_counted.h"
+#include "base/synchronization/lock.h"
+#endif
+
+namespace base {
+
+// This replaces INFINITE from Win32
+static const int kNoTimeout = -1;
+
+class TimeDelta;
+
+// A WaitableEvent can be a useful thread synchronization tool when you want to
+// allow one thread to wait for another thread to finish some work. For
+// non-Windows systems, this can only be used from within a single address
+// space.
+//
+// Use a WaitableEvent when you would otherwise use a Lock+ConditionVariable to
+// protect a simple boolean value. However, if you find yourself using a
+// WaitableEvent in conjunction with a Lock to wait for a more complex state
+// change (e.g., for an item to be added to a queue), then you should probably
+// be using a ConditionVariable instead of a WaitableEvent.
+//
+// NOTE: On Windows, this class provides a subset of the functionality afforded
+// by a Windows event object. This is intentional. If you are writing Windows
+// specific code and you need other features of a Windows event, then you might
+// be better off just using an Windows event directly.
+class BASE_EXPORT WaitableEvent {
+ public:
+ // If manual_reset is true, then to set the event state to non-signaled, a
+ // consumer must call the Reset method. If this parameter is false, then the
+ // system automatically resets the event state to non-signaled after a single
+ // waiting thread has been released.
+ WaitableEvent(bool manual_reset, bool initially_signaled);
+
+#if defined(OS_WIN)
+ // Create a WaitableEvent from an Event HANDLE which has already been
+ // created. This objects takes ownership of the HANDLE and will close it when
+ // deleted.
+ explicit WaitableEvent(HANDLE event_handle);
+
+ // Releases ownership of the handle from this object.
+ HANDLE Release();
+#endif
+
+ ~WaitableEvent();
+
+ // Put the event in the un-signaled state.
+ void Reset();
+
+ // Put the event in the signaled state. Causing any thread blocked on Wait
+ // to be woken up.
+ void Signal();
+
+ // Returns true if the event is in the signaled state, else false. If this
+ // is not a manual reset event, then this test will cause a reset.
+ bool IsSignaled();
+
+ // Wait indefinitely for the event to be signaled. Returns true if the event
+ // was signaled, else false is returned to indicate that waiting failed.
+ bool Wait();
+
+ // Wait up until max_time has passed for the event to be signaled. Returns
+ // true if the event was signaled. If this method returns false, then it
+ // does not necessarily mean that max_time was exceeded.
+ bool TimedWait(const TimeDelta& max_time);
+
+#if defined(OS_WIN)
+ HANDLE handle() const { return handle_; }
+#endif
+
+ // Wait, synchronously, on multiple events.
+ // waitables: an array of WaitableEvent pointers
+ // count: the number of elements in @waitables
+ //
+ // returns: the index of a WaitableEvent which has been signaled.
+ //
+ // You MUST NOT delete any of the WaitableEvent objects while this wait is
+ // happening.
+ static size_t WaitMany(WaitableEvent** waitables, size_t count);
+
+ // For asynchronous waiting, see WaitableEventWatcher
+
+ // This is a private helper class. It's here because it's used by friends of
+ // this class (such as WaitableEventWatcher) to be able to enqueue elements
+ // of the wait-list
+ class Waiter {
+ public:
+ // Signal the waiter to wake up.
+ //
+ // Consider the case of a Waiter which is in multiple WaitableEvent's
+ // wait-lists. Each WaitableEvent is automatic-reset and two of them are
+ // signaled at the same time. Now, each will wake only the first waiter in
+ // the wake-list before resetting. However, if those two waiters happen to
+ // be the same object (as can happen if another thread didn't have a chance
+ // to dequeue the waiter from the other wait-list in time), two auto-resets
+ // will have happened, but only one waiter has been signaled!
+ //
+ // Because of this, a Waiter may "reject" a wake by returning false. In
+ // this case, the auto-reset WaitableEvent shouldn't act as if anything has
+ // been notified.
+ virtual bool Fire(WaitableEvent* signaling_event) = 0;
+
+ // Waiters may implement this in order to provide an extra condition for
+ // two Waiters to be considered equal. In WaitableEvent::Dequeue, if the
+ // pointers match then this function is called as a final check. See the
+ // comments in ~Handle for why.
+ virtual bool Compare(void* tag) = 0;
+
+ protected:
+ virtual ~Waiter() {}
+ };
+
+ private:
+ friend class WaitableEventWatcher;
+
+#if defined(OS_WIN)
+ HANDLE handle_;
+#else
+ // On Windows, one can close a HANDLE which is currently being waited on. The
+ // MSDN documentation says that the resulting behaviour is 'undefined', but
+ // it doesn't crash. However, if we were to include the following members
+ // directly then, on POSIX, one couldn't use WaitableEventWatcher to watch an
+ // event which gets deleted. This mismatch has bitten us several times now,
+ // so we have a kernel of the WaitableEvent, which is reference counted.
+ // WaitableEventWatchers may then take a reference and thus match the Windows
+ // behaviour.
+ struct WaitableEventKernel :
+ public RefCountedThreadSafe<WaitableEventKernel> {
+ public:
+ WaitableEventKernel(bool manual_reset, bool initially_signaled);
+ virtual ~WaitableEventKernel();
+
+ bool Dequeue(Waiter* waiter, void* tag);
+
+ base::Lock lock_;
+ const bool manual_reset_;
+ bool signaled_;
+ std::list<Waiter*> waiters_;
+ };
+
+ typedef std::pair<WaitableEvent*, size_t> WaiterAndIndex;
+
+ // When dealing with arrays of WaitableEvent*, we want to sort by the address
+ // of the WaitableEvent in order to have a globally consistent locking order.
+ // In that case we keep them, in sorted order, in an array of pairs where the
+ // second element is the index of the WaitableEvent in the original,
+ // unsorted, array.
+ static size_t EnqueueMany(WaiterAndIndex* waitables,
+ size_t count, Waiter* waiter);
+
+ bool SignalAll();
+ bool SignalOne();
+ void Enqueue(Waiter* waiter);
+
+ scoped_refptr<WaitableEventKernel> kernel_;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(WaitableEvent);
+};
+
+} // namespace base
+
+#endif // BASE_SYNCHRONIZATION_WAITABLE_EVENT_H_
diff --git a/base/template_util.h b/base/template_util.h
new file mode 100644
index 000000000000..f19fb4b4ee04
--- /dev/null
+++ b/base/template_util.h
@@ -0,0 +1,109 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEMPLATE_UTIL_H_
+#define BASE_TEMPLATE_UTIL_H_
+#pragma once
+
+#include <cstddef> // For size_t.
+
+#include "build/build_config.h"
+
+namespace base {
+
+// template definitions from tr1
+
+template<class T, T v>
+struct integral_constant {
+ static const T value = v;
+ typedef T value_type;
+ typedef integral_constant<T, v> type;
+};
+
+template <class T, T v> const T integral_constant<T, v>::value;
+
+typedef integral_constant<bool, true> true_type;
+typedef integral_constant<bool, false> false_type;
+
+template <class T> struct is_pointer : false_type {};
+template <class T> struct is_pointer<T*> : true_type {};
+
+template <class T, class U> struct is_same : public false_type {};
+template <class T> struct is_same<T,T> : true_type {};
+
+template<class> struct is_array : public false_type {};
+template<class T, size_t n> struct is_array<T[n]> : public true_type {};
+template<class T> struct is_array<T[]> : public true_type {};
+
+template <class T> struct is_non_const_reference : false_type {};
+template <class T> struct is_non_const_reference<T&> : true_type {};
+template <class T> struct is_non_const_reference<const T&> : false_type {};
+
+template <class T> struct is_void : false_type {};
+template <> struct is_void<void> : true_type {};
+
+namespace internal {
+
+// Types YesType and NoType are guaranteed such that sizeof(YesType) <
+// sizeof(NoType).
+typedef char YesType;
+
+struct NoType {
+ YesType dummy[2];
+};
+
+// This class is an implementation detail for is_convertible, and you
+// don't need to know how it works to use is_convertible. For those
+// who care: we declare two different functions, one whose argument is
+// of type To and one with a variadic argument list. We give them
+// return types of different size, so we can use sizeof to trick the
+// compiler into telling us which function it would have chosen if we
+// had called it with an argument of type From. See Alexandrescu's
+// _Modern C++ Design_ for more details on this sort of trick.
+
+struct ConvertHelper {
+ template <typename To>
+ static YesType Test(To);
+
+ template <typename To>
+ static NoType Test(...);
+
+ template <typename From>
+ static From Create();
+};
+
+// Used to determine if a type is a struct/union/class. Inspired by Boost's
+// is_class type_trait implementation.
+struct IsClassHelper {
+ template <typename C>
+ static YesType Test(void(C::*)(void));
+
+ template <typename C>
+ static NoType Test(...);
+};
+
+} // namespace internal
+
+// Inherits from true_type if From is convertible to To, false_type otherwise.
+//
+// Note that if the type is convertible, this will be a true_type REGARDLESS
+// of whether or not the conversion would emit a warning.
+template <typename From, typename To>
+struct is_convertible
+ : integral_constant<bool,
+ sizeof(internal::ConvertHelper::Test<To>(
+ internal::ConvertHelper::Create<From>())) ==
+ sizeof(internal::YesType)> {
+};
+
+template <typename T>
+struct is_class
+ : integral_constant<bool,
+ sizeof(internal::IsClassHelper::Test<T>(0)) ==
+ sizeof(internal::YesType)> {
+};
+
+} // namespace base
+
+#endif // BASE_TEMPLATE_UTIL_H_
diff --git a/base/third_party/dynamic_annotations/LICENSE b/base/third_party/dynamic_annotations/LICENSE
new file mode 100644
index 000000000000..5c581a9391b9
--- /dev/null
+++ b/base/third_party/dynamic_annotations/LICENSE
@@ -0,0 +1,28 @@
+/* Copyright (c) 2008-2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Neither the name of Google Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT
+ * OWNER 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.
+ *
+ * ---
+ * Author: Kostya Serebryany
+ */
diff --git a/base/third_party/dynamic_annotations/README.chromium b/base/third_party/dynamic_annotations/README.chromium
new file mode 100644
index 000000000000..f78a98214386
--- /dev/null
+++ b/base/third_party/dynamic_annotations/README.chromium
@@ -0,0 +1,11 @@
+Name: dynamic annotations
+URL: http://code.google.com/p/data-race-test/wiki/DynamicAnnotations
+
+One header and one source file (dynamic_annotations.h and dynamic_annotations.c)
+in this directory define runtime macros useful for annotating synchronization
+utilities and benign data races so data race detectors can handle Chromium code
+with better precision.
+
+These files were taken from
+http://code.google.com/p/data-race-test/source/browse/?r=2062#svn/trunk/dynamic_annotations
+The files are covered under BSD license as described within the files.
diff --git a/base/third_party/dynamic_annotations/dynamic_annotations.c b/base/third_party/dynamic_annotations/dynamic_annotations.c
new file mode 100644
index 000000000000..e7d44f4a647e
--- /dev/null
+++ b/base/third_party/dynamic_annotations/dynamic_annotations.c
@@ -0,0 +1,257 @@
+/* Copyright (c) 2011, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Neither the name of Google Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT
+ * OWNER 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 _MSC_VER
+# include <windows.h>
+#endif
+
+#ifdef __cplusplus
+# error "This file should be built as pure C to avoid name mangling"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+
+#ifdef __GNUC__
+/* valgrind.h uses gcc extensions so it won't build with other compilers */
+# include "base/third_party/valgrind/valgrind.h"
+#endif
+
+/* Each function is empty and called (via a macro) only in debug mode.
+ The arguments are captured by dynamic tools at runtime. */
+
+#if DYNAMIC_ANNOTATIONS_ENABLED == 1
+
+/* Identical code folding(-Wl,--icf=all) countermeasures.
+ This makes all Annotate* functions different, which prevents the linker from
+ folding them. */
+#ifdef __COUNTER__
+#define DYNAMIC_ANNOTATIONS_IMPL \
+ volatile short lineno = (__LINE__ << 8) + __COUNTER__; (void)lineno;
+#else
+#define DYNAMIC_ANNOTATIONS_IMPL \
+ volatile short lineno = (__LINE__ << 8); (void)lineno;
+#endif
+
+/* WARNING: always add new annotations to the end of the list.
+ Otherwise, lineno (see above) numbers for different Annotate* functions may
+ conflict. */
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockCreate)(
+ const char *file, int line, const volatile void *lock)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockDestroy)(
+ const char *file, int line, const volatile void *lock)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockAcquired)(
+ const char *file, int line, const volatile void *lock, long is_w)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockReleased)(
+ const char *file, int line, const volatile void *lock, long is_w)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierInit)(
+ const char *file, int line, const volatile void *barrier, long count,
+ long reinitialization_allowed)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitBefore)(
+ const char *file, int line, const volatile void *barrier)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitAfter)(
+ const char *file, int line, const volatile void *barrier)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierDestroy)(
+ const char *file, int line, const volatile void *barrier)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarWait)(
+ const char *file, int line, const volatile void *cv,
+ const volatile void *lock)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignal)(
+ const char *file, int line, const volatile void *cv)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignalAll)(
+ const char *file, int line, const volatile void *cv)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateHappensBefore)(
+ const char *file, int line, const volatile void *obj)
+{DYNAMIC_ANNOTATIONS_IMPL};
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateHappensAfter)(
+ const char *file, int line, const volatile void *obj)
+{DYNAMIC_ANNOTATIONS_IMPL};
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePublishMemoryRange)(
+ const char *file, int line, const volatile void *address, long size)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateUnpublishMemoryRange)(
+ const char *file, int line, const volatile void *address, long size)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQCreate)(
+ const char *file, int line, const volatile void *pcq)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQDestroy)(
+ const char *file, int line, const volatile void *pcq)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQPut)(
+ const char *file, int line, const volatile void *pcq)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQGet)(
+ const char *file, int line, const volatile void *pcq)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateNewMemory)(
+ const char *file, int line, const volatile void *mem, long size)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateExpectRace)(
+ const char *file, int line, const volatile void *mem,
+ const char *description)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushExpectedRaces)(
+ const char *file, int line)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRace)(
+ const char *file, int line, const volatile void *mem,
+ const char *description)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRaceSized)(
+ const char *file, int line, const volatile void *mem, long size,
+ const char *description)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsUsedAsCondVar)(
+ const char *file, int line, const volatile void *mu)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsNotPHB)(
+ const char *file, int line, const volatile void *mu)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateTraceMemory)(
+ const char *file, int line, const volatile void *arg)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateThreadName)(
+ const char *file, int line, const char *name)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsBegin)(
+ const char *file, int line)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsEnd)(
+ const char *file, int line)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesBegin)(
+ const char *file, int line)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesEnd)(
+ const char *file, int line)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncBegin)(
+ const char *file, int line)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncEnd)(
+ const char *file, int line)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateEnableRaceDetection)(
+ const char *file, int line, int enable)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateNoOp)(
+ const char *file, int line, const volatile void *arg)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushState)(
+ const char *file, int line)
+{DYNAMIC_ANNOTATIONS_IMPL}
+
+#endif /* DYNAMIC_ANNOTATIONS_ENABLED == 1 */
+
+#if DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND == 1
+static int GetRunningOnValgrind(void) {
+#ifdef RUNNING_ON_VALGRIND
+ if (RUNNING_ON_VALGRIND) return 1;
+#endif
+
+#ifndef _MSC_VER
+ char *running_on_valgrind_str = getenv("RUNNING_ON_VALGRIND");
+ if (running_on_valgrind_str) {
+ return strcmp(running_on_valgrind_str, "0") != 0;
+ }
+#else
+ /* Visual Studio issues warnings if we use getenv,
+ * so we use GetEnvironmentVariableA instead.
+ */
+ char value[100] = "1";
+ int res = GetEnvironmentVariableA("RUNNING_ON_VALGRIND",
+ value, sizeof(value));
+ /* value will remain "1" if res == 0 or res >= sizeof(value). The latter
+ * can happen only if the given value is long, in this case it can't be "0".
+ */
+ if (res > 0 && strcmp(value, "0") != 0)
+ return 1;
+#endif
+ return 0;
+}
+
+/* See the comments in dynamic_annotations.h */
+int RunningOnValgrind(void) {
+ static volatile int running_on_valgrind = -1;
+ /* C doesn't have thread-safe initialization of statics, and we
+ don't want to depend on pthread_once here, so hack it. */
+ int local_running_on_valgrind = running_on_valgrind;
+ if (local_running_on_valgrind == -1)
+ running_on_valgrind = local_running_on_valgrind = GetRunningOnValgrind();
+ return local_running_on_valgrind;
+}
+
+#endif /* DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND == 1 */
diff --git a/base/third_party/dynamic_annotations/dynamic_annotations.gyp b/base/third_party/dynamic_annotations/dynamic_annotations.gyp
new file mode 100644
index 000000000000..47334d88360a
--- /dev/null
+++ b/base/third_party/dynamic_annotations/dynamic_annotations.gyp
@@ -0,0 +1,45 @@
+# Copyright (c) 2010 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'dynamic_annotations',
+ 'type': 'static_library',
+ 'include_dirs': [
+ '../../../',
+ ],
+ 'sources': [
+ 'dynamic_annotations.c',
+ 'dynamic_annotations.h',
+ ],
+ },
+ ],
+ 'conditions': [
+ ['OS == "win"', {
+ 'targets': [
+ {
+ 'target_name': 'dynamic_annotations_win64',
+ 'type': 'static_library',
+ # We can't use dynamic_annotations target for win64 build since it is
+ # a 32-bit library.
+ # TODO(gregoryd): merge with dynamic_annotations when
+ # the win32/64 targets are merged.
+ 'include_dirs': [
+ '../../../',
+ ],
+ 'sources': [
+ 'dynamic_annotations.c',
+ 'dynamic_annotations.h',
+ ],
+ 'configurations': {
+ 'Common_Base': {
+ 'msvs_target_platform': 'x64',
+ },
+ },
+ },
+ ],
+ }],
+ ],
+}
diff --git a/base/third_party/dynamic_annotations/dynamic_annotations.h b/base/third_party/dynamic_annotations/dynamic_annotations.h
new file mode 100644
index 000000000000..8d7f05202b70
--- /dev/null
+++ b/base/third_party/dynamic_annotations/dynamic_annotations.h
@@ -0,0 +1,595 @@
+/* Copyright (c) 2011, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Neither the name of Google Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT
+ * OWNER 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.
+ */
+
+/* This file defines dynamic annotations for use with dynamic analysis
+ tool such as valgrind, PIN, etc.
+
+ Dynamic annotation is a source code annotation that affects
+ the generated code (that is, the annotation is not a comment).
+ Each such annotation is attached to a particular
+ instruction and/or to a particular object (address) in the program.
+
+ The annotations that should be used by users are macros in all upper-case
+ (e.g., ANNOTATE_NEW_MEMORY).
+
+ Actual implementation of these macros may differ depending on the
+ dynamic analysis tool being used.
+
+ See http://code.google.com/p/data-race-test/ for more information.
+
+ This file supports the following dynamic analysis tools:
+ - None (DYNAMIC_ANNOTATIONS_ENABLED is not defined or zero).
+ Macros are defined empty.
+ - ThreadSanitizer, Helgrind, DRD (DYNAMIC_ANNOTATIONS_ENABLED is 1).
+ Macros are defined as calls to non-inlinable empty functions
+ that are intercepted by Valgrind. */
+
+#ifndef __DYNAMIC_ANNOTATIONS_H__
+#define __DYNAMIC_ANNOTATIONS_H__
+
+#ifndef DYNAMIC_ANNOTATIONS_PREFIX
+# define DYNAMIC_ANNOTATIONS_PREFIX
+#endif
+
+#ifndef DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND
+# define DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND 1
+#endif
+
+#ifdef DYNAMIC_ANNOTATIONS_WANT_ATTRIBUTE_WEAK
+# ifdef __GNUC__
+# define DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK __attribute__((weak))
+# else
+/* TODO(glider): for Windows support we may want to change this macro in order
+ to prepend __declspec(selectany) to the annotations' declarations. */
+# error weak annotations are not supported for your compiler
+# endif
+#else
+# define DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK
+#endif
+
+/* The following preprocessor magic prepends the value of
+ DYNAMIC_ANNOTATIONS_PREFIX to annotation function names. */
+#define DYNAMIC_ANNOTATIONS_GLUE0(A, B) A##B
+#define DYNAMIC_ANNOTATIONS_GLUE(A, B) DYNAMIC_ANNOTATIONS_GLUE0(A, B)
+#define DYNAMIC_ANNOTATIONS_NAME(name) \
+ DYNAMIC_ANNOTATIONS_GLUE(DYNAMIC_ANNOTATIONS_PREFIX, name)
+
+#ifndef DYNAMIC_ANNOTATIONS_ENABLED
+# define DYNAMIC_ANNOTATIONS_ENABLED 0
+#endif
+
+#if DYNAMIC_ANNOTATIONS_ENABLED != 0
+
+ /* -------------------------------------------------------------
+ Annotations useful when implementing condition variables such as CondVar,
+ using conditional critical sections (Await/LockWhen) and when constructing
+ user-defined synchronization mechanisms.
+
+ The annotations ANNOTATE_HAPPENS_BEFORE() and ANNOTATE_HAPPENS_AFTER() can
+ be used to define happens-before arcs in user-defined synchronization
+ mechanisms: the race detector will infer an arc from the former to the
+ latter when they share the same argument pointer.
+
+ Example 1 (reference counting):
+
+ void Unref() {
+ ANNOTATE_HAPPENS_BEFORE(&refcount_);
+ if (AtomicDecrementByOne(&refcount_) == 0) {
+ ANNOTATE_HAPPENS_AFTER(&refcount_);
+ delete this;
+ }
+ }
+
+ Example 2 (message queue):
+
+ void MyQueue::Put(Type *e) {
+ MutexLock lock(&mu_);
+ ANNOTATE_HAPPENS_BEFORE(e);
+ PutElementIntoMyQueue(e);
+ }
+
+ Type *MyQueue::Get() {
+ MutexLock lock(&mu_);
+ Type *e = GetElementFromMyQueue();
+ ANNOTATE_HAPPENS_AFTER(e);
+ return e;
+ }
+
+ Note: when possible, please use the existing reference counting and message
+ queue implementations instead of inventing new ones. */
+
+ /* Report that wait on the condition variable at address "cv" has succeeded
+ and the lock at address "lock" is held. */
+ #define ANNOTATE_CONDVAR_LOCK_WAIT(cv, lock) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarWait)(__FILE__, __LINE__, cv, lock)
+
+ /* Report that wait on the condition variable at "cv" has succeeded. Variant
+ w/o lock. */
+ #define ANNOTATE_CONDVAR_WAIT(cv) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarWait)(__FILE__, __LINE__, cv, NULL)
+
+ /* Report that we are about to signal on the condition variable at address
+ "cv". */
+ #define ANNOTATE_CONDVAR_SIGNAL(cv) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignal)(__FILE__, __LINE__, cv)
+
+ /* Report that we are about to signal_all on the condition variable at address
+ "cv". */
+ #define ANNOTATE_CONDVAR_SIGNAL_ALL(cv) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignalAll)(__FILE__, __LINE__, cv)
+
+ /* Annotations for user-defined synchronization mechanisms. */
+ #define ANNOTATE_HAPPENS_BEFORE(obj) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateHappensBefore)(__FILE__, __LINE__, obj)
+ #define ANNOTATE_HAPPENS_AFTER(obj) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateHappensAfter)(__FILE__, __LINE__, obj)
+
+ /* DEPRECATED. Don't use it. */
+ #define ANNOTATE_PUBLISH_MEMORY_RANGE(pointer, size) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotatePublishMemoryRange)(__FILE__, __LINE__, \
+ pointer, size)
+
+ /* DEPRECATED. Don't use it. */
+ #define ANNOTATE_UNPUBLISH_MEMORY_RANGE(pointer, size) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateUnpublishMemoryRange)(__FILE__, __LINE__, \
+ pointer, size)
+
+ /* DEPRECATED. Don't use it. */
+ #define ANNOTATE_SWAP_MEMORY_RANGE(pointer, size) \
+ do { \
+ ANNOTATE_UNPUBLISH_MEMORY_RANGE(pointer, size); \
+ ANNOTATE_PUBLISH_MEMORY_RANGE(pointer, size); \
+ } while (0)
+
+ /* Instruct the tool to create a happens-before arc between mu->Unlock() and
+ mu->Lock(). This annotation may slow down the race detector and hide real
+ races. Normally it is used only when it would be difficult to annotate each
+ of the mutex's critical sections individually using the annotations above.
+ This annotation makes sense only for hybrid race detectors. For pure
+ happens-before detectors this is a no-op. For more details see
+ http://code.google.com/p/data-race-test/wiki/PureHappensBeforeVsHybrid . */
+ #define ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(mu) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsUsedAsCondVar)(__FILE__, __LINE__, \
+ mu)
+
+ /* Opposite to ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX.
+ Instruct the tool to NOT create h-b arcs between Unlock and Lock, even in
+ pure happens-before mode. For a hybrid mode this is a no-op. */
+ #define ANNOTATE_NOT_HAPPENS_BEFORE_MUTEX(mu) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsNotPHB)(__FILE__, __LINE__, mu)
+
+ /* Deprecated. Use ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX. */
+ #define ANNOTATE_MUTEX_IS_USED_AS_CONDVAR(mu) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsUsedAsCondVar)(__FILE__, __LINE__, \
+ mu)
+
+ /* -------------------------------------------------------------
+ Annotations useful when defining memory allocators, or when memory that
+ was protected in one way starts to be protected in another. */
+
+ /* Report that a new memory at "address" of size "size" has been allocated.
+ This might be used when the memory has been retrieved from a free list and
+ is about to be reused, or when a the locking discipline for a variable
+ changes. */
+ #define ANNOTATE_NEW_MEMORY(address, size) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateNewMemory)(__FILE__, __LINE__, address, \
+ size)
+
+ /* -------------------------------------------------------------
+ Annotations useful when defining FIFO queues that transfer data between
+ threads. */
+
+ /* Report that the producer-consumer queue (such as ProducerConsumerQueue) at
+ address "pcq" has been created. The ANNOTATE_PCQ_* annotations
+ should be used only for FIFO queues. For non-FIFO queues use
+ ANNOTATE_HAPPENS_BEFORE (for put) and ANNOTATE_HAPPENS_AFTER (for get). */
+ #define ANNOTATE_PCQ_CREATE(pcq) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQCreate)(__FILE__, __LINE__, pcq)
+
+ /* Report that the queue at address "pcq" is about to be destroyed. */
+ #define ANNOTATE_PCQ_DESTROY(pcq) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQDestroy)(__FILE__, __LINE__, pcq)
+
+ /* Report that we are about to put an element into a FIFO queue at address
+ "pcq". */
+ #define ANNOTATE_PCQ_PUT(pcq) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQPut)(__FILE__, __LINE__, pcq)
+
+ /* Report that we've just got an element from a FIFO queue at address
+ "pcq". */
+ #define ANNOTATE_PCQ_GET(pcq) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQGet)(__FILE__, __LINE__, pcq)
+
+ /* -------------------------------------------------------------
+ Annotations that suppress errors. It is usually better to express the
+ program's synchronization using the other annotations, but these can
+ be used when all else fails. */
+
+ /* Report that we may have a benign race at "pointer", with size
+ "sizeof(*(pointer))". "pointer" must be a non-void* pointer. Insert at the
+ point where "pointer" has been allocated, preferably close to the point
+ where the race happens. See also ANNOTATE_BENIGN_RACE_STATIC. */
+ #define ANNOTATE_BENIGN_RACE(pointer, description) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRaceSized)(__FILE__, __LINE__, \
+ pointer, sizeof(*(pointer)), description)
+
+ /* Same as ANNOTATE_BENIGN_RACE(address, description), but applies to
+ the memory range [address, address+size). */
+ #define ANNOTATE_BENIGN_RACE_SIZED(address, size, description) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRaceSized)(__FILE__, __LINE__, \
+ address, size, description)
+
+ /* Request the analysis tool to ignore all reads in the current thread
+ until ANNOTATE_IGNORE_READS_END is called.
+ Useful to ignore intentional racey reads, while still checking
+ other reads and all writes.
+ See also ANNOTATE_UNPROTECTED_READ. */
+ #define ANNOTATE_IGNORE_READS_BEGIN() \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsBegin)(__FILE__, __LINE__)
+
+ /* Stop ignoring reads. */
+ #define ANNOTATE_IGNORE_READS_END() \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsEnd)(__FILE__, __LINE__)
+
+ /* Similar to ANNOTATE_IGNORE_READS_BEGIN, but ignore writes. */
+ #define ANNOTATE_IGNORE_WRITES_BEGIN() \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesBegin)(__FILE__, __LINE__)
+
+ /* Stop ignoring writes. */
+ #define ANNOTATE_IGNORE_WRITES_END() \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesEnd)(__FILE__, __LINE__)
+
+ /* Start ignoring all memory accesses (reads and writes). */
+ #define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() \
+ do {\
+ ANNOTATE_IGNORE_READS_BEGIN();\
+ ANNOTATE_IGNORE_WRITES_BEGIN();\
+ }while(0)\
+
+ /* Stop ignoring all memory accesses. */
+ #define ANNOTATE_IGNORE_READS_AND_WRITES_END() \
+ do {\
+ ANNOTATE_IGNORE_WRITES_END();\
+ ANNOTATE_IGNORE_READS_END();\
+ }while(0)\
+
+ /* Similar to ANNOTATE_IGNORE_READS_BEGIN, but ignore synchronization events:
+ RWLOCK* and CONDVAR*. */
+ #define ANNOTATE_IGNORE_SYNC_BEGIN() \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncBegin)(__FILE__, __LINE__)
+
+ /* Stop ignoring sync events. */
+ #define ANNOTATE_IGNORE_SYNC_END() \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncEnd)(__FILE__, __LINE__)
+
+
+ /* Enable (enable!=0) or disable (enable==0) race detection for all threads.
+ This annotation could be useful if you want to skip expensive race analysis
+ during some period of program execution, e.g. during initialization. */
+ #define ANNOTATE_ENABLE_RACE_DETECTION(enable) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateEnableRaceDetection)(__FILE__, __LINE__, \
+ enable)
+
+ /* -------------------------------------------------------------
+ Annotations useful for debugging. */
+
+ /* Request to trace every access to "address". */
+ #define ANNOTATE_TRACE_MEMORY(address) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateTraceMemory)(__FILE__, __LINE__, address)
+
+ /* Report the current thread name to a race detector. */
+ #define ANNOTATE_THREAD_NAME(name) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateThreadName)(__FILE__, __LINE__, name)
+
+ /* -------------------------------------------------------------
+ Annotations useful when implementing locks. They are not
+ normally needed by modules that merely use locks.
+ The "lock" argument is a pointer to the lock object. */
+
+ /* Report that a lock has been created at address "lock". */
+ #define ANNOTATE_RWLOCK_CREATE(lock) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockCreate)(__FILE__, __LINE__, lock)
+
+ /* Report that the lock at address "lock" is about to be destroyed. */
+ #define ANNOTATE_RWLOCK_DESTROY(lock) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockDestroy)(__FILE__, __LINE__, lock)
+
+ /* Report that the lock at address "lock" has been acquired.
+ is_w=1 for writer lock, is_w=0 for reader lock. */
+ #define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockAcquired)(__FILE__, __LINE__, lock, \
+ is_w)
+
+ /* Report that the lock at address "lock" is about to be released. */
+ #define ANNOTATE_RWLOCK_RELEASED(lock, is_w) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockReleased)(__FILE__, __LINE__, lock, \
+ is_w)
+
+ /* -------------------------------------------------------------
+ Annotations useful when implementing barriers. They are not
+ normally needed by modules that merely use barriers.
+ The "barrier" argument is a pointer to the barrier object. */
+
+ /* Report that the "barrier" has been initialized with initial "count".
+ If 'reinitialization_allowed' is true, initialization is allowed to happen
+ multiple times w/o calling barrier_destroy() */
+ #define ANNOTATE_BARRIER_INIT(barrier, count, reinitialization_allowed) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierInit)(__FILE__, __LINE__, barrier, \
+ count, reinitialization_allowed)
+
+ /* Report that we are about to enter barrier_wait("barrier"). */
+ #define ANNOTATE_BARRIER_WAIT_BEFORE(barrier) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitBefore)(__FILE__, __LINE__, \
+ barrier)
+
+ /* Report that we just exited barrier_wait("barrier"). */
+ #define ANNOTATE_BARRIER_WAIT_AFTER(barrier) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitAfter)(__FILE__, __LINE__, \
+ barrier)
+
+ /* Report that the "barrier" has been destroyed. */
+ #define ANNOTATE_BARRIER_DESTROY(barrier) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierDestroy)(__FILE__, __LINE__, \
+ barrier)
+
+ /* -------------------------------------------------------------
+ Annotations useful for testing race detectors. */
+
+ /* Report that we expect a race on the variable at "address".
+ Use only in unit tests for a race detector. */
+ #define ANNOTATE_EXPECT_RACE(address, description) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateExpectRace)(__FILE__, __LINE__, address, \
+ description)
+
+ #define ANNOTATE_FLUSH_EXPECTED_RACES() \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushExpectedRaces)(__FILE__, __LINE__)
+
+ /* A no-op. Insert where you like to test the interceptors. */
+ #define ANNOTATE_NO_OP(arg) \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateNoOp)(__FILE__, __LINE__, arg)
+
+ /* Force the race detector to flush its state. The actual effect depends on
+ * the implementation of the detector. */
+ #define ANNOTATE_FLUSH_STATE() \
+ DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushState)(__FILE__, __LINE__)
+
+
+#else /* DYNAMIC_ANNOTATIONS_ENABLED == 0 */
+
+ #define ANNOTATE_RWLOCK_CREATE(lock) /* empty */
+ #define ANNOTATE_RWLOCK_DESTROY(lock) /* empty */
+ #define ANNOTATE_RWLOCK_ACQUIRED(lock, is_w) /* empty */
+ #define ANNOTATE_RWLOCK_RELEASED(lock, is_w) /* empty */
+ #define ANNOTATE_BARRIER_INIT(barrier, count, reinitialization_allowed) /* */
+ #define ANNOTATE_BARRIER_WAIT_BEFORE(barrier) /* empty */
+ #define ANNOTATE_BARRIER_WAIT_AFTER(barrier) /* empty */
+ #define ANNOTATE_BARRIER_DESTROY(barrier) /* empty */
+ #define ANNOTATE_CONDVAR_LOCK_WAIT(cv, lock) /* empty */
+ #define ANNOTATE_CONDVAR_WAIT(cv) /* empty */
+ #define ANNOTATE_CONDVAR_SIGNAL(cv) /* empty */
+ #define ANNOTATE_CONDVAR_SIGNAL_ALL(cv) /* empty */
+ #define ANNOTATE_HAPPENS_BEFORE(obj) /* empty */
+ #define ANNOTATE_HAPPENS_AFTER(obj) /* empty */
+ #define ANNOTATE_PUBLISH_MEMORY_RANGE(address, size) /* empty */
+ #define ANNOTATE_UNPUBLISH_MEMORY_RANGE(address, size) /* empty */
+ #define ANNOTATE_SWAP_MEMORY_RANGE(address, size) /* empty */
+ #define ANNOTATE_PCQ_CREATE(pcq) /* empty */
+ #define ANNOTATE_PCQ_DESTROY(pcq) /* empty */
+ #define ANNOTATE_PCQ_PUT(pcq) /* empty */
+ #define ANNOTATE_PCQ_GET(pcq) /* empty */
+ #define ANNOTATE_NEW_MEMORY(address, size) /* empty */
+ #define ANNOTATE_EXPECT_RACE(address, description) /* empty */
+ #define ANNOTATE_FLUSH_EXPECTED_RACES(address, description) /* empty */
+ #define ANNOTATE_BENIGN_RACE(address, description) /* empty */
+ #define ANNOTATE_BENIGN_RACE_SIZED(address, size, description) /* empty */
+ #define ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(mu) /* empty */
+ #define ANNOTATE_MUTEX_IS_USED_AS_CONDVAR(mu) /* empty */
+ #define ANNOTATE_TRACE_MEMORY(arg) /* empty */
+ #define ANNOTATE_THREAD_NAME(name) /* empty */
+ #define ANNOTATE_IGNORE_READS_BEGIN() /* empty */
+ #define ANNOTATE_IGNORE_READS_END() /* empty */
+ #define ANNOTATE_IGNORE_WRITES_BEGIN() /* empty */
+ #define ANNOTATE_IGNORE_WRITES_END() /* empty */
+ #define ANNOTATE_IGNORE_READS_AND_WRITES_BEGIN() /* empty */
+ #define ANNOTATE_IGNORE_READS_AND_WRITES_END() /* empty */
+ #define ANNOTATE_IGNORE_SYNC_BEGIN() /* empty */
+ #define ANNOTATE_IGNORE_SYNC_END() /* empty */
+ #define ANNOTATE_ENABLE_RACE_DETECTION(enable) /* empty */
+ #define ANNOTATE_NO_OP(arg) /* empty */
+ #define ANNOTATE_FLUSH_STATE() /* empty */
+
+#endif /* DYNAMIC_ANNOTATIONS_ENABLED */
+
+/* Use the macros above rather than using these functions directly. */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockCreate)(
+ const char *file, int line,
+ const volatile void *lock) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockDestroy)(
+ const char *file, int line,
+ const volatile void *lock) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockAcquired)(
+ const char *file, int line,
+ const volatile void *lock, long is_w) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateRWLockReleased)(
+ const char *file, int line,
+ const volatile void *lock, long is_w) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierInit)(
+ const char *file, int line, const volatile void *barrier, long count,
+ long reinitialization_allowed) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitBefore)(
+ const char *file, int line,
+ const volatile void *barrier) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierWaitAfter)(
+ const char *file, int line,
+ const volatile void *barrier) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBarrierDestroy)(
+ const char *file, int line,
+ const volatile void *barrier) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarWait)(
+ const char *file, int line, const volatile void *cv,
+ const volatile void *lock) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignal)(
+ const char *file, int line,
+ const volatile void *cv) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateCondVarSignalAll)(
+ const char *file, int line,
+ const volatile void *cv) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateHappensBefore)(
+ const char *file, int line,
+ const volatile void *obj) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateHappensAfter)(
+ const char *file, int line,
+ const volatile void *obj) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePublishMemoryRange)(
+ const char *file, int line,
+ const volatile void *address, long size) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateUnpublishMemoryRange)(
+ const char *file, int line,
+ const volatile void *address, long size) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQCreate)(
+ const char *file, int line,
+ const volatile void *pcq) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQDestroy)(
+ const char *file, int line,
+ const volatile void *pcq) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQPut)(
+ const char *file, int line,
+ const volatile void *pcq) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotatePCQGet)(
+ const char *file, int line,
+ const volatile void *pcq) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateNewMemory)(
+ const char *file, int line,
+ const volatile void *mem, long size) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateExpectRace)(
+ const char *file, int line, const volatile void *mem,
+ const char *description) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushExpectedRaces)(
+ const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRace)(
+ const char *file, int line, const volatile void *mem,
+ const char *description) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateBenignRaceSized)(
+ const char *file, int line, const volatile void *mem, long size,
+ const char *description) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsUsedAsCondVar)(
+ const char *file, int line,
+ const volatile void *mu) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateMutexIsNotPHB)(
+ const char *file, int line,
+ const volatile void *mu) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateTraceMemory)(
+ const char *file, int line,
+ const volatile void *arg) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateThreadName)(
+ const char *file, int line,
+ const char *name) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsBegin)(
+ const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreReadsEnd)(
+ const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesBegin)(
+ const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreWritesEnd)(
+ const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncBegin)(
+ const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateIgnoreSyncEnd)(
+ const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateEnableRaceDetection)(
+ const char *file, int line, int enable) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateNoOp)(
+ const char *file, int line,
+ const volatile void *arg) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+void DYNAMIC_ANNOTATIONS_NAME(AnnotateFlushState)(
+ const char *file, int line) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+
+#if DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND == 1
+/* Return non-zero value if running under valgrind.
+
+ If "valgrind.h" is included into dynamic_annotations.c,
+ the regular valgrind mechanism will be used.
+ See http://valgrind.org/docs/manual/manual-core-adv.html about
+ RUNNING_ON_VALGRIND and other valgrind "client requests".
+ The file "valgrind.h" may be obtained by doing
+ svn co svn://svn.valgrind.org/valgrind/trunk/include
+
+ If for some reason you can't use "valgrind.h" or want to fake valgrind,
+ there are two ways to make this function return non-zero:
+ - Use environment variable: export RUNNING_ON_VALGRIND=1
+ - Make your tool intercept the function RunningOnValgrind() and
+ change its return value.
+ */
+int RunningOnValgrind(void) DYNAMIC_ANNOTATIONS_ATTRIBUTE_WEAK;
+#endif /* DYNAMIC_ANNOTATIONS_PROVIDE_RUNNING_ON_VALGRIND == 1 */
+
+#ifdef __cplusplus
+}
+#endif
+
+#if DYNAMIC_ANNOTATIONS_ENABLED != 0 && defined(__cplusplus)
+
+ /* ANNOTATE_UNPROTECTED_READ is the preferred way to annotate racey reads.
+
+ Instead of doing
+ ANNOTATE_IGNORE_READS_BEGIN();
+ ... = x;
+ ANNOTATE_IGNORE_READS_END();
+ one can use
+ ... = ANNOTATE_UNPROTECTED_READ(x); */
+ template <class T>
+ inline T ANNOTATE_UNPROTECTED_READ(const volatile T &x) {
+ ANNOTATE_IGNORE_READS_BEGIN();
+ T res = x;
+ ANNOTATE_IGNORE_READS_END();
+ return res;
+ }
+ /* Apply ANNOTATE_BENIGN_RACE_SIZED to a static variable. */
+ #define ANNOTATE_BENIGN_RACE_STATIC(static_var, description) \
+ namespace { \
+ class static_var ## _annotator { \
+ public: \
+ static_var ## _annotator() { \
+ ANNOTATE_BENIGN_RACE_SIZED(&static_var, \
+ sizeof(static_var), \
+ # static_var ": " description); \
+ } \
+ }; \
+ static static_var ## _annotator the ## static_var ## _annotator;\
+ }
+#else /* DYNAMIC_ANNOTATIONS_ENABLED == 0 */
+
+ #define ANNOTATE_UNPROTECTED_READ(x) (x)
+ #define ANNOTATE_BENIGN_RACE_STATIC(static_var, description) /* empty */
+
+#endif /* DYNAMIC_ANNOTATIONS_ENABLED */
+
+#endif /* __DYNAMIC_ANNOTATIONS_H__ */
diff --git a/base/threading/platform_thread.h b/base/threading/platform_thread.h
new file mode 100644
index 000000000000..8382bbeb0179
--- /dev/null
+++ b/base/threading/platform_thread.h
@@ -0,0 +1,115 @@
+// 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.
+
+// WARNING: You should *NOT* be using this class directly. PlatformThread is
+// the low-level platform-specific abstraction to the OS's threading interface.
+// You should instead be using a message-loop driven Thread, see thread.h.
+
+#ifndef BASE_THREADING_PLATFORM_THREAD_H_
+#define BASE_THREADING_PLATFORM_THREAD_H_
+#pragma once
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#elif defined(OS_POSIX)
+#include <pthread.h>
+#if defined(OS_MACOSX)
+#include <mach/mach.h>
+#else // OS_POSIX && !OS_MACOSX
+#include <unistd.h>
+#endif
+#endif
+
+namespace base {
+
+// PlatformThreadHandle should not be assumed to be a numeric type, since the
+// standard intends to allow pthread_t to be a structure. This means you
+// should not initialize it to a value, like 0. If it's a member variable, the
+// constructor can safely "value initialize" using () in the initializer list.
+#if defined(OS_WIN)
+typedef DWORD PlatformThreadId;
+typedef void* PlatformThreadHandle; // HANDLE
+const PlatformThreadHandle kNullThreadHandle = NULL;
+#elif defined(OS_POSIX)
+typedef pthread_t PlatformThreadHandle;
+const PlatformThreadHandle kNullThreadHandle = 0;
+#if defined(OS_MACOSX)
+typedef mach_port_t PlatformThreadId;
+#else // OS_POSIX && !OS_MACOSX
+typedef pid_t PlatformThreadId;
+#endif
+#endif
+
+const PlatformThreadId kInvalidThreadId = 0;
+
+// Valid values for SetThreadPriority()
+enum ThreadPriority{
+ kThreadPriority_Normal,
+ // Suitable for low-latency, glitch-resistant audio.
+ kThreadPriority_RealtimeAudio
+};
+
+// A namespace for low-level thread functions.
+class BASE_EXPORT PlatformThread {
+ public:
+ // Implement this interface to run code on a background thread. Your
+ // ThreadMain method will be called on the newly created thread.
+ class BASE_EXPORT Delegate {
+ public:
+ virtual ~Delegate() {}
+ virtual void ThreadMain() = 0;
+ };
+
+ // Gets the current thread id, which may be useful for logging purposes.
+ static PlatformThreadId CurrentId();
+
+ // Yield the current thread so another thread can be scheduled.
+ static void YieldCurrentThread();
+
+ // Sleeps for the specified duration (units are milliseconds).
+ static void Sleep(int duration_ms);
+
+ // Sets the thread name visible to debuggers/tools. This has no effect
+ // otherwise. This name pointer is not copied internally. Thus, it must stay
+ // valid until the thread ends.
+ static void SetName(const char* name);
+
+ // Gets the thread name, if previously set by SetName.
+ static const char* GetName();
+
+ // Creates a new thread. The |stack_size| parameter can be 0 to indicate
+ // that the default stack size should be used. Upon success,
+ // |*thread_handle| will be assigned a handle to the newly created thread,
+ // and |delegate|'s ThreadMain method will be executed on the newly created
+ // thread.
+ // NOTE: When you are done with the thread handle, you must call Join to
+ // release system resources associated with the thread. You must ensure that
+ // the Delegate object outlives the thread.
+ static bool Create(size_t stack_size, Delegate* delegate,
+ PlatformThreadHandle* thread_handle);
+
+ // CreateNonJoinable() does the same thing as Create() except the thread
+ // cannot be Join()'d. Therefore, it also does not output a
+ // PlatformThreadHandle.
+ static bool CreateNonJoinable(size_t stack_size, Delegate* delegate);
+
+ // Joins with a thread created via the Create function. This function blocks
+ // the caller until the designated thread exits. This will invalidate
+ // |thread_handle|.
+ static void Join(PlatformThreadHandle thread_handle);
+
+ static void SetThreadPriority(PlatformThreadHandle handle,
+ ThreadPriority priority);
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(PlatformThread);
+};
+
+} // namespace base
+
+#endif // BASE_THREADING_PLATFORM_THREAD_H_
diff --git a/base/threading/platform_thread_posix.cc b/base/threading/platform_thread_posix.cc
new file mode 100644
index 000000000000..c924a16d384c
--- /dev/null
+++ b/base/threading/platform_thread_posix.cc
@@ -0,0 +1,262 @@
+// 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/threading/platform_thread.h"
+
+#include <errno.h>
+#include <sched.h>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/safe_strerror_posix.h"
+#include "base/threading/thread_local.h"
+#include "base/threading/thread_restrictions.h"
+
+#if defined(OS_MACOSX)
+#include <mach/mach.h>
+#include <sys/resource.h>
+#include <algorithm>
+#endif
+
+#if defined(OS_LINUX)
+#include <dlfcn.h>
+#include <sys/prctl.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+#endif
+
+#if defined(OS_ANDROID)
+#include "base/android/jni_android.h"
+#endif
+
+#if defined(OS_NACL)
+#include <sys/nacl_syscalls.h>
+#endif
+
+namespace base {
+
+#if defined(OS_MACOSX)
+void InitThreading();
+#endif
+
+namespace {
+
+static ThreadLocalPointer<char> current_thread_name;
+
+struct ThreadParams {
+ PlatformThread::Delegate* delegate;
+ bool joinable;
+};
+
+void* ThreadFunc(void* params) {
+ ThreadParams* thread_params = static_cast<ThreadParams*>(params);
+ PlatformThread::Delegate* delegate = thread_params->delegate;
+ if (!thread_params->joinable)
+ base::ThreadRestrictions::SetSingletonAllowed(false);
+ delete thread_params;
+ delegate->ThreadMain();
+#if defined(OS_ANDROID)
+ base::android::DetachFromVM();
+#endif
+ return NULL;
+}
+
+bool CreateThread(size_t stack_size, bool joinable,
+ PlatformThread::Delegate* delegate,
+ PlatformThreadHandle* thread_handle) {
+#if defined(OS_MACOSX)
+ base::InitThreading();
+#endif // OS_MACOSX
+
+ bool success = false;
+ pthread_attr_t attributes;
+ pthread_attr_init(&attributes);
+
+ // Pthreads are joinable by default, so only specify the detached attribute if
+ // the thread should be non-joinable.
+ if (!joinable) {
+ pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED);
+ }
+
+#if defined(OS_MACOSX)
+ // The Mac OS X default for a pthread stack size is 512kB.
+ // Libc-594.1.4/pthreads/pthread.c's pthread_attr_init uses
+ // DEFAULT_STACK_SIZE for this purpose.
+ //
+ // 512kB isn't quite generous enough for some deeply recursive threads that
+ // otherwise request the default stack size by specifying 0. Here, adopt
+ // glibc's behavior as on Linux, which is to use the current stack size
+ // limit (ulimit -s) as the default stack size. See
+ // glibc-2.11.1/nptl/nptl-init.c's __pthread_initialize_minimal_internal. To
+ // avoid setting the limit below the Mac OS X default or the minimum usable
+ // stack size, these values are also considered. If any of these values
+ // can't be determined, or if stack size is unlimited (ulimit -s unlimited),
+ // stack_size is left at 0 to get the system default.
+ //
+ // Mac OS X normally only applies ulimit -s to the main thread stack. On
+ // contemporary OS X and Linux systems alike, this value is generally 8MB
+ // or in that neighborhood.
+ if (stack_size == 0) {
+ size_t default_stack_size;
+ struct rlimit stack_rlimit;
+ if (pthread_attr_getstacksize(&attributes, &default_stack_size) == 0 &&
+ getrlimit(RLIMIT_STACK, &stack_rlimit) == 0 &&
+ stack_rlimit.rlim_cur != RLIM_INFINITY) {
+ stack_size = std::max(std::max(default_stack_size,
+ static_cast<size_t>(PTHREAD_STACK_MIN)),
+ static_cast<size_t>(stack_rlimit.rlim_cur));
+ }
+ }
+#endif // OS_MACOSX
+
+ if (stack_size > 0)
+ pthread_attr_setstacksize(&attributes, stack_size);
+
+ ThreadParams* params = new ThreadParams;
+ params->delegate = delegate;
+ params->joinable = joinable;
+ success = !pthread_create(thread_handle, &attributes, ThreadFunc, params);
+
+ pthread_attr_destroy(&attributes);
+ if (!success)
+ delete params;
+ return success;
+}
+
+} // namespace
+
+// static
+PlatformThreadId PlatformThread::CurrentId() {
+ // Pthreads doesn't have the concept of a thread ID, so we have to reach down
+ // into the kernel.
+#if defined(OS_MACOSX)
+ return mach_thread_self();
+#elif defined(OS_LINUX)
+ return syscall(__NR_gettid);
+#elif defined(OS_ANDROID)
+ return gettid();
+#elif defined(OS_FREEBSD)
+ // TODO(BSD): find a better thread ID
+ return reinterpret_cast<int64>(pthread_self());
+#elif defined(OS_NACL) || defined(OS_SOLARIS)
+ return pthread_self();
+#endif
+}
+
+// static
+void PlatformThread::YieldCurrentThread() {
+ sched_yield();
+}
+
+// static
+void PlatformThread::Sleep(int duration_ms) {
+ struct timespec sleep_time, remaining;
+
+ // Contains the portion of duration_ms >= 1 sec.
+ sleep_time.tv_sec = duration_ms / 1000;
+ duration_ms -= sleep_time.tv_sec * 1000;
+
+ // Contains the portion of duration_ms < 1 sec.
+ sleep_time.tv_nsec = duration_ms * 1000 * 1000; // nanoseconds.
+
+ while (nanosleep(&sleep_time, &remaining) == -1 && errno == EINTR)
+ sleep_time = remaining;
+}
+
+// Linux SetName is currently disabled, as we need to distinguish between
+// helper threads (where it's ok to make this call) and the main thread
+// (where making this call renames our process, causing tools like killall
+// to stop working).
+#if 0 && defined(OS_LINUX)
+// static
+void PlatformThread::SetName(const char* name) {
+ // have to cast away const because ThreadLocalPointer does not support const
+ // void*
+ current_thread_name.Set(const_cast<char*>(name));
+
+ // http://0pointer.de/blog/projects/name-your-threads.html
+
+ // glibc recently added support for pthread_setname_np, but it's not
+ // commonly available yet. So test for it at runtime.
+ int (*dynamic_pthread_setname_np)(pthread_t, const char*);
+ *reinterpret_cast<void**>(&dynamic_pthread_setname_np) =
+ dlsym(RTLD_DEFAULT, "pthread_setname_np");
+
+ if (dynamic_pthread_setname_np) {
+ // This limit comes from glibc, which gets it from the kernel
+ // (TASK_COMM_LEN).
+ const int kMaxNameLength = 15;
+ std::string shortened_name = std::string(name).substr(0, kMaxNameLength);
+ int err = dynamic_pthread_setname_np(pthread_self(),
+ shortened_name.c_str());
+ if (err < 0)
+ LOG(ERROR) << "pthread_setname_np: " << safe_strerror(err);
+ } else {
+ // Implementing this function without glibc is simple enough. (We
+ // don't do the name length clipping as above because it will be
+ // truncated by the callee (see TASK_COMM_LEN above).)
+ int err = prctl(PR_SET_NAME, name);
+ if (err < 0)
+ PLOG(ERROR) << "prctl(PR_SET_NAME)";
+ }
+}
+#elif defined(OS_MACOSX)
+// Mac is implemented in platform_thread_mac.mm.
+#else
+// static
+void PlatformThread::SetName(const char* name) {
+ // have to cast away const because ThreadLocalPointer does not support const
+ // void*
+ current_thread_name.Set(const_cast<char*>(name));
+
+ // (This should be relatively simple to implement for the BSDs; I
+ // just don't have one handy to test the code on.)
+}
+#endif // defined(OS_LINUX)
+
+
+#if !defined(OS_MACOSX)
+// Mac is implemented in platform_thread_mac.mm.
+// static
+const char* PlatformThread::GetName() {
+ return current_thread_name.Get();
+}
+#endif
+
+// static
+bool PlatformThread::Create(size_t stack_size, Delegate* delegate,
+ PlatformThreadHandle* thread_handle) {
+ return CreateThread(stack_size, true /* joinable thread */,
+ delegate, thread_handle);
+}
+
+// static
+bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) {
+ PlatformThreadHandle unused;
+
+ bool result = CreateThread(stack_size, false /* non-joinable thread */,
+ delegate, &unused);
+ return result;
+}
+
+// static
+void PlatformThread::Join(PlatformThreadHandle thread_handle) {
+ // Joining another thread may block the current thread for a long time, since
+ // the thread referred to by |thread_handle| may still be running long-lived /
+ // blocking tasks.
+ base::ThreadRestrictions::AssertIOAllowed();
+ pthread_join(thread_handle, NULL);
+}
+
+#if !defined(OS_MACOSX)
+// Mac OS X uses lower-level mach APIs
+
+// static
+void PlatformThread::SetThreadPriority(PlatformThreadHandle, ThreadPriority) {
+ // TODO(crogers): implement
+ NOTIMPLEMENTED();
+}
+#endif
+
+} // namespace base
diff --git a/base/threading/thread.cc b/base/threading/thread.cc
new file mode 100644
index 000000000000..616aac8933a5
--- /dev/null
+++ b/base/threading/thread.cc
@@ -0,0 +1,177 @@
+// 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/threading/thread.h"
+
+#include "base/lazy_instance.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
+#include "base/threading/thread_local.h"
+#include "base/synchronization/waitable_event.h"
+
+namespace base {
+
+namespace {
+
+// We use this thread-local variable to record whether or not a thread exited
+// because its Stop method was called. This allows us to catch cases where
+// MessageLoop::Quit() is called directly, which is unexpected when using a
+// Thread to setup and run a MessageLoop.
+base::LazyInstance<base::ThreadLocalBoolean> lazy_tls_bool(
+ base::LINKER_INITIALIZED);
+
+} // namespace
+
+// This task is used to trigger the message loop to exit.
+class ThreadQuitTask : public Task {
+ public:
+ virtual void Run() {
+ MessageLoop::current()->Quit();
+ Thread::SetThreadWasQuitProperly(true);
+ }
+};
+
+// Used to pass data to ThreadMain. This structure is allocated on the stack
+// from within StartWithOptions.
+struct Thread::StartupData {
+ // We get away with a const reference here because of how we are allocated.
+ const Thread::Options& options;
+
+ // Used to synchronize thread startup.
+ WaitableEvent event;
+
+ explicit StartupData(const Options& opt)
+ : options(opt),
+ event(false, false) {}
+};
+
+Thread::Thread(const char* name)
+ : started_(false),
+ stopping_(false),
+ startup_data_(NULL),
+ thread_(0),
+ message_loop_(NULL),
+ thread_id_(kInvalidThreadId),
+ name_(name) {
+}
+
+Thread::~Thread() {
+ Stop();
+}
+
+bool Thread::Start() {
+ return StartWithOptions(Options());
+}
+
+bool Thread::StartWithOptions(const Options& options) {
+ DCHECK(!message_loop_);
+
+ SetThreadWasQuitProperly(false);
+
+ StartupData startup_data(options);
+ startup_data_ = &startup_data;
+
+ if (!PlatformThread::Create(options.stack_size, this, &thread_)) {
+ DLOG(ERROR) << "failed to create thread";
+ startup_data_ = NULL;
+ return false;
+ }
+
+ // Wait for the thread to start and initialize message_loop_
+ startup_data.event.Wait();
+
+ // set it to NULL so we don't keep a pointer to some object on the stack.
+ startup_data_ = NULL;
+ started_ = true;
+
+ DCHECK(message_loop_);
+ return true;
+}
+
+void Thread::Stop() {
+ if (!thread_was_started())
+ return;
+
+ StopSoon();
+
+ // Wait for the thread to exit.
+ //
+ // TODO(darin): Unfortunately, we need to keep message_loop_ around until
+ // the thread exits. Some consumers are abusing the API. Make them stop.
+ //
+ PlatformThread::Join(thread_);
+
+ // The thread should NULL message_loop_ on exit.
+ DCHECK(!message_loop_);
+
+ // The thread no longer needs to be joined.
+ started_ = false;
+
+ stopping_ = false;
+}
+
+void Thread::StopSoon() {
+ // We should only be called on the same thread that started us.
+
+ // Reading thread_id_ without a lock can lead to a benign data race
+ // with ThreadMain, so we annotate it to stay silent under ThreadSanitizer.
+ DCHECK_NE(ANNOTATE_UNPROTECTED_READ(thread_id_), PlatformThread::CurrentId());
+
+ if (stopping_ || !message_loop_)
+ return;
+
+ stopping_ = true;
+ message_loop_->PostTask(FROM_HERE, new ThreadQuitTask());
+}
+
+void Thread::Run(MessageLoop* message_loop) {
+ message_loop->Run();
+}
+
+void Thread::SetThreadWasQuitProperly(bool flag) {
+ lazy_tls_bool.Pointer()->Set(flag);
+}
+
+bool Thread::GetThreadWasQuitProperly() {
+ bool quit_properly = true;
+#ifndef NDEBUG
+ quit_properly = lazy_tls_bool.Pointer()->Get();
+#endif
+ return quit_properly;
+}
+
+void Thread::ThreadMain() {
+ {
+ // The message loop for this thread.
+ MessageLoop message_loop(startup_data_->options.message_loop_type);
+
+ // Complete the initialization of our Thread object.
+ thread_id_ = PlatformThread::CurrentId();
+ PlatformThread::SetName(name_.c_str());
+ ANNOTATE_THREAD_NAME(name_.c_str()); // Tell the name to race detector.
+ message_loop.set_thread_name(name_);
+ message_loop_ = &message_loop;
+
+ // Let the thread do extra initialization.
+ // Let's do this before signaling we are started.
+ Init();
+
+ startup_data_->event.Signal();
+ // startup_data_ can't be touched anymore since the starting thread is now
+ // unlocked.
+
+ Run(message_loop_);
+
+ // Let the thread do extra cleanup.
+ CleanUp();
+
+ // Assert that MessageLoop::Quit was called by ThreadQuitTask.
+ DCHECK(GetThreadWasQuitProperly());
+
+ // We can't receive messages anymore.
+ message_loop_ = NULL;
+ }
+ thread_id_ = kInvalidThreadId;
+}
+
+} // namespace base
diff --git a/base/threading/thread.h b/base/threading/thread.h
new file mode 100644
index 000000000000..d7451ec58ab9
--- /dev/null
+++ b/base/threading/thread.h
@@ -0,0 +1,191 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_THREAD_H_
+#define BASE_THREAD_H_
+#pragma once
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/message_loop.h"
+#include "base/message_loop_proxy.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+// A simple thread abstraction that establishes a MessageLoop on a new thread.
+// The consumer uses the MessageLoop of the thread to cause code to execute on
+// the thread. When this object is destroyed the thread is terminated. All
+// pending tasks queued on the thread's message loop will run to completion
+// before the thread is terminated.
+//
+// After the thread is stopped, the destruction sequence is:
+//
+// (1) Thread::CleanUp()
+// (2) MessageLoop::~MessageLoop
+// (3.b) MessageLoop::DestructionObserver::WillDestroyCurrentMessageLoop
+class BASE_EXPORT Thread : PlatformThread::Delegate {
+ public:
+ struct Options {
+ Options() : message_loop_type(MessageLoop::TYPE_DEFAULT), stack_size(0) {}
+ Options(MessageLoop::Type type, size_t size)
+ : message_loop_type(type), stack_size(size) {}
+
+ // Specifies the type of message loop that will be allocated on the thread.
+ MessageLoop::Type message_loop_type;
+
+ // Specifies the maximum stack size that the thread is allowed to use.
+ // This does not necessarily correspond to the thread's initial stack size.
+ // A value of 0 indicates that the default maximum should be used.
+ size_t stack_size;
+ };
+
+ // Constructor.
+ // name is a display string to identify the thread.
+ explicit Thread(const char* name);
+
+ // Destroys the thread, stopping it if necessary.
+ //
+ // NOTE: If you are subclassing from Thread, and you wish for your CleanUp
+ // method to be called, then you need to call Stop() from your destructor.
+ //
+ virtual ~Thread();
+
+ // Starts the thread. Returns true if the thread was successfully started;
+ // otherwise, returns false. Upon successful return, the message_loop()
+ // getter will return non-null.
+ //
+ // Note: This function can't be called on Windows with the loader lock held;
+ // i.e. during a DllMain, global object construction or destruction, atexit()
+ // callback.
+ bool Start();
+
+ // Starts the thread. Behaves exactly like Start in addition to allow to
+ // override the default options.
+ //
+ // Note: This function can't be called on Windows with the loader lock held;
+ // i.e. during a DllMain, global object construction or destruction, atexit()
+ // callback.
+ bool StartWithOptions(const Options& options);
+
+ // Signals the thread to exit and returns once the thread has exited. After
+ // this method returns, the Thread object is completely reset and may be used
+ // as if it were newly constructed (i.e., Start may be called again).
+ //
+ // Stop may be called multiple times and is simply ignored if the thread is
+ // already stopped.
+ //
+ // NOTE: This method is optional. It is not strictly necessary to call this
+ // method as the Thread's destructor will take care of stopping the thread if
+ // necessary.
+ //
+ void Stop();
+
+ // Signals the thread to exit in the near future.
+ //
+ // WARNING: This function is not meant to be commonly used. Use at your own
+ // risk. Calling this function will cause message_loop() to become invalid in
+ // the near future. This function was created to workaround a specific
+ // deadlock on Windows with printer worker thread. In any other case, Stop()
+ // should be used.
+ //
+ // StopSoon should not be called multiple times as it is risky to do so. It
+ // could cause a timing issue in message_loop() access. Call Stop() to reset
+ // the thread object once it is known that the thread has quit.
+ void StopSoon();
+
+ // Returns the message loop for this thread. Use the MessageLoop's
+ // PostTask methods to execute code on the thread. This only returns
+ // non-null after a successful call to Start. After Stop has been called,
+ // this will return NULL.
+ //
+ // NOTE: You must not call this MessageLoop's Quit method directly. Use
+ // the Thread's Stop method instead.
+ //
+ MessageLoop* message_loop() const { return message_loop_; }
+
+ // Returns a MessageLoopProxy for this thread. Use the MessageLoopProxy's
+ // PostTask methods to execute code on the thread. This only returns
+ // non-NULL after a successful call to Start. After Stop has been called,
+ // this will return NULL. Callers can hold on to this even after the thread
+ // is gone.
+ // TODO(sanjeevr): Look into merging MessageLoop and MessageLoopProxy.
+ scoped_refptr<MessageLoopProxy> message_loop_proxy() const {
+ return message_loop_->message_loop_proxy();
+ }
+
+ // Set the name of this thread (for display in debugger too).
+ const std::string &thread_name() { return name_; }
+
+ // The native thread handle.
+ PlatformThreadHandle thread_handle() { return thread_; }
+
+ // The thread ID.
+ PlatformThreadId thread_id() const { return thread_id_; }
+
+ // Returns true if the thread has been started, and not yet stopped.
+ // When a thread is running, |thread_id_| is a valid id.
+ bool IsRunning() const { return thread_id_ != kInvalidThreadId; }
+
+ protected:
+ // Called just prior to starting the message loop
+ virtual void Init() {}
+
+ // Called to start the message loop
+ virtual void Run(MessageLoop* message_loop);
+
+ // Called just after the message loop ends
+ virtual void CleanUp() {}
+
+ // Called after the message loop has been deleted. In general clients
+ // should prefer to use CleanUp(). This method is used when code needs to
+ // be run after all of the MessageLoop::DestructionObservers have completed.
+ virtual void CleanUpAfterMessageLoopDestruction() {}
+
+ static void SetThreadWasQuitProperly(bool flag);
+ static bool GetThreadWasQuitProperly();
+
+ void set_message_loop(MessageLoop* message_loop) {
+ message_loop_ = message_loop;
+ }
+
+ private:
+ bool thread_was_started() const { return started_; }
+
+ // PlatformThread::Delegate methods:
+ virtual void ThreadMain();
+
+ // Whether we successfully started the thread.
+ bool started_;
+
+ // If true, we're in the middle of stopping, and shouldn't access
+ // |message_loop_|. It may non-NULL and invalid.
+ bool stopping_;
+
+ // Used to pass data to ThreadMain.
+ struct StartupData;
+ StartupData* startup_data_;
+
+ // The thread's handle.
+ PlatformThreadHandle thread_;
+
+ // The thread's message loop. Valid only while the thread is alive. Set
+ // by the created thread.
+ MessageLoop* message_loop_;
+
+ // Our thread's ID.
+ PlatformThreadId thread_id_;
+
+ // The name of the thread. Used for debugging purposes.
+ std::string name_;
+
+ friend class ThreadQuitTask;
+
+ DISALLOW_COPY_AND_ASSIGN(Thread);
+};
+
+} // namespace base
+
+#endif // BASE_THREAD_H_
diff --git a/base/threading/thread_collision_warner.cc b/base/threading/thread_collision_warner.cc
new file mode 100644
index 000000000000..547e11ca66f9
--- /dev/null
+++ b/base/threading/thread_collision_warner.cc
@@ -0,0 +1,64 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/thread_collision_warner.h"
+
+#include "base/logging.h"
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+void DCheckAsserter::warn() {
+ NOTREACHED() << "Thread Collision";
+}
+
+static subtle::Atomic32 CurrentThread() {
+ const PlatformThreadId current_thread_id = PlatformThread::CurrentId();
+ // We need to get the thread id into an atomic data type. This might be a
+ // truncating conversion, but any loss-of-information just increases the
+ // chance of a fault negative, not a false positive.
+ const subtle::Atomic32 atomic_thread_id =
+ static_cast<subtle::Atomic32>(current_thread_id);
+
+ return atomic_thread_id;
+}
+
+void ThreadCollisionWarner::EnterSelf() {
+ // If the active thread is 0 then I'll write the current thread ID
+ // if two or more threads arrive here only one will succeed to
+ // write on valid_thread_id_ the current thread ID.
+ subtle::Atomic32 current_thread_id = CurrentThread();
+
+ int previous_value = subtle::NoBarrier_CompareAndSwap(&valid_thread_id_,
+ 0,
+ current_thread_id);
+ if (previous_value != 0 && previous_value != current_thread_id) {
+ // gotcha! a thread is trying to use the same class and that is
+ // not current thread.
+ asserter_->warn();
+ }
+
+ subtle::NoBarrier_AtomicIncrement(&counter_, 1);
+}
+
+void ThreadCollisionWarner::Enter() {
+ subtle::Atomic32 current_thread_id = CurrentThread();
+
+ if (subtle::NoBarrier_CompareAndSwap(&valid_thread_id_,
+ 0,
+ current_thread_id) != 0) {
+ // gotcha! another thread is trying to use the same class.
+ asserter_->warn();
+ }
+
+ subtle::NoBarrier_AtomicIncrement(&counter_, 1);
+}
+
+void ThreadCollisionWarner::Leave() {
+ if (subtle::Barrier_AtomicIncrement(&counter_, -1) == 0) {
+ subtle::NoBarrier_Store(&valid_thread_id_, 0);
+ }
+}
+
+} // namespace base
diff --git a/base/threading/thread_collision_warner.h b/base/threading/thread_collision_warner.h
new file mode 100644
index 000000000000..4460602c6c40
--- /dev/null
+++ b/base/threading/thread_collision_warner.h
@@ -0,0 +1,244 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_THREADING_THREAD_COLLISION_WARNER_H_
+#define BASE_THREADING_THREAD_COLLISION_WARNER_H_
+#pragma once
+
+#include <memory>
+
+#include "base/base_export.h"
+#include "base/atomicops.h"
+
+// A helper class alongside macros to be used to verify assumptions about thread
+// safety of a class.
+//
+// Example: Queue implementation non thread-safe but still usable if clients
+// are synchronized somehow.
+//
+// In this case the macro DFAKE_SCOPED_LOCK has to be
+// used, it checks that if a thread is inside the push/pop then
+// noone else is still inside the pop/push
+//
+// class NonThreadSafeQueue {
+// public:
+// ...
+// void push(int) { DFAKE_SCOPED_LOCK(push_pop_); ... }
+// int pop() { DFAKE_SCOPED_LOCK(push_pop_); ... }
+// ...
+// private:
+// DFAKE_MUTEX(push_pop_);
+// };
+//
+//
+// Example: Queue implementation non thread-safe but still usable if clients
+// are synchronized somehow, it calls a method to "protect" from
+// a "protected" method
+//
+// In this case the macro DFAKE_SCOPED_RECURSIVE_LOCK
+// has to be used, it checks that if a thread is inside the push/pop
+// then noone else is still inside the pop/push
+//
+// class NonThreadSafeQueue {
+// public:
+// void push(int) {
+// DFAKE_SCOPED_LOCK(push_pop_);
+// ...
+// }
+// int pop() {
+// DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_);
+// bar();
+// ...
+// }
+// void bar() { DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_); ... }
+// ...
+// private:
+// DFAKE_MUTEX(push_pop_);
+// };
+//
+//
+// Example: Queue implementation not usable even if clients are synchronized,
+// so only one thread in the class life cycle can use the two members
+// push/pop.
+//
+// In this case the macro DFAKE_SCOPED_LOCK_THREAD_LOCKED pins the
+// specified
+// critical section the first time a thread enters push or pop, from
+// that time on only that thread is allowed to execute push or pop.
+//
+// class NonThreadSafeQueue {
+// public:
+// ...
+// void push(int) { DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_); ... }
+// int pop() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_); ... }
+// ...
+// private:
+// DFAKE_MUTEX(push_pop_);
+// };
+//
+//
+// Example: Class that has to be contructed/destroyed on same thread, it has
+// a "shareable" method (with external syncronization) and a not
+// shareable method (even with external synchronization).
+//
+// In this case 3 Critical sections have to be defined
+//
+// class ExoticClass {
+// public:
+// ExoticClass() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... }
+// ~ExoticClass() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... }
+//
+// void Shareable() { DFAKE_SCOPED_LOCK(shareable_section_); ... }
+// void NotShareable() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... }
+// ...
+// private:
+// DFAKE_MUTEX(ctor_dtor_);
+// DFAKE_MUTEX(shareable_section_);
+// };
+
+
+#if !defined(NDEBUG)
+
+// Defines a class member that acts like a mutex. It is used only as a
+// verification tool.
+#define DFAKE_MUTEX(obj) \
+ mutable base::ThreadCollisionWarner obj
+// Asserts the call is never called simultaneously in two threads. Used at
+// member function scope.
+#define DFAKE_SCOPED_LOCK(obj) \
+ base::ThreadCollisionWarner::ScopedCheck s_check_##obj(&obj)
+// Asserts the call is never called simultaneously in two threads. Used at
+// member function scope. Same as DFAKE_SCOPED_LOCK but allows recursive locks.
+#define DFAKE_SCOPED_RECURSIVE_LOCK(obj) \
+ base::ThreadCollisionWarner::ScopedRecursiveCheck sr_check_##obj(&obj)
+// Asserts the code is always executed in the same thread.
+#define DFAKE_SCOPED_LOCK_THREAD_LOCKED(obj) \
+ base::ThreadCollisionWarner::Check check_##obj(&obj)
+
+#else
+
+#define DFAKE_MUTEX(obj)
+#define DFAKE_SCOPED_LOCK(obj) ((void)0)
+#define DFAKE_SCOPED_RECURSIVE_LOCK(obj) ((void)0)
+#define DFAKE_SCOPED_LOCK_THREAD_LOCKED(obj) ((void)0)
+
+#endif
+
+namespace base {
+
+// The class ThreadCollisionWarner uses an Asserter to notify the collision
+// AsserterBase is the interfaces and DCheckAsserter is the default asserter
+// used. During the unit tests is used another class that doesn't "DCHECK"
+// in case of collision (check thread_collision_warner_unittests.cc)
+struct BASE_EXPORT AsserterBase {
+ virtual ~AsserterBase() {}
+ virtual void warn() = 0;
+};
+
+struct BASE_EXPORT DCheckAsserter : public AsserterBase {
+ virtual ~DCheckAsserter() {}
+ virtual void warn();
+};
+
+class BASE_EXPORT ThreadCollisionWarner {
+ public:
+ // The parameter asserter is there only for test purpose
+ ThreadCollisionWarner(AsserterBase* asserter = new DCheckAsserter())
+ : valid_thread_id_(0),
+ counter_(0),
+ asserter_(asserter) {}
+
+ ~ThreadCollisionWarner() {
+ delete asserter_;
+ }
+
+ // This class is meant to be used through the macro
+ // DFAKE_SCOPED_LOCK_THREAD_LOCKED
+ // it doesn't leave the critical section, as opposed to ScopedCheck,
+ // because the critical section being pinned is allowed to be used only
+ // from one thread
+ class BASE_EXPORT Check {
+ public:
+ explicit Check(ThreadCollisionWarner* warner)
+ : warner_(warner) {
+ warner_->EnterSelf();
+ }
+
+ ~Check() {}
+
+ private:
+ ThreadCollisionWarner* warner_;
+
+ DISALLOW_COPY_AND_ASSIGN(Check);
+ };
+
+ // This class is meant to be used through the macro
+ // DFAKE_SCOPED_LOCK
+ class BASE_EXPORT ScopedCheck {
+ public:
+ explicit ScopedCheck(ThreadCollisionWarner* warner)
+ : warner_(warner) {
+ warner_->Enter();
+ }
+
+ ~ScopedCheck() {
+ warner_->Leave();
+ }
+
+ private:
+ ThreadCollisionWarner* warner_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedCheck);
+ };
+
+ // This class is meant to be used through the macro
+ // DFAKE_SCOPED_RECURSIVE_LOCK
+ class BASE_EXPORT ScopedRecursiveCheck {
+ public:
+ explicit ScopedRecursiveCheck(ThreadCollisionWarner* warner)
+ : warner_(warner) {
+ warner_->EnterSelf();
+ }
+
+ ~ScopedRecursiveCheck() {
+ warner_->Leave();
+ }
+
+ private:
+ ThreadCollisionWarner* warner_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedRecursiveCheck);
+ };
+
+ private:
+ // This method stores the current thread identifier and does a DCHECK
+ // if a another thread has already done it, it is safe if same thread
+ // calls this multiple time (recursion allowed).
+ void EnterSelf();
+
+ // Same as EnterSelf but recursion is not allowed.
+ void Enter();
+
+ // Removes the thread_id stored in order to allow other threads to
+ // call EnterSelf or Enter.
+ void Leave();
+
+ // This stores the thread id that is inside the critical section, if the
+ // value is 0 then no thread is inside.
+ volatile subtle::Atomic32 valid_thread_id_;
+
+ // Counter to trace how many time a critical section was "pinned"
+ // (when allowed) in order to unpin it when counter_ reaches 0.
+ volatile subtle::Atomic32 counter_;
+
+ // Here only for class unit tests purpose, during the test I need to not
+ // DCHECK but notify the collision with something else.
+ AsserterBase* asserter_;
+
+ DISALLOW_COPY_AND_ASSIGN(ThreadCollisionWarner);
+};
+
+} // namespace base
+
+#endif // BASE_THREADING_THREAD_COLLISION_WARNER_H_
diff --git a/base/time.h b/base/time.h
new file mode 100644
index 000000000000..aa97f0ab4f42
--- /dev/null
+++ b/base/time.h
@@ -0,0 +1,566 @@
+// 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.
+
+// Time represents an absolute point in time, internally represented as
+// microseconds (s/1,000,000) since a platform-dependent epoch. Each
+// platform's epoch, along with other system-dependent clock interface
+// routines, is defined in time_PLATFORM.cc.
+//
+// TimeDelta represents a duration of time, internally represented in
+// microseconds.
+//
+// TimeTicks represents an abstract time that is always incrementing for use
+// in measuring time durations. It is internally represented in microseconds.
+// It can not be converted to a human-readable time, but is guaranteed not to
+// decrease (if the user changes the computer clock, Time::Now() may actually
+// decrease or jump).
+//
+// These classes are represented as only a 64-bit value, so they can be
+// efficiently passed by value.
+
+#ifndef BASE_TIME_H_
+#define BASE_TIME_H_
+#pragma once
+
+#include <time.h>
+
+#include "base/atomicops.h"
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+#if defined(OS_POSIX)
+// For struct timeval.
+#include <sys/time.h>
+#endif
+
+#if defined(OS_WIN)
+// For FILETIME in FromFileTime, until it moves to a new converter class.
+// See TODO(iyengar) below.
+#include <windows.h>
+#endif
+
+namespace base {
+
+class Time;
+class TimeTicks;
+
+// TimeDelta ------------------------------------------------------------------
+
+class BASE_EXPORT TimeDelta {
+ public:
+ TimeDelta() : delta_(0) {
+ }
+
+ // Converts units of time to TimeDeltas.
+ static TimeDelta FromDays(int64 days);
+ static TimeDelta FromHours(int64 hours);
+ static TimeDelta FromMinutes(int64 minutes);
+ static TimeDelta FromSeconds(int64 secs);
+ static TimeDelta FromMilliseconds(int64 ms);
+ static TimeDelta FromMicroseconds(int64 us);
+
+ // Returns the internal numeric value of the TimeDelta object. 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 delta_;
+ }
+
+#if defined(OS_POSIX)
+ struct timespec ToTimeSpec() const;
+#endif
+
+ // Returns the time delta in some unit. The F versions return a floating
+ // point value, the "regular" versions return a rounded-down value.
+ //
+ // InMillisecondsRoundedUp() instead returns an integer that is rounded up
+ // to the next full millisecond.
+ int InDays() const;
+ int InHours() const;
+ int InMinutes() const;
+ double InSecondsF() const;
+ int64 InSeconds() const;
+ double InMillisecondsF() const;
+ int64 InMilliseconds() const;
+ int64 InMillisecondsRoundedUp() const;
+ int64 InMicroseconds() const;
+
+ TimeDelta& operator=(TimeDelta other) {
+ delta_ = other.delta_;
+ return *this;
+ }
+
+ // Computations with other deltas.
+ TimeDelta operator+(TimeDelta other) const {
+ return TimeDelta(delta_ + other.delta_);
+ }
+ TimeDelta operator-(TimeDelta other) const {
+ return TimeDelta(delta_ - other.delta_);
+ }
+
+ TimeDelta& operator+=(TimeDelta other) {
+ delta_ += other.delta_;
+ return *this;
+ }
+ TimeDelta& operator-=(TimeDelta other) {
+ delta_ -= other.delta_;
+ return *this;
+ }
+ TimeDelta operator-() const {
+ return TimeDelta(-delta_);
+ }
+
+ // Computations with ints, note that we only allow multiplicative operations
+ // with ints, and additive operations with other deltas.
+ TimeDelta operator*(int64 a) const {
+ return TimeDelta(delta_ * a);
+ }
+ TimeDelta operator/(int64 a) const {
+ return TimeDelta(delta_ / a);
+ }
+ TimeDelta& operator*=(int64 a) {
+ delta_ *= a;
+ return *this;
+ }
+ TimeDelta& operator/=(int64 a) {
+ delta_ /= a;
+ return *this;
+ }
+ int64 operator/(TimeDelta a) const {
+ return delta_ / a.delta_;
+ }
+
+ // Defined below because it depends on the definition of the other classes.
+ Time operator+(Time t) const;
+ TimeTicks operator+(TimeTicks t) const;
+
+ // Comparison operators.
+ bool operator==(TimeDelta other) const {
+ return delta_ == other.delta_;
+ }
+ bool operator!=(TimeDelta other) const {
+ return delta_ != other.delta_;
+ }
+ bool operator<(TimeDelta other) const {
+ return delta_ < other.delta_;
+ }
+ bool operator<=(TimeDelta other) const {
+ return delta_ <= other.delta_;
+ }
+ bool operator>(TimeDelta other) const {
+ return delta_ > other.delta_;
+ }
+ bool operator>=(TimeDelta other) const {
+ return delta_ >= other.delta_;
+ }
+
+ private:
+ friend class Time;
+ friend class TimeTicks;
+ friend TimeDelta operator*(int64 a, TimeDelta td);
+
+ // 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) {
+ }
+
+ // Delta in microseconds.
+ int64 delta_;
+};
+
+inline TimeDelta operator*(int64 a, TimeDelta td) {
+ return TimeDelta(a * td.delta_);
+}
+
+// Time -----------------------------------------------------------------------
+
+// Represents a wall clock time.
+class BASE_EXPORT Time {
+ public:
+ static const int64 kMillisecondsPerSecond = 1000;
+ static const int64 kMicrosecondsPerMillisecond = 1000;
+ static const int64 kMicrosecondsPerSecond = kMicrosecondsPerMillisecond *
+ kMillisecondsPerSecond;
+ static const int64 kMicrosecondsPerMinute = kMicrosecondsPerSecond * 60;
+ static const int64 kMicrosecondsPerHour = kMicrosecondsPerMinute * 60;
+ static const int64 kMicrosecondsPerDay = kMicrosecondsPerHour * 24;
+ static const int64 kMicrosecondsPerWeek = kMicrosecondsPerDay * 7;
+ static const int64 kNanosecondsPerMicrosecond = 1000;
+ static const int64 kNanosecondsPerSecond = kNanosecondsPerMicrosecond *
+ kMicrosecondsPerSecond;
+
+#if !defined(OS_WIN)
+ // On Mac & Linux, this value is the delta from the Windows epoch of 1601 to
+ // the Posix delta of 1970. This is used for migrating between the old
+ // 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;
+#endif
+
+ // Represents an exploded time that can be formatted nicely. This is kind of
+ // like the Win32 SYSTEMTIME structure or the Unix "struct tm" with a few
+ // additions and changes to prevent errors.
+ struct BASE_EXPORT Exploded {
+ int year; // Four digit year "2007"
+ int month; // 1-based month (values 1 = January, etc.)
+ int day_of_week; // 0-based day of week (0 = Sunday, etc.)
+ int day_of_month; // 1-based day of month (1-31)
+ int hour; // Hour within the current day (0-23)
+ int minute; // Minute within the current hour (0-59)
+ int second; // Second within the current minute (0-59 plus leap
+ // seconds which may take it up to 60).
+ int millisecond; // Milliseconds within the current second (0-999)
+
+ // A cursory test for whether the data members are within their
+ // respective ranges. A 'true' return value does not guarantee the
+ // Exploded value can be successfully converted to a Time value.
+ bool HasValidValues() const;
+ };
+
+ // Contains the NULL time. Use Time::Now() to get the current time.
+ explicit Time() : us_(0) {
+ }
+
+ // Returns true if the time object has not been initialized.
+ bool is_null() const {
+ return us_ == 0;
+ }
+
+ // Returns the time for epoch in Unix-like system (Jan 1, 1970).
+ static Time UnixEpoch();
+
+ // Returns the current time. Watch out, the system might adjust its clock
+ // in which case time will actually go backwards. We don't guarantee that
+ // times are increasing, or that two calls to Now() won't be the same.
+ static Time Now();
+
+ // Returns the current time. Same as Now() except that this function always
+ // uses system time so that there are no discrepancies between the returned
+ // time and system time even on virtual environments including our test bot.
+ // For timing sensitive unittests, this function should be used.
+ static Time NowFromSystemTime();
+
+ // Converts to/from time_t in UTC and a Time class.
+ // TODO(brettw) this should be removed once everybody starts using the |Time|
+ // class.
+ static Time FromTimeT(time_t tt);
+ time_t ToTimeT() const;
+
+ // Converts time to/from a double which is the number of seconds since epoch
+ // (Jan 1, 1970). Webkit uses this format to represent time.
+ // Because WebKit initializes double time value to 0 to indicate "not
+ // initialized", we map it to empty Time object that also means "not
+ // initialized".
+ static Time FromDoubleT(double dt);
+ double ToDoubleT() const;
+
+#if defined(OS_POSIX)
+ struct timeval ToTimeVal() const;
+#endif
+
+#if defined(OS_WIN)
+ static Time FromFileTime(FILETIME ft);
+ FILETIME ToFileTime() const;
+
+ // The minimum time of a low resolution timer. This is basically a windows
+ // constant of ~15.6ms. While it does vary on some older OS versions, we'll
+ // treat it as static across all windows versions.
+ static const int kMinLowResolutionThresholdMs = 16;
+
+ // Enable or disable Windows high resolution timer. If the high resolution
+ // timer is not enabled, calls to ActivateHighResolutionTimer will fail.
+ // When disabling the high resolution timer, this function will not cause
+ // the high resolution timer to be deactivated, but will prevent future
+ // activations.
+ // Must be called from the main thread.
+ // For more details see comments in time_win.cc.
+ static void EnableHighResolutionTimer(bool enable);
+
+ // Activates or deactivates the high resolution timer based on the |activate|
+ // flag. If the HighResolutionTimer is not Enabled (see
+ // EnableHighResolutionTimer), this function will return false. Otherwise
+ // returns true. Each successful activate call must be paired with a
+ // subsequent deactivate call.
+ // All callers to activate the high resolution timer must eventually call
+ // this function to deactivate the high resolution timer.
+ static bool ActivateHighResolutionTimer(bool activate);
+
+ // Returns true if the high resolution timer is both enabled and activated.
+ // This is provided for testing only, and is not tracked in a thread-safe
+ // way.
+ static bool IsHighResolutionTimerInUse();
+#endif
+
+ // Converts an exploded structure representing either the local time or UTC
+ // into a Time class.
+ static Time FromUTCExploded(const Exploded& exploded) {
+ return FromExploded(false, exploded);
+ }
+ static Time FromLocalExploded(const Exploded& exploded) {
+ return FromExploded(true, exploded);
+ }
+
+ // Converts an integer value representing Time to a class. This is used
+ // when deserializing a |Time| structure, using a value known to be
+ // compatible. It is not provided as a constructor because the integer type
+ // may be unclear from the perspective of a caller.
+ static Time FromInternalValue(int64 us) {
+ return Time(us);
+ }
+
+ // Converts a string representation of time to a Time object.
+ // An example of a time string which is converted is as below:-
+ // "Tue, 15 Nov 1994 12:45:26 GMT". If the timezone is not specified
+ // in the input string, we assume local time.
+ // TODO(iyengar) Move the FromString/FromTimeT/ToTimeT/FromFileTime to
+ // a new time converter class.
+ static bool FromString(const char* time_string, Time* parsed_time);
+
+ // For serializing, use FromInternalValue to reconstitute. Please don't use
+ // this and do arithmetic on it, as it is more error prone than using the
+ // provided operators.
+ int64 ToInternalValue() const {
+ return us_;
+ }
+
+ // Fills the given exploded structure with either the local time or UTC from
+ // this time structure (containing UTC).
+ void UTCExplode(Exploded* exploded) const {
+ return Explode(false, exploded);
+ }
+ void LocalExplode(Exploded* exploded) const {
+ return Explode(true, exploded);
+ }
+
+ // Rounds this time down to the nearest day in local time. It will represent
+ // midnight on that day.
+ Time LocalMidnight() const;
+
+ Time& operator=(Time other) {
+ us_ = other.us_;
+ return *this;
+ }
+
+ // Compute the difference between two times.
+ TimeDelta operator-(Time other) const {
+ return TimeDelta(us_ - other.us_);
+ }
+
+ // Modify by some time delta.
+ Time& operator+=(TimeDelta delta) {
+ us_ += delta.delta_;
+ return *this;
+ }
+ Time& operator-=(TimeDelta delta) {
+ us_ -= delta.delta_;
+ return *this;
+ }
+
+ // Return a new time modified by some delta.
+ Time operator+(TimeDelta delta) const {
+ return Time(us_ + delta.delta_);
+ }
+ Time operator-(TimeDelta delta) const {
+ return Time(us_ - delta.delta_);
+ }
+
+ // Comparison operators
+ bool operator==(Time other) const {
+ return us_ == other.us_;
+ }
+ bool operator!=(Time other) const {
+ return us_ != other.us_;
+ }
+ bool operator<(Time other) const {
+ return us_ < other.us_;
+ }
+ bool operator<=(Time other) const {
+ return us_ <= other.us_;
+ }
+ bool operator>(Time other) const {
+ return us_ > other.us_;
+ }
+ bool operator>=(Time other) const {
+ return us_ >= other.us_;
+ }
+
+ private:
+ friend class TimeDelta;
+
+ explicit Time(int64 us) : us_(us) {
+ }
+
+ // Explodes the given time to either local time |is_local = true| or UTC
+ // |is_local = false|.
+ void Explode(bool is_local, Exploded* exploded) const;
+
+ // Unexplodes a given time assuming the source is either local time
+ // |is_local = true| or UTC |is_local = false|.
+ static Time FromExploded(bool is_local, const Exploded& exploded);
+
+ // The representation of Jan 1, 1970 UTC in microseconds since the
+ // platform-dependent epoch.
+ static const int64 kTimeTToMicrosecondsOffset;
+
+#if defined(OS_WIN)
+ // Indicates whether fast timers are usable right now. For instance,
+ // when using battery power, we might elect to prevent high speed timers
+ // which would draw more power.
+ static bool high_resolution_timer_enabled_;
+ // Count of activations on the high resolution timer. Only use in tests
+ // which are single threaded.
+ static int high_resolution_timer_activated_;
+#endif
+
+ // Time in microseconds in UTC.
+ int64 us_;
+};
+
+// Inline the TimeDelta factory methods, for fast TimeDelta construction.
+
+// static
+inline TimeDelta TimeDelta::FromDays(int64 days) {
+ return TimeDelta(days * Time::kMicrosecondsPerDay);
+}
+
+// static
+inline TimeDelta TimeDelta::FromHours(int64 hours) {
+ return TimeDelta(hours * Time::kMicrosecondsPerHour);
+}
+
+// static
+inline TimeDelta TimeDelta::FromMinutes(int64 minutes) {
+ return TimeDelta(minutes * Time::kMicrosecondsPerMinute);
+}
+
+// static
+inline TimeDelta TimeDelta::FromSeconds(int64 secs) {
+ return TimeDelta(secs * Time::kMicrosecondsPerSecond);
+}
+
+// static
+inline TimeDelta TimeDelta::FromMilliseconds(int64 ms) {
+ return TimeDelta(ms * Time::kMicrosecondsPerMillisecond);
+}
+
+// static
+inline TimeDelta TimeDelta::FromMicroseconds(int64 us) {
+ return TimeDelta(us);
+}
+
+inline Time TimeDelta::operator+(Time t) const {
+ return Time(t.us_ + delta_);
+}
+
+// TimeTicks ------------------------------------------------------------------
+
+class BASE_EXPORT TimeTicks {
+ public:
+ TimeTicks() : ticks_(0) {
+ }
+
+ // Platform-dependent tick count representing "right now."
+ // The resolution of this clock is ~1-15ms. Resolution varies depending
+ // on hardware/operating system configuration.
+ static TimeTicks Now();
+
+ // Returns a platform-dependent high-resolution tick count. Implementation
+ // is hardware dependent and may or may not return sub-millisecond
+ // resolution. THIS CALL IS GENERALLY MUCH MORE EXPENSIVE THAN Now() AND
+ // SHOULD ONLY BE USED WHEN IT IS REALLY NEEDED.
+ static TimeTicks HighResNow();
+
+#if defined(OS_WIN)
+ // Get the absolute value of QPC time drift. For testing.
+ static int64 GetQPCDriftMicroseconds();
+
+ // Returns true if the high resolution clock is working on this system.
+ // This is only for testing.
+ static bool IsHighResClockWorking();
+#endif
+
+ // Returns true if this object has not been initialized.
+ bool is_null() const {
+ return ticks_ == 0;
+ }
+
+ // Returns the internal numeric value of the TimeTicks object.
+ int64 ToInternalValue() const {
+ return ticks_;
+ }
+
+ TimeTicks& operator=(TimeTicks other) {
+ ticks_ = other.ticks_;
+ return *this;
+ }
+
+ // Compute the difference between two times.
+ TimeDelta operator-(TimeTicks other) const {
+ return TimeDelta(ticks_ - other.ticks_);
+ }
+
+ // Modify by some time delta.
+ TimeTicks& operator+=(TimeDelta delta) {
+ ticks_ += delta.delta_;
+ return *this;
+ }
+ TimeTicks& operator-=(TimeDelta delta) {
+ ticks_ -= delta.delta_;
+ return *this;
+ }
+
+ // Return a new TimeTicks modified by some delta.
+ TimeTicks operator+(TimeDelta delta) const {
+ return TimeTicks(ticks_ + delta.delta_);
+ }
+ TimeTicks operator-(TimeDelta delta) const {
+ return TimeTicks(ticks_ - delta.delta_);
+ }
+
+ // Comparison operators
+ bool operator==(TimeTicks other) const {
+ return ticks_ == other.ticks_;
+ }
+ bool operator!=(TimeTicks other) const {
+ return ticks_ != other.ticks_;
+ }
+ bool operator<(TimeTicks other) const {
+ return ticks_ < other.ticks_;
+ }
+ bool operator<=(TimeTicks other) const {
+ return ticks_ <= other.ticks_;
+ }
+ bool operator>(TimeTicks other) const {
+ return ticks_ > other.ticks_;
+ }
+ bool operator>=(TimeTicks other) const {
+ return ticks_ >= other.ticks_;
+ }
+
+ protected:
+ friend class TimeDelta;
+
+ // Please use Now() to create a new object. This is for internal use
+ // and testing. Ticks is in microseconds.
+ explicit TimeTicks(int64 ticks) : ticks_(ticks) {
+ }
+
+ // Tick count in microseconds.
+ int64 ticks_;
+
+#if defined(OS_WIN)
+ typedef DWORD (*TickFunctionType)(void);
+ static TickFunctionType SetMockTickFunction(TickFunctionType ticker);
+#endif
+};
+
+inline TimeTicks TimeDelta::operator+(TimeTicks t) const {
+ return TimeTicks(t.ticks_ + delta_);
+}
+
+} // namespace base
+
+#endif // BASE_TIME_H_
diff --git a/base/tuple.h b/base/tuple.h
new file mode 100644
index 000000000000..65d0908a0fad
--- /dev/null
+++ b/base/tuple.h
@@ -0,0 +1,1056 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// A Tuple is a generic templatized container, similar in concept to std::pair.
+// There are classes Tuple0 to Tuple6, cooresponding to the number of elements
+// it contains. The convenient MakeTuple() function takes 0 to 6 arguments,
+// and will construct and return the appropriate Tuple object. The functions
+// DispatchToMethod and DispatchToFunction take a function pointer or instance
+// and method pointer, and unpack a tuple into arguments to the call.
+//
+// Tuple elements are copied by value, and stored in the tuple. See the unit
+// tests for more details of how/when the values are copied.
+//
+// Example usage:
+// // These two methods of creating a Tuple are identical.
+// Tuple2<int, const char*> tuple_a(1, "wee");
+// Tuple2<int, const char*> tuple_b = MakeTuple(1, "wee");
+//
+// void SomeFunc(int a, const char* b) { }
+// DispatchToFunction(&SomeFunc, tuple_a); // SomeFunc(1, "wee")
+// DispatchToFunction(
+// &SomeFunc, MakeTuple(10, "foo")); // SomeFunc(10, "foo")
+//
+// struct { void SomeMeth(int a, int b, int c) { } } foo;
+// DispatchToMethod(&foo, &Foo::SomeMeth, MakeTuple(1, 2, 3));
+// // foo->SomeMeth(1, 2, 3);
+
+#ifndef BASE_TUPLE_H__
+#define BASE_TUPLE_H__
+#pragma once
+
+#if defined(OS_CHROMEOS)
+// To troubleshoot crosbug.com/7327.
+#include "base/logging.h"
+#endif
+// Traits ----------------------------------------------------------------------
+//
+// A simple traits class for tuple arguments.
+//
+// ValueType: the bare, nonref version of a type (same as the type for nonrefs).
+// RefType: the ref version of a type (same as the type for refs).
+// ParamType: what type to pass to functions (refs should not be constified).
+
+template <class P>
+struct TupleTraits {
+ typedef P ValueType;
+ typedef P& RefType;
+ typedef const P& ParamType;
+};
+
+template <class P>
+struct TupleTraits<P&> {
+ typedef P ValueType;
+ typedef P& RefType;
+ typedef P& ParamType;
+};
+
+template <class P>
+struct TupleTypes { };
+
+// Tuple -----------------------------------------------------------------------
+//
+// This set of classes is useful for bundling 0 or more heterogeneous data types
+// into a single variable. The advantage of this is that it greatly simplifies
+// function objects that need to take an arbitrary number of parameters; see
+// RunnableMethod and IPC::MessageWithTuple.
+//
+// Tuple0 is supplied to act as a 'void' type. It can be used, for example,
+// when dispatching to a function that accepts no arguments (see the
+// Dispatchers below).
+// Tuple1<A> is rarely useful. One such use is when A is non-const ref that you
+// want filled by the dispatchee, and the tuple is merely a container for that
+// output (a "tier"). See MakeRefTuple and its usages.
+
+struct Tuple0 {
+ typedef Tuple0 ValueTuple;
+ typedef Tuple0 RefTuple;
+ typedef Tuple0 ParamTuple;
+};
+
+template <class A>
+struct Tuple1 {
+ public:
+ typedef A TypeA;
+
+ Tuple1() {}
+ explicit Tuple1(typename TupleTraits<A>::ParamType a) : a(a) {}
+
+ A a;
+};
+
+template <class A, class B>
+struct Tuple2 {
+ public:
+ typedef A TypeA;
+ typedef B TypeB;
+
+ Tuple2() {}
+ Tuple2(typename TupleTraits<A>::ParamType a,
+ typename TupleTraits<B>::ParamType b)
+ : a(a), b(b) {
+ }
+
+ A a;
+ B b;
+};
+
+template <class A, class B, class C>
+struct Tuple3 {
+ public:
+ typedef A TypeA;
+ typedef B TypeB;
+ typedef C TypeC;
+
+ Tuple3() {}
+ Tuple3(typename TupleTraits<A>::ParamType a,
+ typename TupleTraits<B>::ParamType b,
+ typename TupleTraits<C>::ParamType c)
+ : a(a), b(b), c(c){
+ }
+
+ A a;
+ B b;
+ C c;
+};
+
+template <class A, class B, class C, class D>
+struct Tuple4 {
+ public:
+ typedef A TypeA;
+ typedef B TypeB;
+ typedef C TypeC;
+ typedef D TypeD;
+
+ Tuple4() {}
+ Tuple4(typename TupleTraits<A>::ParamType a,
+ typename TupleTraits<B>::ParamType b,
+ typename TupleTraits<C>::ParamType c,
+ typename TupleTraits<D>::ParamType d)
+ : a(a), b(b), c(c), d(d) {
+ }
+
+ A a;
+ B b;
+ C c;
+ D d;
+};
+
+template <class A, class B, class C, class D, class E>
+struct Tuple5 {
+ public:
+ typedef A TypeA;
+ typedef B TypeB;
+ typedef C TypeC;
+ typedef D TypeD;
+ typedef E TypeE;
+
+ Tuple5() {}
+ Tuple5(typename TupleTraits<A>::ParamType a,
+ typename TupleTraits<B>::ParamType b,
+ typename TupleTraits<C>::ParamType c,
+ typename TupleTraits<D>::ParamType d,
+ typename TupleTraits<E>::ParamType e)
+ : a(a), b(b), c(c), d(d), e(e) {
+ }
+
+ A a;
+ B b;
+ C c;
+ D d;
+ E e;
+};
+
+template <class A, class B, class C, class D, class E, class F>
+struct Tuple6 {
+ public:
+ typedef A TypeA;
+ typedef B TypeB;
+ typedef C TypeC;
+ typedef D TypeD;
+ typedef E TypeE;
+ typedef F TypeF;
+
+ Tuple6() {}
+ Tuple6(typename TupleTraits<A>::ParamType a,
+ typename TupleTraits<B>::ParamType b,
+ typename TupleTraits<C>::ParamType c,
+ typename TupleTraits<D>::ParamType d,
+ typename TupleTraits<E>::ParamType e,
+ typename TupleTraits<F>::ParamType f)
+ : a(a), b(b), c(c), d(d), e(e), f(f) {
+ }
+
+ A a;
+ B b;
+ C c;
+ D d;
+ E e;
+ F f;
+};
+
+template <class A, class B, class C, class D, class E, class F, class G>
+struct Tuple7 {
+ public:
+ typedef A TypeA;
+ typedef B TypeB;
+ typedef C TypeC;
+ typedef D TypeD;
+ typedef E TypeE;
+ typedef F TypeF;
+ typedef G TypeG;
+
+ Tuple7() {}
+ Tuple7(typename TupleTraits<A>::ParamType a,
+ typename TupleTraits<B>::ParamType b,
+ typename TupleTraits<C>::ParamType c,
+ typename TupleTraits<D>::ParamType d,
+ typename TupleTraits<E>::ParamType e,
+ typename TupleTraits<F>::ParamType f,
+ typename TupleTraits<G>::ParamType g)
+ : a(a), b(b), c(c), d(d), e(e), f(f), g(g) {
+ }
+
+ A a;
+ B b;
+ C c;
+ D d;
+ E e;
+ F f;
+ G g;
+};
+
+template <class A, class B, class C, class D, class E, class F, class G,
+ class H>
+struct Tuple8 {
+ public:
+ typedef A TypeA;
+ typedef B TypeB;
+ typedef C TypeC;
+ typedef D TypeD;
+ typedef E TypeE;
+ typedef F TypeF;
+ typedef G TypeG;
+ typedef H TypeH;
+
+ Tuple8() {}
+ Tuple8(typename TupleTraits<A>::ParamType a,
+ typename TupleTraits<B>::ParamType b,
+ typename TupleTraits<C>::ParamType c,
+ typename TupleTraits<D>::ParamType d,
+ typename TupleTraits<E>::ParamType e,
+ typename TupleTraits<F>::ParamType f,
+ typename TupleTraits<G>::ParamType g,
+ typename TupleTraits<H>::ParamType h)
+ : a(a), b(b), c(c), d(d), e(e), f(f), g(g), h(h) {
+ }
+
+ A a;
+ B b;
+ C c;
+ D d;
+ E e;
+ F f;
+ G g;
+ H h;
+};
+
+// Tuple types ----------------------------------------------------------------
+//
+// Allows for selection of ValueTuple/RefTuple/ParamTuple without needing the
+// definitions of class types the tuple takes as parameters.
+
+template <>
+struct TupleTypes< Tuple0 > {
+ typedef Tuple0 ValueTuple;
+ typedef Tuple0 RefTuple;
+ typedef Tuple0 ParamTuple;
+};
+
+template <class A>
+struct TupleTypes< Tuple1<A> > {
+ typedef Tuple1<typename TupleTraits<A>::ValueType> ValueTuple;
+ typedef Tuple1<typename TupleTraits<A>::RefType> RefTuple;
+ typedef Tuple1<typename TupleTraits<A>::ParamType> ParamTuple;
+};
+
+template <class A, class B>
+struct TupleTypes< Tuple2<A, B> > {
+ typedef Tuple2<typename TupleTraits<A>::ValueType,
+ typename TupleTraits<B>::ValueType> ValueTuple;
+typedef Tuple2<typename TupleTraits<A>::RefType,
+ typename TupleTraits<B>::RefType> RefTuple;
+ typedef Tuple2<typename TupleTraits<A>::ParamType,
+ typename TupleTraits<B>::ParamType> ParamTuple;
+};
+
+template <class A, class B, class C>
+struct TupleTypes< Tuple3<A, B, C> > {
+ typedef Tuple3<typename TupleTraits<A>::ValueType,
+ typename TupleTraits<B>::ValueType,
+ typename TupleTraits<C>::ValueType> ValueTuple;
+typedef Tuple3<typename TupleTraits<A>::RefType,
+ typename TupleTraits<B>::RefType,
+ typename TupleTraits<C>::RefType> RefTuple;
+ typedef Tuple3<typename TupleTraits<A>::ParamType,
+ typename TupleTraits<B>::ParamType,
+ typename TupleTraits<C>::ParamType> ParamTuple;
+};
+
+template <class A, class B, class C, class D>
+struct TupleTypes< Tuple4<A, B, C, D> > {
+ typedef Tuple4<typename TupleTraits<A>::ValueType,
+ typename TupleTraits<B>::ValueType,
+ typename TupleTraits<C>::ValueType,
+ typename TupleTraits<D>::ValueType> ValueTuple;
+typedef Tuple4<typename TupleTraits<A>::RefType,
+ typename TupleTraits<B>::RefType,
+ typename TupleTraits<C>::RefType,
+ typename TupleTraits<D>::RefType> RefTuple;
+ typedef Tuple4<typename TupleTraits<A>::ParamType,
+ typename TupleTraits<B>::ParamType,
+ typename TupleTraits<C>::ParamType,
+ typename TupleTraits<D>::ParamType> ParamTuple;
+};
+
+template <class A, class B, class C, class D, class E>
+struct TupleTypes< Tuple5<A, B, C, D, E> > {
+ typedef Tuple5<typename TupleTraits<A>::ValueType,
+ typename TupleTraits<B>::ValueType,
+ typename TupleTraits<C>::ValueType,
+ typename TupleTraits<D>::ValueType,
+ typename TupleTraits<E>::ValueType> ValueTuple;
+typedef Tuple5<typename TupleTraits<A>::RefType,
+ typename TupleTraits<B>::RefType,
+ typename TupleTraits<C>::RefType,
+ typename TupleTraits<D>::RefType,
+ typename TupleTraits<E>::RefType> RefTuple;
+ typedef Tuple5<typename TupleTraits<A>::ParamType,
+ typename TupleTraits<B>::ParamType,
+ typename TupleTraits<C>::ParamType,
+ typename TupleTraits<D>::ParamType,
+ typename TupleTraits<E>::ParamType> ParamTuple;
+};
+
+template <class A, class B, class C, class D, class E, class F>
+struct TupleTypes< Tuple6<A, B, C, D, E, F> > {
+ typedef Tuple6<typename TupleTraits<A>::ValueType,
+ typename TupleTraits<B>::ValueType,
+ typename TupleTraits<C>::ValueType,
+ typename TupleTraits<D>::ValueType,
+ typename TupleTraits<E>::ValueType,
+ typename TupleTraits<F>::ValueType> ValueTuple;
+typedef Tuple6<typename TupleTraits<A>::RefType,
+ typename TupleTraits<B>::RefType,
+ typename TupleTraits<C>::RefType,
+ typename TupleTraits<D>::RefType,
+ typename TupleTraits<E>::RefType,
+ typename TupleTraits<F>::RefType> RefTuple;
+ typedef Tuple6<typename TupleTraits<A>::ParamType,
+ typename TupleTraits<B>::ParamType,
+ typename TupleTraits<C>::ParamType,
+ typename TupleTraits<D>::ParamType,
+ typename TupleTraits<E>::ParamType,
+ typename TupleTraits<F>::ParamType> ParamTuple;
+};
+
+template <class A, class B, class C, class D, class E, class F, class G>
+struct TupleTypes< Tuple7<A, B, C, D, E, F, G> > {
+ typedef Tuple7<typename TupleTraits<A>::ValueType,
+ typename TupleTraits<B>::ValueType,
+ typename TupleTraits<C>::ValueType,
+ typename TupleTraits<D>::ValueType,
+ typename TupleTraits<E>::ValueType,
+ typename TupleTraits<F>::ValueType,
+ typename TupleTraits<G>::ValueType> ValueTuple;
+typedef Tuple7<typename TupleTraits<A>::RefType,
+ typename TupleTraits<B>::RefType,
+ typename TupleTraits<C>::RefType,
+ typename TupleTraits<D>::RefType,
+ typename TupleTraits<E>::RefType,
+ typename TupleTraits<F>::RefType,
+ typename TupleTraits<G>::RefType> RefTuple;
+ typedef Tuple7<typename TupleTraits<A>::ParamType,
+ typename TupleTraits<B>::ParamType,
+ typename TupleTraits<C>::ParamType,
+ typename TupleTraits<D>::ParamType,
+ typename TupleTraits<E>::ParamType,
+ typename TupleTraits<F>::ParamType,
+ typename TupleTraits<G>::ParamType> ParamTuple;
+};
+
+template <class A, class B, class C, class D, class E, class F, class G,
+ class H>
+struct TupleTypes< Tuple8<A, B, C, D, E, F, G, H> > {
+ typedef Tuple8<typename TupleTraits<A>::ValueType,
+ typename TupleTraits<B>::ValueType,
+ typename TupleTraits<C>::ValueType,
+ typename TupleTraits<D>::ValueType,
+ typename TupleTraits<E>::ValueType,
+ typename TupleTraits<F>::ValueType,
+ typename TupleTraits<G>::ValueType,
+ typename TupleTraits<H>::ValueType> ValueTuple;
+typedef Tuple8<typename TupleTraits<A>::RefType,
+ typename TupleTraits<B>::RefType,
+ typename TupleTraits<C>::RefType,
+ typename TupleTraits<D>::RefType,
+ typename TupleTraits<E>::RefType,
+ typename TupleTraits<F>::RefType,
+ typename TupleTraits<G>::RefType,
+ typename TupleTraits<H>::RefType> RefTuple;
+ typedef Tuple8<typename TupleTraits<A>::ParamType,
+ typename TupleTraits<B>::ParamType,
+ typename TupleTraits<C>::ParamType,
+ typename TupleTraits<D>::ParamType,
+ typename TupleTraits<E>::ParamType,
+ typename TupleTraits<F>::ParamType,
+ typename TupleTraits<G>::ParamType,
+ typename TupleTraits<H>::ParamType> ParamTuple;
+};
+
+// Tuple creators -------------------------------------------------------------
+//
+// Helper functions for constructing tuples while inferring the template
+// argument types.
+
+inline Tuple0 MakeTuple() {
+ return Tuple0();
+}
+
+template <class A>
+inline Tuple1<A> MakeTuple(const A& a) {
+ return Tuple1<A>(a);
+}
+
+template <class A, class B>
+inline Tuple2<A, B> MakeTuple(const A& a, const B& b) {
+ return Tuple2<A, B>(a, b);
+}
+
+template <class A, class B, class C>
+inline Tuple3<A, B, C> MakeTuple(const A& a, const B& b, const C& c) {
+ return Tuple3<A, B, C>(a, b, c);
+}
+
+template <class A, class B, class C, class D>
+inline Tuple4<A, B, C, D> MakeTuple(const A& a, const B& b, const C& c,
+ const D& d) {
+ return Tuple4<A, B, C, D>(a, b, c, d);
+}
+
+template <class A, class B, class C, class D, class E>
+inline Tuple5<A, B, C, D, E> MakeTuple(const A& a, const B& b, const C& c,
+ const D& d, const E& e) {
+ return Tuple5<A, B, C, D, E>(a, b, c, d, e);
+}
+
+template <class A, class B, class C, class D, class E, class F>
+inline Tuple6<A, B, C, D, E, F> MakeTuple(const A& a, const B& b, const C& c,
+ const D& d, const E& e, const F& f) {
+ return Tuple6<A, B, C, D, E, F>(a, b, c, d, e, f);
+}
+
+template <class A, class B, class C, class D, class E, class F, class G>
+inline Tuple7<A, B, C, D, E, F, G> MakeTuple(const A& a, const B& b, const C& c,
+ const D& d, const E& e, const F& f,
+ const G& g) {
+ return Tuple7<A, B, C, D, E, F, G>(a, b, c, d, e, f, g);
+}
+
+template <class A, class B, class C, class D, class E, class F, class G,
+ class H>
+inline Tuple8<A, B, C, D, E, F, G, H> MakeTuple(const A& a, const B& b,
+ const C& c, const D& d,
+ const E& e, const F& f,
+ const G& g, const H& h) {
+ return Tuple8<A, B, C, D, E, F, G, H>(a, b, c, d, e, f, g, h);
+}
+
+// The following set of helpers make what Boost refers to as "Tiers" - a tuple
+// of references.
+
+template <class A>
+inline Tuple1<A&> MakeRefTuple(A& a) {
+ return Tuple1<A&>(a);
+}
+
+template <class A, class B>
+inline Tuple2<A&, B&> MakeRefTuple(A& a, B& b) {
+ return Tuple2<A&, B&>(a, b);
+}
+
+template <class A, class B, class C>
+inline Tuple3<A&, B&, C&> MakeRefTuple(A& a, B& b, C& c) {
+ return Tuple3<A&, B&, C&>(a, b, c);
+}
+
+template <class A, class B, class C, class D>
+inline Tuple4<A&, B&, C&, D&> MakeRefTuple(A& a, B& b, C& c, D& d) {
+ return Tuple4<A&, B&, C&, D&>(a, b, c, d);
+}
+
+template <class A, class B, class C, class D, class E>
+inline Tuple5<A&, B&, C&, D&, E&> MakeRefTuple(A& a, B& b, C& c, D& d, E& e) {
+ return Tuple5<A&, B&, C&, D&, E&>(a, b, c, d, e);
+}
+
+template <class A, class B, class C, class D, class E, class F>
+inline Tuple6<A&, B&, C&, D&, E&, F&> MakeRefTuple(A& a, B& b, C& c, D& d, E& e,
+ F& f) {
+ return Tuple6<A&, B&, C&, D&, E&, F&>(a, b, c, d, e, f);
+}
+
+template <class A, class B, class C, class D, class E, class F, class G>
+inline Tuple7<A&, B&, C&, D&, E&, F&, G&> MakeRefTuple(A& a, B& b, C& c, D& d,
+ E& e, F& f, G& g) {
+ return Tuple7<A&, B&, C&, D&, E&, F&, G&>(a, b, c, d, e, f, g);
+}
+
+template <class A, class B, class C, class D, class E, class F, class G,
+ class H>
+inline Tuple8<A&, B&, C&, D&, E&, F&, G&, H&> MakeRefTuple(A& a, B& b, C& c,
+ D& d, E& e, F& f,
+ G& g, H& h) {
+ return Tuple8<A&, B&, C&, D&, E&, F&, G&, H&>(a, b, c, d, e, f, g, h);
+}
+
+// Dispatchers ----------------------------------------------------------------
+//
+// Helper functions that call the given method on an object, with the unpacked
+// tuple arguments. Notice that they all have the same number of arguments,
+// so you need only write:
+// DispatchToMethod(object, &Object::method, args);
+// This is very useful for templated dispatchers, since they don't need to know
+// what type |args| is.
+
+// Non-Static Dispatchers with no out params.
+
+template <class ObjT, class Method>
+inline void DispatchToMethod(ObjT* obj, Method method, const Tuple0& arg) {
+ (obj->*method)();
+}
+
+template <class ObjT, class Method, class A>
+inline void DispatchToMethod(ObjT* obj, Method method, const A& arg) {
+ (obj->*method)(arg);
+}
+
+template <class ObjT, class Method, class A>
+inline void DispatchToMethod(ObjT* obj, Method method, const Tuple1<A>& arg) {
+ (obj->*method)(arg.a);
+}
+
+template<class ObjT, class Method, class A, class B>
+inline void DispatchToMethod(ObjT* obj,
+ Method method,
+ const Tuple2<A, B>& arg) {
+ (obj->*method)(arg.a, arg.b);
+}
+
+template<class ObjT, class Method, class A, class B, class C>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple3<A, B, C>& arg) {
+ (obj->*method)(arg.a, arg.b, arg.c);
+}
+
+template<class ObjT, class Method, class A, class B, class C, class D>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple4<A, B, C, D>& arg) {
+ (obj->*method)(arg.a, arg.b, arg.c, arg.d);
+}
+
+template<class ObjT, class Method, class A, class B, class C, class D, class E>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple5<A, B, C, D, E>& arg) {
+ (obj->*method)(arg.a, arg.b, arg.c, arg.d, arg.e);
+}
+
+template<class ObjT, class Method, class A, class B, class C, class D, class E,
+ class F>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple6<A, B, C, D, E, F>& arg) {
+ (obj->*method)(arg.a, arg.b, arg.c, arg.d, arg.e, arg.f);
+}
+
+template<class ObjT, class Method, class A, class B, class C, class D, class E,
+ class F, class G>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple7<A, B, C, D, E, F, G>& arg) {
+ (obj->*method)(arg.a, arg.b, arg.c, arg.d, arg.e, arg.f, arg.g);
+}
+
+template<class ObjT, class Method, class A, class B, class C, class D, class E,
+ class F, class G, class H>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple8<A, B, C, D, E, F, G, H>& arg) {
+ (obj->*method)(arg.a, arg.b, arg.c, arg.d, arg.e, arg.f, arg.g, arg.h);
+}
+
+// Static Dispatchers with no out params.
+
+template <class Function>
+inline void DispatchToFunction(Function function, const Tuple0& arg) {
+ (*function)();
+}
+
+template <class Function, class A>
+inline void DispatchToFunction(Function function, const A& arg) {
+ (*function)(arg);
+}
+
+template <class Function, class A>
+inline void DispatchToFunction(Function function, const Tuple1<A>& arg) {
+ (*function)(arg.a);
+}
+
+template<class Function, class A, class B>
+inline void DispatchToFunction(Function function, const Tuple2<A, B>& arg) {
+ (*function)(arg.a, arg.b);
+}
+
+template<class Function, class A, class B, class C>
+inline void DispatchToFunction(Function function, const Tuple3<A, B, C>& arg) {
+ (*function)(arg.a, arg.b, arg.c);
+}
+
+template<class Function, class A, class B, class C, class D>
+inline void DispatchToFunction(Function function,
+ const Tuple4<A, B, C, D>& arg) {
+ (*function)(arg.a, arg.b, arg.c, arg.d);
+}
+
+template<class Function, class A, class B, class C, class D, class E>
+inline void DispatchToFunction(Function function,
+ const Tuple5<A, B, C, D, E>& arg) {
+ (*function)(arg.a, arg.b, arg.c, arg.d, arg.e);
+}
+
+template<class Function, class A, class B, class C, class D, class E, class F>
+inline void DispatchToFunction(Function function,
+ const Tuple6<A, B, C, D, E, F>& arg) {
+ (*function)(arg.a, arg.b, arg.c, arg.d, arg.e, arg.f);
+}
+
+template<class Function, class A, class B, class C, class D, class E, class F,
+ class G>
+inline void DispatchToFunction(Function function,
+ const Tuple7<A, B, C, D, E, F, G>& arg) {
+ (*function)(arg.a, arg.b, arg.c, arg.d, arg.e, arg.f, arg.g);
+}
+
+template<class Function, class A, class B, class C, class D, class E, class F,
+ class G, class H>
+inline void DispatchToFunction(Function function,
+ const Tuple8<A, B, C, D, E, F, G, H>& arg) {
+ (*function)(arg.a, arg.b, arg.c, arg.d, arg.e, arg.f, arg.g, arg.h);
+}
+
+// Dispatchers with 0 out param (as a Tuple0).
+
+template <class ObjT, class Method>
+inline void DispatchToMethod(ObjT* obj,
+ Method method,
+ const Tuple0& arg, Tuple0*) {
+ (obj->*method)();
+}
+
+template <class ObjT, class Method, class A>
+inline void DispatchToMethod(ObjT* obj, Method method, const A& arg, Tuple0*) {
+ (obj->*method)(arg);
+}
+
+template <class ObjT, class Method, class A>
+inline void DispatchToMethod(ObjT* obj,
+ Method method,
+ const Tuple1<A>& arg, Tuple0*) {
+ (obj->*method)(arg.a);
+}
+
+template<class ObjT, class Method, class A, class B>
+inline void DispatchToMethod(ObjT* obj,
+ Method method,
+ const Tuple2<A, B>& arg, Tuple0*) {
+ (obj->*method)(arg.a, arg.b);
+}
+
+template<class ObjT, class Method, class A, class B, class C>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple3<A, B, C>& arg, Tuple0*) {
+ (obj->*method)(arg.a, arg.b, arg.c);
+}
+
+template<class ObjT, class Method, class A, class B, class C, class D>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple4<A, B, C, D>& arg, Tuple0*) {
+ (obj->*method)(arg.a, arg.b, arg.c, arg.d);
+}
+
+template<class ObjT, class Method, class A, class B, class C, class D, class E>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple5<A, B, C, D, E>& arg, Tuple0*) {
+ (obj->*method)(arg.a, arg.b, arg.c, arg.d, arg.e);
+}
+
+template<class ObjT, class Method, class A, class B, class C, class D, class E,
+ class F>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple6<A, B, C, D, E, F>& arg, Tuple0*) {
+ (obj->*method)(arg.a, arg.b, arg.c, arg.d, arg.e, arg.f);
+}
+
+// Dispatchers with 1 out param.
+
+template<class ObjT, class Method,
+ class OutA>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple0& in,
+ Tuple1<OutA>* out) {
+ (obj->*method)(&out->a);
+}
+
+template<class ObjT, class Method, class InA,
+ class OutA>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const InA& in,
+ Tuple1<OutA>* out) {
+ (obj->*method)(in, &out->a);
+}
+
+template<class ObjT, class Method, class InA,
+ class OutA>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple1<InA>& in,
+ Tuple1<OutA>* out) {
+ (obj->*method)(in.a, &out->a);
+}
+
+template<class ObjT, class Method, class InA, class InB,
+ class OutA>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple2<InA, InB>& in,
+ Tuple1<OutA>* out) {
+ (obj->*method)(in.a, in.b, &out->a);
+}
+
+template<class ObjT, class Method, class InA, class InB, class InC,
+ class OutA>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple3<InA, InB, InC>& in,
+ Tuple1<OutA>* out) {
+ (obj->*method)(in.a, in.b, in.c, &out->a);
+}
+
+template<class ObjT, class Method, class InA, class InB, class InC, class InD,
+ class OutA>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple4<InA, InB, InC, InD>& in,
+ Tuple1<OutA>* out) {
+ (obj->*method)(in.a, in.b, in.c, in.d, &out->a);
+}
+
+template<class ObjT, class Method, class InA, class InB, class InC, class InD,
+ class InE, class OutA>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple5<InA, InB, InC, InD, InE>& in,
+ Tuple1<OutA>* out) {
+ (obj->*method)(in.a, in.b, in.c, in.d, in.e, &out->a);
+}
+
+template<class ObjT, class Method,
+ class InA, class InB, class InC, class InD, class InE, class InF,
+ class OutA>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple6<InA, InB, InC, InD, InE, InF>& in,
+ Tuple1<OutA>* out) {
+ (obj->*method)(in.a, in.b, in.c, in.d, in.e, in.f, &out->a);
+}
+
+// Dispatchers with 2 out params.
+
+template<class ObjT, class Method,
+ class OutA, class OutB>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple0& in,
+ Tuple2<OutA, OutB>* out) {
+ (obj->*method)(&out->a, &out->b);
+}
+
+template<class ObjT, class Method, class InA,
+ class OutA, class OutB>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const InA& in,
+ Tuple2<OutA, OutB>* out) {
+ (obj->*method)(in, &out->a, &out->b);
+}
+
+template<class ObjT, class Method, class InA,
+ class OutA, class OutB>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple1<InA>& in,
+ Tuple2<OutA, OutB>* out) {
+ (obj->*method)(in.a, &out->a, &out->b);
+}
+
+template<class ObjT, class Method, class InA, class InB,
+ class OutA, class OutB>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple2<InA, InB>& in,
+ Tuple2<OutA, OutB>* out) {
+ (obj->*method)(in.a, in.b, &out->a, &out->b);
+}
+
+template<class ObjT, class Method, class InA, class InB, class InC,
+ class OutA, class OutB>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple3<InA, InB, InC>& in,
+ Tuple2<OutA, OutB>* out) {
+ (obj->*method)(in.a, in.b, in.c, &out->a, &out->b);
+}
+
+template<class ObjT, class Method, class InA, class InB, class InC, class InD,
+ class OutA, class OutB>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple4<InA, InB, InC, InD>& in,
+ Tuple2<OutA, OutB>* out) {
+ (obj->*method)(in.a, in.b, in.c, in.d, &out->a, &out->b);
+}
+
+template<class ObjT, class Method,
+ class InA, class InB, class InC, class InD, class InE,
+ class OutA, class OutB>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple5<InA, InB, InC, InD, InE>& in,
+ Tuple2<OutA, OutB>* out) {
+ (obj->*method)(in.a, in.b, in.c, in.d, in.e, &out->a, &out->b);
+}
+
+template<class ObjT, class Method,
+ class InA, class InB, class InC, class InD, class InE, class InF,
+ class OutA, class OutB>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple6<InA, InB, InC, InD, InE, InF>& in,
+ Tuple2<OutA, OutB>* out) {
+ (obj->*method)(in.a, in.b, in.c, in.d, in.e, in.f, &out->a, &out->b);
+}
+
+// Dispatchers with 3 out params.
+
+template<class ObjT, class Method,
+ class OutA, class OutB, class OutC>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple0& in,
+ Tuple3<OutA, OutB, OutC>* out) {
+ (obj->*method)(&out->a, &out->b, &out->c);
+}
+
+template<class ObjT, class Method, class InA,
+ class OutA, class OutB, class OutC>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const InA& in,
+ Tuple3<OutA, OutB, OutC>* out) {
+ (obj->*method)(in, &out->a, &out->b, &out->c);
+}
+
+template<class ObjT, class Method, class InA,
+ class OutA, class OutB, class OutC>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple1<InA>& in,
+ Tuple3<OutA, OutB, OutC>* out) {
+ (obj->*method)(in.a, &out->a, &out->b, &out->c);
+}
+
+template<class ObjT, class Method, class InA, class InB,
+ class OutA, class OutB, class OutC>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple2<InA, InB>& in,
+ Tuple3<OutA, OutB, OutC>* out) {
+ (obj->*method)(in.a, in.b, &out->a, &out->b, &out->c);
+}
+
+template<class ObjT, class Method, class InA, class InB, class InC,
+ class OutA, class OutB, class OutC>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple3<InA, InB, InC>& in,
+ Tuple3<OutA, OutB, OutC>* out) {
+ (obj->*method)(in.a, in.b, in.c, &out->a, &out->b, &out->c);
+}
+
+template<class ObjT, class Method, class InA, class InB, class InC, class InD,
+ class OutA, class OutB, class OutC>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple4<InA, InB, InC, InD>& in,
+ Tuple3<OutA, OutB, OutC>* out) {
+ (obj->*method)(in.a, in.b, in.c, in.d, &out->a, &out->b, &out->c);
+}
+
+template<class ObjT, class Method,
+ class InA, class InB, class InC, class InD, class InE,
+ class OutA, class OutB, class OutC>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple5<InA, InB, InC, InD, InE>& in,
+ Tuple3<OutA, OutB, OutC>* out) {
+ (obj->*method)(in.a, in.b, in.c, in.d, in.e, &out->a, &out->b, &out->c);
+}
+
+template<class ObjT, class Method,
+ class InA, class InB, class InC, class InD, class InE, class InF,
+ class OutA, class OutB, class OutC>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple6<InA, InB, InC, InD, InE, InF>& in,
+ Tuple3<OutA, OutB, OutC>* out) {
+ (obj->*method)(in.a, in.b, in.c, in.d, in.e, in.f, &out->a, &out->b, &out->c);
+}
+
+// Dispatchers with 4 out params.
+
+template<class ObjT, class Method,
+ class OutA, class OutB, class OutC, class OutD>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple0& in,
+ Tuple4<OutA, OutB, OutC, OutD>* out) {
+ (obj->*method)(&out->a, &out->b, &out->c, &out->d);
+}
+
+template<class ObjT, class Method, class InA,
+ class OutA, class OutB, class OutC, class OutD>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const InA& in,
+ Tuple4<OutA, OutB, OutC, OutD>* out) {
+ (obj->*method)(in, &out->a, &out->b, &out->c, &out->d);
+}
+
+template<class ObjT, class Method, class InA,
+ class OutA, class OutB, class OutC, class OutD>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple1<InA>& in,
+ Tuple4<OutA, OutB, OutC, OutD>* out) {
+ (obj->*method)(in.a, &out->a, &out->b, &out->c, &out->d);
+}
+
+template<class ObjT, class Method, class InA, class InB,
+ class OutA, class OutB, class OutC, class OutD>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple2<InA, InB>& in,
+ Tuple4<OutA, OutB, OutC, OutD>* out) {
+ (obj->*method)(in.a, in.b, &out->a, &out->b, &out->c, &out->d);
+}
+
+template<class ObjT, class Method, class InA, class InB, class InC,
+ class OutA, class OutB, class OutC, class OutD>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple3<InA, InB, InC>& in,
+ Tuple4<OutA, OutB, OutC, OutD>* out) {
+ (obj->*method)(in.a, in.b, in.c, &out->a, &out->b, &out->c, &out->d);
+}
+
+template<class ObjT, class Method, class InA, class InB, class InC, class InD,
+ class OutA, class OutB, class OutC, class OutD>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple4<InA, InB, InC, InD>& in,
+ Tuple4<OutA, OutB, OutC, OutD>* out) {
+ (obj->*method)(in.a, in.b, in.c, in.d, &out->a, &out->b, &out->c, &out->d);
+}
+
+template<class ObjT, class Method,
+ class InA, class InB, class InC, class InD, class InE,
+ class OutA, class OutB, class OutC, class OutD>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple5<InA, InB, InC, InD, InE>& in,
+ Tuple4<OutA, OutB, OutC, OutD>* out) {
+ (obj->*method)(in.a, in.b, in.c, in.d, in.e,
+ &out->a, &out->b, &out->c, &out->d);
+}
+
+template<class ObjT, class Method,
+ class InA, class InB, class InC, class InD, class InE, class InF,
+ class OutA, class OutB, class OutC, class OutD>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple6<InA, InB, InC, InD, InE, InF>& in,
+ Tuple4<OutA, OutB, OutC, OutD>* out) {
+ (obj->*method)(in.a, in.b, in.c, in.d, in.e, in.f,
+ &out->a, &out->b, &out->c, &out->d);
+}
+
+// Dispatchers with 5 out params.
+
+template<class ObjT, class Method,
+ class OutA, class OutB, class OutC, class OutD, class OutE>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple0& in,
+ Tuple5<OutA, OutB, OutC, OutD, OutE>* out) {
+ (obj->*method)(&out->a, &out->b, &out->c, &out->d, &out->e);
+}
+
+template<class ObjT, class Method, class InA,
+ class OutA, class OutB, class OutC, class OutD, class OutE>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const InA& in,
+ Tuple5<OutA, OutB, OutC, OutD, OutE>* out) {
+ (obj->*method)(in, &out->a, &out->b, &out->c, &out->d, &out->e);
+}
+
+template<class ObjT, class Method, class InA,
+ class OutA, class OutB, class OutC, class OutD, class OutE>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple1<InA>& in,
+ Tuple5<OutA, OutB, OutC, OutD, OutE>* out) {
+ (obj->*method)(in.a, &out->a, &out->b, &out->c, &out->d, &out->e);
+}
+
+template<class ObjT, class Method, class InA, class InB,
+ class OutA, class OutB, class OutC, class OutD, class OutE>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple2<InA, InB>& in,
+ Tuple5<OutA, OutB, OutC, OutD, OutE>* out) {
+ (obj->*method)(in.a, in.b, &out->a, &out->b, &out->c, &out->d, &out->e);
+}
+
+template<class ObjT, class Method, class InA, class InB, class InC,
+ class OutA, class OutB, class OutC, class OutD, class OutE>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple3<InA, InB, InC>& in,
+ Tuple5<OutA, OutB, OutC, OutD, OutE>* out) {
+ (obj->*method)(in.a, in.b, in.c, &out->a, &out->b, &out->c, &out->d, &out->e);
+}
+
+template<class ObjT, class Method, class InA, class InB, class InC, class InD,
+ class OutA, class OutB, class OutC, class OutD, class OutE>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple4<InA, InB, InC, InD>& in,
+ Tuple5<OutA, OutB, OutC, OutD, OutE>* out) {
+ (obj->*method)(in.a, in.b, in.c, in.d, &out->a, &out->b, &out->c, &out->d,
+ &out->e);
+}
+
+template<class ObjT, class Method,
+ class InA, class InB, class InC, class InD, class InE,
+ class OutA, class OutB, class OutC, class OutD, class OutE>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple5<InA, InB, InC, InD, InE>& in,
+ Tuple5<OutA, OutB, OutC, OutD, OutE>* out) {
+ (obj->*method)(in.a, in.b, in.c, in.d, in.e,
+ &out->a, &out->b, &out->c, &out->d, &out->e);
+}
+
+template<class ObjT, class Method,
+ class InA, class InB, class InC, class InD, class InE, class InF,
+ class OutA, class OutB, class OutC, class OutD, class OutE>
+inline void DispatchToMethod(ObjT* obj, Method method,
+ const Tuple6<InA, InB, InC, InD, InE, InF>& in,
+ Tuple5<OutA, OutB, OutC, OutD, OutE>* out) {
+ (obj->*method)(in.a, in.b, in.c, in.d, in.e, in.f,
+ &out->a, &out->b, &out->c, &out->d, &out->e);
+}
+
+#endif // BASE_TUPLE_H__
diff --git a/base/values.cc b/base/values.cc
new file mode 100644
index 000000000000..7a364bd8ff0f
--- /dev/null
+++ b/base/values.cc
@@ -0,0 +1,905 @@
+// 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/values.h"
+
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "base/utf_string_conversions.h"
+
+namespace {
+
+// Make a deep copy of |node|, but don't include empty lists or dictionaries
+// in the copy. It's possible for this function to return NULL and it
+// expects |node| to always be non-NULL.
+Value* CopyWithoutEmptyChildren(Value* node) {
+ DCHECK(node);
+ switch (node->GetType()) {
+ case Value::TYPE_LIST: {
+ ListValue* list = static_cast<ListValue*>(node);
+ ListValue* copy = new ListValue;
+ for (ListValue::const_iterator it = list->begin(); it != list->end();
+ ++it) {
+ Value* child_copy = CopyWithoutEmptyChildren(*it);
+ if (child_copy)
+ copy->Append(child_copy);
+ }
+ if (!copy->empty())
+ return copy;
+
+ delete copy;
+ return NULL;
+ }
+
+ case Value::TYPE_DICTIONARY: {
+ DictionaryValue* dict = static_cast<DictionaryValue*>(node);
+ DictionaryValue* copy = new DictionaryValue;
+ for (DictionaryValue::key_iterator it = dict->begin_keys();
+ it != dict->end_keys(); ++it) {
+ Value* child = NULL;
+ bool rv = dict->GetWithoutPathExpansion(*it, &child);
+ DCHECK(rv);
+ Value* child_copy = CopyWithoutEmptyChildren(child);
+ if (child_copy)
+ copy->SetWithoutPathExpansion(*it, child_copy);
+ }
+ if (!copy->empty())
+ return copy;
+
+ delete copy;
+ return NULL;
+ }
+
+ default:
+ // For everything else, just make a copy.
+ return node->DeepCopy();
+ }
+}
+
+} // namespace
+
+namespace base {
+
+///////////////////// Value ////////////////////
+
+Value::~Value() {
+}
+
+// static
+Value* Value::CreateNullValue() {
+ return new Value(TYPE_NULL);
+}
+
+// static
+FundamentalValue* Value::CreateBooleanValue(bool in_value) {
+ return new FundamentalValue(in_value);
+}
+
+// static
+FundamentalValue* Value::CreateIntegerValue(int in_value) {
+ return new FundamentalValue(in_value);
+}
+
+// static
+FundamentalValue* Value::CreateDoubleValue(double in_value) {
+ return new FundamentalValue(in_value);
+}
+
+// static
+StringValue* Value::CreateStringValue(const std::string& in_value) {
+ return new StringValue(in_value);
+}
+
+// static
+StringValue* Value::CreateStringValue(const string16& in_value) {
+ return new StringValue(in_value);
+}
+
+bool Value::GetAsBoolean(bool* out_value) const {
+ return false;
+}
+
+bool Value::GetAsInteger(int* out_value) const {
+ return false;
+}
+
+bool Value::GetAsDouble(double* out_value) const {
+ return false;
+}
+
+bool Value::GetAsString(std::string* out_value) const {
+ return false;
+}
+
+bool Value::GetAsString(string16* out_value) const {
+ return false;
+}
+
+bool Value::GetAsList(ListValue** out_value) {
+ return false;
+}
+
+bool Value::GetAsList(const ListValue** out_value) const {
+ return false;
+}
+
+Value* Value::DeepCopy() const {
+ // This method should only be getting called for null Values--all subclasses
+ // need to provide their own implementation;.
+ DCHECK(IsType(TYPE_NULL));
+ return CreateNullValue();
+}
+
+bool Value::Equals(const Value* other) const {
+ // This method should only be getting called for null Values--all subclasses
+ // need to provide their own implementation;.
+ DCHECK(IsType(TYPE_NULL));
+ return other->IsType(TYPE_NULL);
+}
+
+// static
+bool Value::Equals(const Value* a, const Value* b) {
+ if ((a == NULL) && (b == NULL)) return true;
+ if ((a == NULL) ^ (b == NULL)) return false;
+ return a->Equals(b);
+}
+
+Value::Value(Type type) : type_(type) {
+}
+
+///////////////////// FundamentalValue ////////////////////
+
+FundamentalValue::FundamentalValue(bool in_value)
+ : Value(TYPE_BOOLEAN), boolean_value_(in_value) {
+}
+
+FundamentalValue::FundamentalValue(int in_value)
+ : Value(TYPE_INTEGER), integer_value_(in_value) {
+}
+
+FundamentalValue::FundamentalValue(double in_value)
+ : Value(TYPE_DOUBLE), double_value_(in_value) {
+}
+
+FundamentalValue::~FundamentalValue() {
+}
+
+bool FundamentalValue::GetAsBoolean(bool* out_value) const {
+ if (out_value && IsType(TYPE_BOOLEAN))
+ *out_value = boolean_value_;
+ return (IsType(TYPE_BOOLEAN));
+}
+
+bool FundamentalValue::GetAsInteger(int* out_value) const {
+ if (out_value && IsType(TYPE_INTEGER))
+ *out_value = integer_value_;
+ return (IsType(TYPE_INTEGER));
+}
+
+bool FundamentalValue::GetAsDouble(double* out_value) const {
+ if (out_value && IsType(TYPE_DOUBLE))
+ *out_value = double_value_;
+ else if (out_value && IsType(TYPE_INTEGER))
+ *out_value = integer_value_;
+ return (IsType(TYPE_DOUBLE) || IsType(TYPE_INTEGER));
+}
+
+FundamentalValue* FundamentalValue::DeepCopy() const {
+ switch (GetType()) {
+ case TYPE_BOOLEAN:
+ return CreateBooleanValue(boolean_value_);
+
+ case TYPE_INTEGER:
+ return CreateIntegerValue(integer_value_);
+
+ case TYPE_DOUBLE:
+ return CreateDoubleValue(double_value_);
+
+ default:
+ NOTREACHED();
+ return NULL;
+ }
+}
+
+bool FundamentalValue::Equals(const Value* other) const {
+ if (other->GetType() != GetType())
+ return false;
+
+ switch (GetType()) {
+ case TYPE_BOOLEAN: {
+ bool lhs, rhs;
+ return GetAsBoolean(&lhs) && other->GetAsBoolean(&rhs) && lhs == rhs;
+ }
+ case TYPE_INTEGER: {
+ int lhs, rhs;
+ return GetAsInteger(&lhs) && other->GetAsInteger(&rhs) && lhs == rhs;
+ }
+ case TYPE_DOUBLE: {
+ double lhs, rhs;
+ return GetAsDouble(&lhs) && other->GetAsDouble(&rhs) && lhs == rhs;
+ }
+ default:
+ NOTREACHED();
+ return false;
+ }
+}
+
+///////////////////// StringValue ////////////////////
+
+StringValue::StringValue(const std::string& in_value)
+ : Value(TYPE_STRING),
+ value_(in_value) {
+ DCHECK(IsStringUTF8(in_value));
+}
+
+StringValue::StringValue(const string16& in_value)
+ : Value(TYPE_STRING),
+ value_(UTF16ToUTF8(in_value)) {
+}
+
+StringValue::~StringValue() {
+}
+
+bool StringValue::GetAsString(std::string* out_value) const {
+ if (out_value)
+ *out_value = value_;
+ return true;
+}
+
+bool StringValue::GetAsString(string16* out_value) const {
+ if (out_value)
+ *out_value = UTF8ToUTF16(value_);
+ return true;
+}
+
+StringValue* StringValue::DeepCopy() const {
+ return CreateStringValue(value_);
+}
+
+bool StringValue::Equals(const Value* other) const {
+ if (other->GetType() != GetType())
+ return false;
+ std::string lhs, rhs;
+ return GetAsString(&lhs) && other->GetAsString(&rhs) && lhs == rhs;
+}
+
+///////////////////// BinaryValue ////////////////////
+
+BinaryValue::~BinaryValue() {
+ DCHECK(buffer_);
+ if (buffer_)
+ delete[] buffer_;
+}
+
+// static
+BinaryValue* BinaryValue::Create(char* buffer, size_t size) {
+ if (!buffer)
+ return NULL;
+
+ return new BinaryValue(buffer, size);
+}
+
+// static
+BinaryValue* BinaryValue::CreateWithCopiedBuffer(const char* buffer,
+ size_t size) {
+ if (!buffer)
+ return NULL;
+
+ char* buffer_copy = new char[size];
+ memcpy(buffer_copy, buffer, size);
+ return new BinaryValue(buffer_copy, size);
+}
+
+BinaryValue* BinaryValue::DeepCopy() const {
+ return CreateWithCopiedBuffer(buffer_, size_);
+}
+
+bool BinaryValue::Equals(const Value* other) const {
+ if (other->GetType() != GetType())
+ return false;
+ const BinaryValue* other_binary = static_cast<const BinaryValue*>(other);
+ if (other_binary->size_ != size_)
+ return false;
+ return !memcmp(buffer_, other_binary->buffer_, size_);
+}
+
+BinaryValue::BinaryValue(char* buffer, size_t size)
+ : Value(TYPE_BINARY),
+ buffer_(buffer),
+ size_(size) {
+ DCHECK(buffer_);
+}
+
+///////////////////// DictionaryValue ////////////////////
+
+DictionaryValue::DictionaryValue()
+ : Value(TYPE_DICTIONARY) {
+}
+
+DictionaryValue::~DictionaryValue() {
+ Clear();
+}
+
+bool DictionaryValue::HasKey(const std::string& key) const {
+ DCHECK(IsStringUTF8(key));
+ ValueMap::const_iterator current_entry = dictionary_.find(key);
+ DCHECK((current_entry == dictionary_.end()) || current_entry->second);
+ return current_entry != dictionary_.end();
+}
+
+void DictionaryValue::Clear() {
+ ValueMap::iterator dict_iterator = dictionary_.begin();
+ while (dict_iterator != dictionary_.end()) {
+ delete dict_iterator->second;
+ ++dict_iterator;
+ }
+
+ dictionary_.clear();
+}
+
+void DictionaryValue::Set(const std::string& path, Value* in_value) {
+ DCHECK(IsStringUTF8(path));
+ DCHECK(in_value);
+
+ std::string current_path(path);
+ DictionaryValue* current_dictionary = this;
+ for (size_t delimiter_position = current_path.find('.');
+ delimiter_position != std::string::npos;
+ delimiter_position = current_path.find('.')) {
+ // Assume that we're indexing into a dictionary.
+ std::string key(current_path, 0, delimiter_position);
+ DictionaryValue* child_dictionary = NULL;
+ if (!current_dictionary->GetDictionary(key, &child_dictionary)) {
+ child_dictionary = new DictionaryValue;
+ current_dictionary->SetWithoutPathExpansion(key, child_dictionary);
+ }
+
+ current_dictionary = child_dictionary;
+ current_path.erase(0, delimiter_position + 1);
+ }
+
+ current_dictionary->SetWithoutPathExpansion(current_path, in_value);
+}
+
+void DictionaryValue::SetBoolean(const std::string& path, bool in_value) {
+ Set(path, CreateBooleanValue(in_value));
+}
+
+void DictionaryValue::SetInteger(const std::string& path, int in_value) {
+ Set(path, CreateIntegerValue(in_value));
+}
+
+void DictionaryValue::SetDouble(const std::string& path, double in_value) {
+ Set(path, CreateDoubleValue(in_value));
+}
+
+void DictionaryValue::SetString(const std::string& path,
+ const std::string& in_value) {
+ Set(path, CreateStringValue(in_value));
+}
+
+void DictionaryValue::SetString(const std::string& path,
+ const string16& in_value) {
+ Set(path, CreateStringValue(in_value));
+}
+
+void DictionaryValue::SetWithoutPathExpansion(const std::string& key,
+ Value* in_value) {
+ // If there's an existing value here, we need to delete it, because
+ // we own all our children.
+ if (HasKey(key)) {
+ DCHECK(dictionary_[key] != in_value); // This would be bogus
+ delete dictionary_[key];
+ }
+
+ dictionary_[key] = in_value;
+}
+
+bool DictionaryValue::Get(const std::string& path, Value** out_value) const {
+ DCHECK(IsStringUTF8(path));
+ std::string current_path(path);
+ const DictionaryValue* current_dictionary = this;
+ for (size_t delimiter_position = current_path.find('.');
+ delimiter_position != std::string::npos;
+ delimiter_position = current_path.find('.')) {
+ DictionaryValue* child_dictionary = NULL;
+ if (!current_dictionary->GetDictionary(
+ current_path.substr(0, delimiter_position), &child_dictionary))
+ return false;
+
+ current_dictionary = child_dictionary;
+ current_path.erase(0, delimiter_position + 1);
+ }
+
+ return current_dictionary->GetWithoutPathExpansion(current_path, out_value);
+}
+
+bool DictionaryValue::GetBoolean(const std::string& path,
+ bool* bool_value) const {
+ Value* value;
+ if (!Get(path, &value))
+ return false;
+
+ return value->GetAsBoolean(bool_value);
+}
+
+bool DictionaryValue::GetInteger(const std::string& path,
+ int* out_value) const {
+ Value* value;
+ if (!Get(path, &value))
+ return false;
+
+ return value->GetAsInteger(out_value);
+}
+
+bool DictionaryValue::GetDouble(const std::string& path,
+ double* out_value) const {
+ Value* value;
+ if (!Get(path, &value))
+ return false;
+
+ return value->GetAsDouble(out_value);
+}
+
+bool DictionaryValue::GetString(const std::string& path,
+ std::string* out_value) const {
+ Value* value;
+ if (!Get(path, &value))
+ return false;
+
+ return value->GetAsString(out_value);
+}
+
+bool DictionaryValue::GetString(const std::string& path,
+ string16* out_value) const {
+ Value* value;
+ if (!Get(path, &value))
+ return false;
+
+ return value->GetAsString(out_value);
+}
+
+bool DictionaryValue::GetStringASCII(const std::string& path,
+ std::string* out_value) const {
+ std::string out;
+ if (!GetString(path, &out))
+ return false;
+
+ if (!IsStringASCII(out)) {
+ NOTREACHED();
+ return false;
+ }
+
+ out_value->assign(out);
+ return true;
+}
+
+bool DictionaryValue::GetBinary(const std::string& path,
+ BinaryValue** out_value) const {
+ Value* value;
+ bool result = Get(path, &value);
+ if (!result || !value->IsType(TYPE_BINARY))
+ return false;
+
+ if (out_value)
+ *out_value = static_cast<BinaryValue*>(value);
+
+ return true;
+}
+
+bool DictionaryValue::GetDictionary(const std::string& path,
+ DictionaryValue** out_value) const {
+ Value* value;
+ bool result = Get(path, &value);
+ if (!result || !value->IsType(TYPE_DICTIONARY))
+ return false;
+
+ if (out_value)
+ *out_value = static_cast<DictionaryValue*>(value);
+
+ return true;
+}
+
+bool DictionaryValue::GetList(const std::string& path,
+ ListValue** out_value) const {
+ Value* value;
+ bool result = Get(path, &value);
+ if (!result || !value->IsType(TYPE_LIST))
+ return false;
+
+ if (out_value)
+ *out_value = static_cast<ListValue*>(value);
+
+ return true;
+}
+
+bool DictionaryValue::GetWithoutPathExpansion(const std::string& key,
+ Value** out_value) const {
+ DCHECK(IsStringUTF8(key));
+ ValueMap::const_iterator entry_iterator = dictionary_.find(key);
+ if (entry_iterator == dictionary_.end())
+ return false;
+
+ Value* entry = entry_iterator->second;
+ if (out_value)
+ *out_value = entry;
+ return true;
+}
+
+bool DictionaryValue::GetIntegerWithoutPathExpansion(const std::string& key,
+ int* out_value) const {
+ Value* value;
+ if (!GetWithoutPathExpansion(key, &value))
+ return false;
+
+ return value->GetAsInteger(out_value);
+}
+
+bool DictionaryValue::GetDoubleWithoutPathExpansion(const std::string& key,
+ double* out_value) const {
+ Value* value;
+ if (!GetWithoutPathExpansion(key, &value))
+ return false;
+
+ return value->GetAsDouble(out_value);
+}
+
+bool DictionaryValue::GetStringWithoutPathExpansion(
+ const std::string& key,
+ std::string* out_value) const {
+ Value* value;
+ if (!GetWithoutPathExpansion(key, &value))
+ return false;
+
+ return value->GetAsString(out_value);
+}
+
+bool DictionaryValue::GetStringWithoutPathExpansion(
+ const std::string& key,
+ string16* out_value) const {
+ Value* value;
+ if (!GetWithoutPathExpansion(key, &value))
+ return false;
+
+ return value->GetAsString(out_value);
+}
+
+bool DictionaryValue::GetDictionaryWithoutPathExpansion(
+ const std::string& key,
+ DictionaryValue** out_value) const {
+ Value* value;
+ bool result = GetWithoutPathExpansion(key, &value);
+ if (!result || !value->IsType(TYPE_DICTIONARY))
+ return false;
+
+ if (out_value)
+ *out_value = static_cast<DictionaryValue*>(value);
+
+ return true;
+}
+
+bool DictionaryValue::GetListWithoutPathExpansion(const std::string& key,
+ ListValue** out_value) const {
+ Value* value;
+ bool result = GetWithoutPathExpansion(key, &value);
+ if (!result || !value->IsType(TYPE_LIST))
+ return false;
+
+ if (out_value)
+ *out_value = static_cast<ListValue*>(value);
+
+ return true;
+}
+
+bool DictionaryValue::Remove(const std::string& path, Value** out_value) {
+ DCHECK(IsStringUTF8(path));
+ std::string current_path(path);
+ DictionaryValue* current_dictionary = this;
+ size_t delimiter_position = current_path.rfind('.');
+ if (delimiter_position != std::string::npos) {
+ if (!GetDictionary(current_path.substr(0, delimiter_position),
+ &current_dictionary))
+ return false;
+ current_path.erase(0, delimiter_position + 1);
+ }
+
+ return current_dictionary->RemoveWithoutPathExpansion(current_path,
+ out_value);
+}
+
+bool DictionaryValue::RemoveWithoutPathExpansion(const std::string& key,
+ Value** out_value) {
+ DCHECK(IsStringUTF8(key));
+ ValueMap::iterator entry_iterator = dictionary_.find(key);
+ if (entry_iterator == dictionary_.end())
+ return false;
+
+ Value* entry = entry_iterator->second;
+ if (out_value)
+ *out_value = entry;
+ else
+ delete entry;
+ dictionary_.erase(entry_iterator);
+ return true;
+}
+
+DictionaryValue* DictionaryValue::DeepCopyWithoutEmptyChildren() {
+ Value* copy = CopyWithoutEmptyChildren(this);
+ return copy ? static_cast<DictionaryValue*>(copy) : new DictionaryValue;
+}
+
+void DictionaryValue::MergeDictionary(const DictionaryValue* dictionary) {
+ for (DictionaryValue::key_iterator key(dictionary->begin_keys());
+ key != dictionary->end_keys(); ++key) {
+ Value* merge_value;
+ if (dictionary->GetWithoutPathExpansion(*key, &merge_value)) {
+ // Check whether we have to merge dictionaries.
+ if (merge_value->IsType(Value::TYPE_DICTIONARY)) {
+ DictionaryValue* sub_dict;
+ if (GetDictionaryWithoutPathExpansion(*key, &sub_dict)) {
+ sub_dict->MergeDictionary(
+ static_cast<const DictionaryValue*>(merge_value));
+ continue;
+ }
+ }
+ // All other cases: Make a copy and hook it up.
+ SetWithoutPathExpansion(*key, merge_value->DeepCopy());
+ }
+ }
+}
+
+DictionaryValue* DictionaryValue::DeepCopy() const {
+ DictionaryValue* result = new DictionaryValue;
+
+ for (ValueMap::const_iterator current_entry(dictionary_.begin());
+ current_entry != dictionary_.end(); ++current_entry) {
+ result->SetWithoutPathExpansion(current_entry->first,
+ current_entry->second->DeepCopy());
+ }
+
+ return result;
+}
+
+bool DictionaryValue::Equals(const Value* other) const {
+ if (other->GetType() != GetType())
+ return false;
+
+ const DictionaryValue* other_dict =
+ static_cast<const DictionaryValue*>(other);
+ key_iterator lhs_it(begin_keys());
+ key_iterator rhs_it(other_dict->begin_keys());
+ while (lhs_it != end_keys() && rhs_it != other_dict->end_keys()) {
+ Value* lhs;
+ Value* rhs;
+ if (*lhs_it != *rhs_it ||
+ !GetWithoutPathExpansion(*lhs_it, &lhs) ||
+ !other_dict->GetWithoutPathExpansion(*rhs_it, &rhs) ||
+ !lhs->Equals(rhs)) {
+ return false;
+ }
+ ++lhs_it;
+ ++rhs_it;
+ }
+ if (lhs_it != end_keys() || rhs_it != other_dict->end_keys())
+ return false;
+
+ return true;
+}
+
+///////////////////// ListValue ////////////////////
+
+ListValue::ListValue() : Value(TYPE_LIST) {
+}
+
+ListValue::~ListValue() {
+ Clear();
+}
+
+void ListValue::Clear() {
+ for (ValueVector::iterator i(list_.begin()); i != list_.end(); ++i)
+ delete *i;
+ list_.clear();
+}
+
+bool ListValue::Set(size_t index, Value* in_value) {
+ if (!in_value)
+ return false;
+
+ if (index >= list_.size()) {
+ // Pad out any intermediate indexes with null settings
+ while (index > list_.size())
+ Append(CreateNullValue());
+ Append(in_value);
+ } else {
+ DCHECK(list_[index] != in_value);
+ delete list_[index];
+ list_[index] = in_value;
+ }
+ return true;
+}
+
+bool ListValue::Get(size_t index, Value** out_value) const {
+ if (index >= list_.size())
+ return false;
+
+ if (out_value)
+ *out_value = list_[index];
+
+ return true;
+}
+
+bool ListValue::GetBoolean(size_t index, bool* bool_value) const {
+ Value* value;
+ if (!Get(index, &value))
+ return false;
+
+ return value->GetAsBoolean(bool_value);
+}
+
+bool ListValue::GetInteger(size_t index, int* out_value) const {
+ Value* value;
+ if (!Get(index, &value))
+ return false;
+
+ return value->GetAsInteger(out_value);
+}
+
+bool ListValue::GetDouble(size_t index, double* out_value) const {
+ Value* value;
+ if (!Get(index, &value))
+ return false;
+
+ return value->GetAsDouble(out_value);
+}
+
+bool ListValue::GetString(size_t index, std::string* out_value) const {
+ Value* value;
+ if (!Get(index, &value))
+ return false;
+
+ return value->GetAsString(out_value);
+}
+
+bool ListValue::GetString(size_t index, string16* out_value) const {
+ Value* value;
+ if (!Get(index, &value))
+ return false;
+
+ return value->GetAsString(out_value);
+}
+
+bool ListValue::GetBinary(size_t index, BinaryValue** out_value) const {
+ Value* value;
+ bool result = Get(index, &value);
+ if (!result || !value->IsType(TYPE_BINARY))
+ return false;
+
+ if (out_value)
+ *out_value = static_cast<BinaryValue*>(value);
+
+ return true;
+}
+
+bool ListValue::GetDictionary(size_t index, DictionaryValue** out_value) const {
+ Value* value;
+ bool result = Get(index, &value);
+ if (!result || !value->IsType(TYPE_DICTIONARY))
+ return false;
+
+ if (out_value)
+ *out_value = static_cast<DictionaryValue*>(value);
+
+ return true;
+}
+
+bool ListValue::GetList(size_t index, ListValue** out_value) const {
+ Value* value;
+ bool result = Get(index, &value);
+ if (!result || !value->IsType(TYPE_LIST))
+ return false;
+
+ if (out_value)
+ *out_value = static_cast<ListValue*>(value);
+
+ return true;
+}
+
+bool ListValue::Remove(size_t index, Value** out_value) {
+ if (index >= list_.size())
+ return false;
+
+ if (out_value)
+ *out_value = list_[index];
+ else
+ delete list_[index];
+
+ list_.erase(list_.begin() + index);
+ return true;
+}
+
+bool ListValue::Remove(const Value& value, size_t* index) {
+ for (ValueVector::iterator i(list_.begin()); i != list_.end(); ++i) {
+ if ((*i)->Equals(&value)) {
+ size_t previous_index = i - list_.begin();
+ delete *i;
+ list_.erase(i);
+
+ if (index)
+ *index = previous_index;
+ return true;
+ }
+ }
+ return false;
+}
+
+void ListValue::Append(Value* in_value) {
+ DCHECK(in_value);
+ list_.push_back(in_value);
+}
+
+bool ListValue::AppendIfNotPresent(Value* in_value) {
+ DCHECK(in_value);
+ for (ValueVector::const_iterator i(list_.begin()); i != list_.end(); ++i) {
+ if ((*i)->Equals(in_value)) {
+ delete in_value;
+ return false;
+ }
+ }
+ list_.push_back(in_value);
+ return true;
+}
+
+bool ListValue::Insert(size_t index, Value* in_value) {
+ DCHECK(in_value);
+ if (index > list_.size())
+ return false;
+
+ list_.insert(list_.begin() + index, in_value);
+ return true;
+}
+
+bool ListValue::GetAsList(ListValue** out_value) {
+ if (out_value)
+ *out_value = this;
+ return true;
+}
+
+bool ListValue::GetAsList(const ListValue** out_value) const {
+ if (out_value)
+ *out_value = this;
+ return true;
+}
+
+ListValue* ListValue::DeepCopy() const {
+ ListValue* result = new ListValue;
+
+ for (ValueVector::const_iterator i(list_.begin()); i != list_.end(); ++i)
+ result->Append((*i)->DeepCopy());
+
+ return result;
+}
+
+bool ListValue::Equals(const Value* other) const {
+ if (other->GetType() != GetType())
+ return false;
+
+ const ListValue* other_list =
+ static_cast<const ListValue*>(other);
+ const_iterator lhs_it, rhs_it;
+ for (lhs_it = begin(), rhs_it = other_list->begin();
+ lhs_it != end() && rhs_it != other_list->end();
+ ++lhs_it, ++rhs_it) {
+ if (!(*lhs_it)->Equals(*rhs_it))
+ return false;
+ }
+ if (lhs_it != end() || rhs_it != other_list->end())
+ return false;
+
+ return true;
+}
+
+ValueSerializer::~ValueSerializer() {
+}
+
+} // namespace base
diff --git a/base/values.h b/base/values.h
new file mode 100644
index 000000000000..a30791bc6357
--- /dev/null
+++ b/base/values.h
@@ -0,0 +1,470 @@
+// 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 specifies a recursive data storage class called Value intended for
+// storing setting and other persistable data. It includes the ability to
+// specify (recursive) lists and dictionaries, so it's fairly expressive.
+// However, the API is optimized for the common case, namely storing a
+// hierarchical tree of simple values. Given a DictionaryValue root, you can
+// easily do things like:
+//
+// root->SetString("global.pages.homepage", "http://goateleporter.com");
+// std::string homepage = "http://google.com"; // default/fallback value
+// root->GetString("global.pages.homepage", &homepage);
+//
+// where "global" and "pages" are also DictionaryValues, and "homepage" is a
+// string setting. If some elements of the path didn't exist yet, the
+// SetString() method would create the missing elements and attach them to root
+// before attaching the homepage value.
+
+#ifndef BASE_VALUES_H_
+#define BASE_VALUES_H_
+#pragma once
+
+#include <iterator>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/string16.h"
+
+// This file declares "using base::Value", etc. at the bottom, so that
+// current code can use these classes without the base namespace. In
+// new code, please always use base::Value, etc. or add your own
+// "using" declaration.
+// http://crbug.com/88666
+namespace base {
+
+class BinaryValue;
+class DictionaryValue;
+class FundamentalValue;
+class ListValue;
+class StringValue;
+class Value;
+
+typedef std::vector<Value*> ValueVector;
+typedef std::map<std::string, Value*> ValueMap;
+
+// The Value class is the base class for Values. A Value can be instantiated
+// via the Create*Value() factory methods, or by directly creating instances of
+// the subclasses.
+class BASE_EXPORT Value {
+ public:
+ enum Type {
+ TYPE_NULL = 0,
+ TYPE_BOOLEAN,
+ TYPE_INTEGER,
+ TYPE_DOUBLE,
+ TYPE_STRING,
+ TYPE_BINARY,
+ TYPE_DICTIONARY,
+ TYPE_LIST
+ };
+
+ virtual ~Value();
+
+ // Convenience methods for creating Value objects for various
+ // kinds of values without thinking about which class implements them.
+ // These can always be expected to return a valid Value*.
+ static Value* CreateNullValue();
+ static FundamentalValue* CreateBooleanValue(bool in_value);
+ static FundamentalValue* CreateIntegerValue(int in_value);
+ static FundamentalValue* CreateDoubleValue(double in_value);
+ static StringValue* CreateStringValue(const std::string& in_value);
+ static StringValue* CreateStringValue(const string16& in_value);
+
+ // Returns the type of the value stored by the current Value object.
+ // Each type will be implemented by only one subclass of Value, so it's
+ // safe to use the Type to determine whether you can cast from
+ // Value* to (Implementing Class)*. Also, a Value object never changes
+ // its type after construction.
+ Type GetType() const { return type_; }
+
+ // Returns true if the current object represents a given type.
+ bool IsType(Type type) const { return type == type_; }
+
+ // These methods allow the convenient retrieval of settings.
+ // If the current setting object can be converted into the given type,
+ // the value is returned through the |out_value| parameter and true is
+ // returned; otherwise, false is returned and |out_value| is unchanged.
+ virtual bool GetAsBoolean(bool* out_value) const;
+ virtual bool GetAsInteger(int* out_value) const;
+ virtual bool GetAsDouble(double* out_value) const;
+ virtual bool GetAsString(std::string* out_value) const;
+ virtual bool GetAsString(string16* out_value) const;
+ virtual bool GetAsList(ListValue** out_value);
+ virtual bool GetAsList(const ListValue** out_value) const;
+
+ // This creates a deep copy of the entire Value tree, and returns a pointer
+ // to the copy. The caller gets ownership of the copy, of course.
+ //
+ // Subclasses return their own type directly in their overrides;
+ // this works because C++ supports covariant return types.
+ virtual Value* DeepCopy() const;
+
+ // Compares if two Value objects have equal contents.
+ virtual bool Equals(const Value* other) const;
+
+ // Compares if two Value objects have equal contents. Can handle NULLs.
+ // NULLs are considered equal but different from Value::CreateNullValue().
+ static bool Equals(const Value* a, const Value* b);
+
+ protected:
+ // This isn't safe for end-users (they should use the Create*Value()
+ // static methods above), but it's useful for subclasses.
+ explicit Value(Type type);
+
+ private:
+ Value();
+
+ Type type_;
+
+ DISALLOW_COPY_AND_ASSIGN(Value);
+};
+
+// FundamentalValue represents the simple fundamental types of values.
+class BASE_EXPORT FundamentalValue : public Value {
+ public:
+ explicit FundamentalValue(bool in_value);
+ explicit FundamentalValue(int in_value);
+ explicit FundamentalValue(double in_value);
+ virtual ~FundamentalValue();
+
+ // Overridden from Value:
+ virtual bool GetAsBoolean(bool* out_value) const OVERRIDE;
+ virtual bool GetAsInteger(int* out_value) const OVERRIDE;
+ virtual bool GetAsDouble(double* out_value) const OVERRIDE;
+ virtual FundamentalValue* DeepCopy() const OVERRIDE;
+ virtual bool Equals(const Value* other) const OVERRIDE;
+
+ private:
+ union {
+ bool boolean_value_;
+ int integer_value_;
+ double double_value_;
+ };
+
+ DISALLOW_COPY_AND_ASSIGN(FundamentalValue);
+};
+
+class BASE_EXPORT StringValue : public Value {
+ public:
+ // Initializes a StringValue with a UTF-8 narrow character string.
+ explicit StringValue(const std::string& in_value);
+
+ // Initializes a StringValue with a string16.
+ explicit StringValue(const string16& in_value);
+
+ virtual ~StringValue();
+
+ // Overridden from Value:
+ virtual bool GetAsString(std::string* out_value) const OVERRIDE;
+ virtual bool GetAsString(string16* out_value) const OVERRIDE;
+ virtual StringValue* DeepCopy() const OVERRIDE;
+ virtual bool Equals(const Value* other) const OVERRIDE;
+
+ private:
+ std::string value_;
+
+ DISALLOW_COPY_AND_ASSIGN(StringValue);
+};
+
+class BASE_EXPORT BinaryValue: public Value {
+ public:
+ virtual ~BinaryValue();
+
+ // Creates a Value to represent a binary buffer. The new object takes
+ // ownership of the pointer passed in, if successful.
+ // Returns NULL if buffer is NULL.
+ static BinaryValue* Create(char* buffer, size_t size);
+
+ // For situations where you want to keep ownership of your buffer, this
+ // factory method creates a new BinaryValue by copying the contents of the
+ // buffer that's passed in.
+ // Returns NULL if buffer is NULL.
+ static BinaryValue* CreateWithCopiedBuffer(const char* buffer, size_t size);
+
+ size_t GetSize() const { return size_; }
+ char* GetBuffer() { return buffer_; }
+ const char* GetBuffer() const { return buffer_; }
+
+ // Overridden from Value:
+ virtual BinaryValue* DeepCopy() const OVERRIDE;
+ virtual bool Equals(const Value* other) const OVERRIDE;
+
+ private:
+ // Constructor is private so that only objects with valid buffer pointers
+ // and size values can be created.
+ BinaryValue(char* buffer, size_t size);
+
+ char* buffer_;
+ size_t size_;
+
+ DISALLOW_COPY_AND_ASSIGN(BinaryValue);
+};
+
+// DictionaryValue provides a key-value dictionary with (optional) "path"
+// parsing for recursive access; see the comment at the top of the file. Keys
+// are |std::string|s and should be UTF-8 encoded.
+class BASE_EXPORT DictionaryValue : public Value {
+ public:
+ DictionaryValue();
+ virtual ~DictionaryValue();
+
+ // Returns true if the current dictionary has a value for the given key.
+ bool HasKey(const std::string& key) const;
+
+ // Returns the number of Values in this dictionary.
+ size_t size() const { return dictionary_.size(); }
+
+ // Returns whether the dictionary is empty.
+ bool empty() const { return dictionary_.empty(); }
+
+ // Clears any current contents of this dictionary.
+ void Clear();
+
+ // Sets the Value associated with the given path starting from this object.
+ // A path has the form "<key>" or "<key>.<key>.[...]", where "." indexes
+ // into the next DictionaryValue down. Obviously, "." can't be used
+ // within a key, but there are no other restrictions on keys.
+ // If the key at any step of the way doesn't exist, or exists but isn't
+ // a DictionaryValue, a new DictionaryValue will be created and attached
+ // to the path in that location.
+ // Note that the dictionary takes ownership of the value referenced by
+ // |in_value|, and therefore |in_value| must be non-NULL.
+ void Set(const std::string& path, Value* in_value);
+
+ // Convenience forms of Set(). These methods will replace any existing
+ // value at that path, even if it has a different type.
+ void SetBoolean(const std::string& path, bool in_value);
+ void SetInteger(const std::string& path, int in_value);
+ void SetDouble(const std::string& path, double in_value);
+ void SetString(const std::string& path, const std::string& in_value);
+ void SetString(const std::string& path, const string16& in_value);
+
+ // Like Set(), but without special treatment of '.'. This allows e.g. URLs to
+ // be used as paths.
+ void SetWithoutPathExpansion(const std::string& key, Value* in_value);
+
+ // Gets the Value associated with the given path starting from this object.
+ // A path has the form "<key>" or "<key>.<key>.[...]", where "." indexes
+ // into the next DictionaryValue down. If the path can be resolved
+ // successfully, the value for the last key in the path will be returned
+ // through the |out_value| parameter, and the function will return true.
+ // Otherwise, it will return false and |out_value| will be untouched.
+ // Note that the dictionary always owns the value that's returned.
+ bool Get(const std::string& path, Value** out_value) const;
+
+ // These are convenience forms of Get(). The value will be retrieved
+ // and the return value will be true if the path is valid and the value at
+ // the end of the path can be returned in the form specified.
+ bool GetBoolean(const std::string& path, bool* out_value) const;
+ bool GetInteger(const std::string& path, int* out_value) const;
+ bool GetDouble(const std::string& path, double* out_value) const;
+ bool GetString(const std::string& path, std::string* out_value) const;
+ bool GetString(const std::string& path, string16* out_value) const;
+ bool GetStringASCII(const std::string& path, std::string* out_value) const;
+ bool GetBinary(const std::string& path, BinaryValue** out_value) const;
+ bool GetDictionary(const std::string& path,
+ DictionaryValue** out_value) const;
+ bool GetList(const std::string& path, ListValue** out_value) const;
+
+ // Like Get(), but without special treatment of '.'. This allows e.g. URLs to
+ // be used as paths.
+ bool GetWithoutPathExpansion(const std::string& key,
+ Value** out_value) const;
+ bool GetIntegerWithoutPathExpansion(const std::string& key,
+ int* out_value) const;
+ bool GetDoubleWithoutPathExpansion(const std::string& key,
+ double* out_value) const;
+ bool GetStringWithoutPathExpansion(const std::string& key,
+ std::string* out_value) const;
+ bool GetStringWithoutPathExpansion(const std::string& key,
+ string16* out_value) const;
+ bool GetDictionaryWithoutPathExpansion(const std::string& key,
+ DictionaryValue** out_value) const;
+ bool GetListWithoutPathExpansion(const std::string& key,
+ ListValue** out_value) const;
+
+ // Removes the Value with the specified path from this dictionary (or one
+ // of its child dictionaries, if the path is more than just a local key).
+ // If |out_value| is non-NULL, the removed Value AND ITS OWNERSHIP will be
+ // passed out via out_value. If |out_value| is NULL, the removed value will
+ // be deleted. This method returns true if |path| is a valid path; otherwise
+ // it will return false and the DictionaryValue object will be unchanged.
+ bool Remove(const std::string& path, Value** out_value);
+
+ // Like Remove(), but without special treatment of '.'. This allows e.g. URLs
+ // to be used as paths.
+ bool RemoveWithoutPathExpansion(const std::string& key, Value** out_value);
+
+ // Makes a copy of |this| but doesn't include empty dictionaries and lists in
+ // the copy. This never returns NULL, even if |this| itself is empty.
+ DictionaryValue* DeepCopyWithoutEmptyChildren();
+
+ // Merge a given dictionary into this dictionary. This is done recursively,
+ // i.e. any subdictionaries will be merged as well. In case of key collisions,
+ // the passed in dictionary takes precedence and data already present will be
+ // replaced.
+ void MergeDictionary(const DictionaryValue* dictionary);
+
+ // Swaps contents with the |other| dictionary.
+ void Swap(DictionaryValue* other) {
+ dictionary_.swap(other->dictionary_);
+ }
+
+ // This class provides an iterator for the keys in the dictionary.
+ // It can't be used to modify the dictionary.
+ //
+ // YOU SHOULD ALWAYS USE THE XXXWithoutPathExpansion() APIs WITH THESE, NOT
+ // THE NORMAL XXX() APIs. This makes sure things will work correctly if any
+ // keys have '.'s in them.
+ class key_iterator
+ : private std::iterator<std::input_iterator_tag, const std::string> {
+ public:
+ explicit key_iterator(ValueMap::const_iterator itr) { itr_ = itr; }
+ key_iterator operator++() {
+ ++itr_;
+ return *this;
+ }
+ const std::string& operator*() { return itr_->first; }
+ bool operator!=(const key_iterator& other) { return itr_ != other.itr_; }
+ bool operator==(const key_iterator& other) { return itr_ == other.itr_; }
+
+ private:
+ ValueMap::const_iterator itr_;
+ };
+
+ key_iterator begin_keys() const { return key_iterator(dictionary_.begin()); }
+ key_iterator end_keys() const { return key_iterator(dictionary_.end()); }
+
+ // Overridden from Value:
+ virtual DictionaryValue* DeepCopy() const OVERRIDE;
+ virtual bool Equals(const Value* other) const OVERRIDE;
+
+ private:
+ ValueMap dictionary_;
+
+ DISALLOW_COPY_AND_ASSIGN(DictionaryValue);
+};
+
+// This type of Value represents a list of other Value values.
+class BASE_EXPORT ListValue : public Value {
+ public:
+ typedef ValueVector::iterator iterator;
+ typedef ValueVector::const_iterator const_iterator;
+
+ ListValue();
+ virtual ~ListValue();
+
+ // Clears the contents of this ListValue
+ void Clear();
+
+ // Returns the number of Values in this list.
+ size_t GetSize() const { return list_.size(); }
+
+ // Returns whether the list is empty.
+ bool empty() const { return list_.empty(); }
+
+ // Sets the list item at the given index to be the Value specified by
+ // the value given. If the index beyond the current end of the list, null
+ // Values will be used to pad out the list.
+ // Returns true if successful, or false if the index was negative or
+ // the value is a null pointer.
+ bool Set(size_t index, Value* in_value);
+
+ // Gets the Value at the given index. Modifies |out_value| (and returns true)
+ // only if the index falls within the current list range.
+ // Note that the list always owns the Value passed out via |out_value|.
+ bool Get(size_t index, Value** out_value) const;
+
+ // Convenience forms of Get(). Modifies |out_value| (and returns true)
+ // only if the index is valid and the Value at that index can be returned
+ // in the specified form.
+ bool GetBoolean(size_t index, bool* out_value) const;
+ bool GetInteger(size_t index, int* out_value) const;
+ bool GetDouble(size_t index, double* out_value) const;
+ bool GetString(size_t index, std::string* out_value) const;
+ bool GetString(size_t index, string16* out_value) const;
+ bool GetBinary(size_t index, BinaryValue** out_value) const;
+ bool GetDictionary(size_t index, DictionaryValue** out_value) const;
+ bool GetList(size_t index, ListValue** out_value) const;
+
+ // Removes the Value with the specified index from this list.
+ // If |out_value| is non-NULL, the removed Value AND ITS OWNERSHIP will be
+ // passed out via |out_value|. If |out_value| is NULL, the removed value will
+ // be deleted. This method returns true if |index| is valid; otherwise
+ // it will return false and the ListValue object will be unchanged.
+ bool Remove(size_t index, Value** out_value);
+
+ // Removes the first instance of |value| found in the list, if any, and
+ // deletes it. |index| is the location where |value| was found. Returns false
+ // if not found.
+ bool Remove(const Value& value, size_t* index);
+
+ // Appends a Value to the end of the list.
+ void Append(Value* in_value);
+
+ // Appends a Value if it's not already present. Takes ownership of the
+ // |in_value|. Returns true if successful, or false if the value was already
+ // present. If the value was already present the |in_value| is deleted.
+ bool AppendIfNotPresent(Value* in_value);
+
+ // Insert a Value at index.
+ // Returns true if successful, or false if the index was out of range.
+ bool Insert(size_t index, Value* in_value);
+
+ // Swaps contents with the |other| list.
+ void Swap(ListValue* other) {
+ list_.swap(other->list_);
+ }
+
+ // Iteration.
+ iterator begin() { return list_.begin(); }
+ iterator end() { return list_.end(); }
+
+ const_iterator begin() const { return list_.begin(); }
+ const_iterator end() const { return list_.end(); }
+
+ // Overridden from Value:
+ virtual bool GetAsList(ListValue** out_value) OVERRIDE;
+ virtual bool GetAsList(const ListValue** out_value) const OVERRIDE;
+ virtual ListValue* DeepCopy() const OVERRIDE;
+ virtual bool Equals(const Value* other) const OVERRIDE;
+
+ private:
+ ValueVector list_;
+
+ DISALLOW_COPY_AND_ASSIGN(ListValue);
+};
+
+// This interface is implemented by classes that know how to serialize and
+// deserialize Value objects.
+class BASE_EXPORT ValueSerializer {
+ public:
+ virtual ~ValueSerializer();
+
+ virtual bool Serialize(const Value& root) = 0;
+
+ // This method deserializes the subclass-specific format into a Value object.
+ // If the return value is non-NULL, the caller takes ownership of returned
+ // Value. If the return value is NULL, and if error_code is non-NULL,
+ // 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;
+};
+
+} // namespace base
+
+// http://crbug.com/88666
+using base::DictionaryValue;
+using base::ListValue;
+using base::StringValue;
+using base::Value;
+
+#endif // BASE_VALUES_H_
diff --git a/build/build_config.h b/build/build_config.h
new file mode 100644
index 000000000000..ce5ac6a138de
--- /dev/null
+++ b/build/build_config.h
@@ -0,0 +1,151 @@
+// 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 adds defines about the platform we're currently building on.
+// Operating System:
+// OS_WIN / OS_MACOSX / OS_LINUX / OS_POSIX (MACOSX or LINUX)
+// Compiler:
+// COMPILER_MSVC / COMPILER_GCC
+// Processor:
+// ARCH_CPU_X86 / ARCH_CPU_X86_64 / ARCH_CPU_X86_FAMILY (X86 or X86_64)
+// ARCH_CPU_32_BITS / ARCH_CPU_64_BITS
+
+#ifndef BUILD_BUILD_CONFIG_H_
+#define BUILD_BUILD_CONFIG_H_
+
+// A set of macros to use for platform detection.
+#if defined(__APPLE__)
+#define OS_MACOSX 1
+#elif defined(ANDROID)
+#define OS_ANDROID 1
+#elif defined(__native_client__)
+#define OS_NACL 1
+#elif defined(__linux__)
+#define OS_LINUX 1
+// Use TOOLKIT_GTK on linux if TOOLKIT_VIEWS isn't defined.
+#if !defined(TOOLKIT_VIEWS)
+#define TOOLKIT_GTK
+#endif
+#elif defined(_WIN32)
+#define OS_WIN 1
+#define TOOLKIT_VIEWS 1
+#elif defined(__FreeBSD__)
+#define OS_FREEBSD 1
+#define TOOLKIT_GTK
+#elif defined(__OpenBSD__)
+#define OS_OPENBSD 1
+#define TOOLKIT_GTK
+#elif defined(__sun)
+#define OS_SOLARIS 1
+#define TOOLKIT_GTK
+#else
+#error Please add support for your platform in build/build_config.h
+#endif
+
+// A flag derived from the above flags, used to cover GTK code in
+// both TOOLKIT_GTK and TOOLKIT_VIEWS.
+#if defined(TOOLKIT_GTK) || (defined(TOOLKIT_VIEWS) && !defined(OS_WIN))
+#define TOOLKIT_USES_GTK 1
+#endif
+
+#if defined(OS_LINUX) || defined(OS_FREEBSD) || defined(OS_OPENBSD) || \
+ defined(OS_SOLARIS) || defined(OS_ANDROID)
+#if !defined(USE_OPENSSL)
+#define USE_NSS 1 // Default to use NSS for crypto, unless OpenSSL is chosen.
+#endif
+#ifndef OS_ANDROID
+#define USE_X11 1 // Use X for graphics.
+#endif
+#endif
+
+#if defined(USE_OPENSSL) && defined(USE_NSS)
+#error Cannot use both OpenSSL and NSS
+#endif
+
+// For access to standard POSIXish features, use OS_POSIX instead of a
+// more specific macro.
+#if defined(OS_MACOSX) || defined(OS_LINUX) || defined(OS_FREEBSD) || \
+ defined(OS_OPENBSD) || defined(OS_SOLARIS) || defined(OS_ANDROID) || \
+ defined(OS_NACL)
+#define OS_POSIX 1
+#endif
+
+// Use tcmalloc
+#if (defined(OS_WIN) || defined(OS_LINUX)) && !defined(NO_TCMALLOC)
+#define USE_TCMALLOC 1
+#endif
+
+// Use heapchecker.
+#if defined(OS_LINUX) && !defined(NO_HEAPCHECKER)
+#define USE_HEAPCHECKER 1
+#endif
+
+// Compiler detection.
+#if defined(__GNUC__)
+#define COMPILER_GCC 1
+#elif defined(_MSC_VER)
+#define COMPILER_MSVC 1
+#else
+#error Please add support for your compiler in build/build_config.h
+#endif
+
+// Processor architecture detection. For more info on what's defined, see:
+// http://msdn.microsoft.com/en-us/library/b0084kay.aspx
+// http://www.agner.org/optimize/calling_conventions.pdf
+// or with gcc, run: "echo | gcc -E -dM -"
+#if defined(_M_X64) || defined(__x86_64__)
+#define ARCH_CPU_X86_FAMILY 1
+#define ARCH_CPU_X86_64 1
+#define ARCH_CPU_64_BITS 1
+#define ARCH_CPU_LITTLE_ENDIAN 1
+#elif defined(_M_IX86) || defined(__i386__)
+#define ARCH_CPU_X86_FAMILY 1
+#define ARCH_CPU_X86 1
+#define ARCH_CPU_32_BITS 1
+#define ARCH_CPU_LITTLE_ENDIAN 1
+#elif defined(__ARMEL__)
+#define ARCH_CPU_ARM_FAMILY 1
+#define ARCH_CPU_ARMEL 1
+#define ARCH_CPU_32_BITS 1
+#define ARCH_CPU_LITTLE_ENDIAN 1
+#define WCHAR_T_IS_UNSIGNED 1
+#else
+#error Please add support for your architecture in build/build_config.h
+#endif
+
+// Type detection for wchar_t.
+#if defined(OS_WIN)
+#define WCHAR_T_IS_UTF16
+#elif defined(OS_POSIX) && defined(COMPILER_GCC) && \
+ defined(__WCHAR_MAX__) && \
+ (__WCHAR_MAX__ == 0x7fffffff || __WCHAR_MAX__ == 0xffffffff)
+#define WCHAR_T_IS_UTF32
+#elif defined(OS_POSIX) && defined(COMPILER_GCC) && \
+ defined(__WCHAR_MAX__) && \
+ (__WCHAR_MAX__ == 0x7fff || __WCHAR_MAX__ == 0xffff)
+// On Posix, we'll detect short wchar_t, but projects aren't guaranteed to
+// compile in this mode (in particular, Chrome doesn't). This is intended for
+// other projects using base who manage their own dependencies and make sure
+// short wchar works for them.
+#define WCHAR_T_IS_UTF16
+#else
+#error Please add support for your compiler in build/build_config.h
+#endif
+
+#if defined(OS_CHROMEOS)
+// Single define to trigger whether CrOS fonts have BCI on.
+// In that case font sizes/deltas should be adjusted.
+//define CROS_FONTS_USING_BCI
+#endif
+
+#if defined(OS_ANDROID)
+// The compiler thinks std::string::const_iterator and "const char*" are
+// equivalent types.
+#define STD_STRING_ITERATOR_IS_CHAR_POINTER
+// The compiler thinks base::string16::const_iterator and "char16*" are
+// equivalent types.
+#define BASE_STRING16_ITERATOR_IS_CHAR16_POINTER
+#endif
+
+#endif // BUILD_BUILD_CONFIG_H_
diff --git a/chromium.manifest b/chromium.manifest
new file mode 100644
index 000000000000..ae3e6f71a699
--- /dev/null
+++ b/chromium.manifest
@@ -0,0 +1,5 @@
+<manifest>
+ <request>
+ <domain name="_"/>
+ </request>
+</manifest> \ No newline at end of file
diff --git a/chromium.pc.in b/chromium.pc.in
new file mode 100755
index 000000000000..b6609e06bac9
--- /dev/null
+++ b/chromium.pc.in
@@ -0,0 +1,14 @@
+# Package Information for pkg-config
+
+prefix=@PREFIX@
+exec_prefix=/usr
+libdir=/usr/lib
+includedir=/usr/include/chromium
+
+Name: @PC_NAME@
+Description: @PACKAGE_DESCRIPTION@
+Version: @VERSION@
+Requires: @PC_REQUIRED@
+Libs: -L${libdir} @PC_LDFLAGS@
+Cflags: -I${includedir}
+
diff --git a/ipc/OWNERS b/ipc/OWNERS
new file mode 100644
index 000000000000..fc187f8ba4f1
--- /dev/null
+++ b/ipc/OWNERS
@@ -0,0 +1,7 @@
+agl@chromium.org
+cpu@chromium.org
+darin@chromium.org
+dmaclach@chromium.org
+jam@chromium.org
+jeremy@chromium.org
+tsepez@chromium.org
diff --git a/ipc/file_descriptor_set_posix.cc b/ipc/file_descriptor_set_posix.cc
new file mode 100644
index 000000000000..7f17322de47b
--- /dev/null
+++ b/ipc/file_descriptor_set_posix.cc
@@ -0,0 +1,136 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ipc/file_descriptor_set_posix.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "base/eintr_wrapper.h"
+#include "base/logging.h"
+
+FileDescriptorSet::FileDescriptorSet()
+ : consumed_descriptor_highwater_(0) {
+}
+
+FileDescriptorSet::~FileDescriptorSet() {
+ if (consumed_descriptor_highwater_ == descriptors_.size())
+ return;
+
+ LOG(WARNING) << "FileDescriptorSet destroyed with unconsumed descriptors";
+ // We close all the descriptors where the close flag is set. If this
+ // message should have been transmitted, then closing those with close
+ // flags set mirrors the expected behaviour.
+ //
+ // If this message was received with more descriptors than expected
+ // (which could a DOS against the browser by a rogue renderer) then all
+ // the descriptors have their close flag set and we free all the extra
+ // kernel resources.
+ for (unsigned i = consumed_descriptor_highwater_;
+ i < descriptors_.size(); ++i) {
+ if (descriptors_[i].auto_close)
+ if (HANDLE_EINTR(close(descriptors_[i].fd)) < 0)
+ PLOG(ERROR) << "close";
+ }
+}
+
+bool FileDescriptorSet::Add(int fd) {
+ if (descriptors_.size() == MAX_DESCRIPTORS_PER_MESSAGE)
+ return false;
+
+ struct base::FileDescriptor sd;
+ sd.fd = fd;
+ sd.auto_close = false;
+ descriptors_.push_back(sd);
+ return true;
+}
+
+bool FileDescriptorSet::AddAndAutoClose(int fd) {
+ if (descriptors_.size() == MAX_DESCRIPTORS_PER_MESSAGE)
+ return false;
+
+ struct base::FileDescriptor sd;
+ sd.fd = fd;
+ sd.auto_close = true;
+ descriptors_.push_back(sd);
+ DCHECK(descriptors_.size() <= MAX_DESCRIPTORS_PER_MESSAGE);
+ return true;
+}
+
+int FileDescriptorSet::GetDescriptorAt(unsigned index) const {
+ if (index >= descriptors_.size())
+ return -1;
+
+ // We should always walk the descriptors in order, so it's reasonable to
+ // enforce this. Consider the case where a compromised renderer sends us
+ // the following message:
+ //
+ // ExampleMsg:
+ // num_fds:2 msg:FD(index = 1) control:SCM_RIGHTS {n, m}
+ //
+ // Here the renderer sent us a message which should have a descriptor, but
+ // actually sent two in an attempt to fill our fd table and kill us. By
+ // setting the index of the descriptor in the message to 1 (it should be
+ // 0), we would record a highwater of 1 and then consider all the
+ // descriptors to have been used.
+ //
+ // So we can either track of the use of each descriptor in a bitset, or we
+ // can enforce that we walk the indexes strictly in order.
+ //
+ // There's one more wrinkle: When logging messages, we may reparse them. So
+ // we have an exception: When the consumed_descriptor_highwater_ is at the
+ // end of the array and index 0 is requested, we reset the highwater value.
+ if (index == 0 && consumed_descriptor_highwater_ == descriptors_.size())
+ consumed_descriptor_highwater_ = 0;
+
+ if (index != consumed_descriptor_highwater_)
+ return -1;
+
+ consumed_descriptor_highwater_ = index + 1;
+ return descriptors_[index].fd;
+}
+
+void FileDescriptorSet::GetDescriptors(int* buffer) const {
+ for (std::vector<base::FileDescriptor>::const_iterator
+ i = descriptors_.begin(); i != descriptors_.end(); ++i) {
+ *(buffer++) = i->fd;
+ }
+}
+
+bool FileDescriptorSet::ContainsDirectoryDescriptor() const {
+ struct stat st;
+
+ for (std::vector<base::FileDescriptor>::const_iterator
+ i = descriptors_.begin(); i != descriptors_.end(); ++i) {
+ if (fstat(i->fd, &st) == 0 && S_ISDIR(st.st_mode))
+ return true;
+ }
+
+ return false;
+}
+
+void FileDescriptorSet::CommitAll() {
+ for (std::vector<base::FileDescriptor>::iterator
+ i = descriptors_.begin(); i != descriptors_.end(); ++i) {
+ if (i->auto_close)
+ if (HANDLE_EINTR(close(i->fd)) < 0)
+ PLOG(ERROR) << "close";
+ }
+ descriptors_.clear();
+ consumed_descriptor_highwater_ = 0;
+}
+
+void FileDescriptorSet::SetDescriptors(const int* buffer, unsigned count) {
+ DCHECK_LE(count, MAX_DESCRIPTORS_PER_MESSAGE);
+ DCHECK_EQ(descriptors_.size(), 0u);
+ DCHECK_EQ(consumed_descriptor_highwater_, 0u);
+
+ descriptors_.reserve(count);
+ for (unsigned i = 0; i < count; ++i) {
+ struct base::FileDescriptor sd;
+ sd.fd = buffer[i];
+ sd.auto_close = true;
+ descriptors_.push_back(sd);
+ }
+}
diff --git a/ipc/file_descriptor_set_posix.h b/ipc/file_descriptor_set_posix.h
new file mode 100644
index 000000000000..1554c38510d2
--- /dev/null
+++ b/ipc/file_descriptor_set_posix.h
@@ -0,0 +1,117 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IPC_FILE_DESCRIPTOR_SET_POSIX_H_
+#define IPC_FILE_DESCRIPTOR_SET_POSIX_H_
+#pragma once
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/file_descriptor_posix.h"
+#include "base/memory/ref_counted.h"
+#include "ipc/ipc_export.h"
+
+// -----------------------------------------------------------------------------
+// A FileDescriptorSet is an ordered set of POSIX file descriptors. These are
+// associated with IPC messages so that descriptors can be transmitted over a
+// UNIX domain socket.
+// -----------------------------------------------------------------------------
+class IPC_EXPORT FileDescriptorSet
+ : public base::RefCountedThreadSafe<FileDescriptorSet> {
+ public:
+ FileDescriptorSet();
+
+ // This is the maximum number of descriptors per message. We need to know this
+ // because the control message kernel interface has to be given a buffer which
+ // is large enough to store all the descriptor numbers. Otherwise the kernel
+ // tells us that it truncated the control data and the extra descriptors are
+ // lost.
+ //
+ // In debugging mode, it's a fatal error to try and add more than this number
+ // of descriptors to a FileDescriptorSet.
+ enum {
+ MAX_DESCRIPTORS_PER_MESSAGE = 5,
+ };
+
+ // ---------------------------------------------------------------------------
+ // Interfaces for building during message serialisation...
+
+ // Add a descriptor to the end of the set. Returns false iff the set is full.
+ bool Add(int fd);
+ // Add a descriptor to the end of the set and automatically close it after
+ // transmission. Returns false iff the set is full.
+ bool AddAndAutoClose(int fd);
+
+ // ---------------------------------------------------------------------------
+
+
+ // ---------------------------------------------------------------------------
+ // Interfaces for accessing during message deserialisation...
+
+ // Return the number of descriptors
+ unsigned size() const { return descriptors_.size(); }
+ // Return true if no unconsumed descriptors remain
+ bool empty() const { return descriptors_.empty(); }
+ // Fetch the nth descriptor from the beginning of the set. Code using this
+ // /must/ access the descriptors in order, except that it may wrap from the
+ // end to index 0 again.
+ //
+ // This interface is designed for the deserialising code as it doesn't
+ // support close flags.
+ // returns: file descriptor, or -1 on error
+ int GetDescriptorAt(unsigned n) const;
+
+ // ---------------------------------------------------------------------------
+
+
+ // ---------------------------------------------------------------------------
+ // Interfaces for transmission...
+
+ // Fill an array with file descriptors without 'consuming' them. CommitAll
+ // must be called after these descriptors have been transmitted.
+ // buffer: (output) a buffer of, at least, size() integers.
+ void GetDescriptors(int* buffer) const;
+ // This must be called after transmitting the descriptors returned by
+ // GetDescriptors. It marks all the descriptors as consumed and closes those
+ // which are auto-close.
+ void CommitAll();
+ // Returns true if any contained file descriptors appear to be handles to a
+ // directory.
+ bool ContainsDirectoryDescriptor() const;
+
+ // ---------------------------------------------------------------------------
+
+
+ // ---------------------------------------------------------------------------
+ // Interfaces for receiving...
+
+ // Set the contents of the set from the given buffer. This set must be empty
+ // before calling. The auto-close flag is set on all the descriptors so that
+ // unconsumed descriptors are closed on destruction.
+ void SetDescriptors(const int* buffer, unsigned count);
+
+ // ---------------------------------------------------------------------------
+
+ private:
+ friend class base::RefCountedThreadSafe<FileDescriptorSet>;
+
+ ~FileDescriptorSet();
+
+ // A vector of descriptors and close flags. If this message is sent, then
+ // these descriptors are sent as control data. After sending, any descriptors
+ // with a true flag are closed. If this message has been received, then these
+ // are the descriptors which were received and all close flags are true.
+ std::vector<base::FileDescriptor> descriptors_;
+
+ // This contains the index of the next descriptor which should be consumed.
+ // It's used in a couple of ways. Firstly, at destruction we can check that
+ // all the descriptors have been read (with GetNthDescriptor). Secondly, we
+ // can check that they are read in order.
+ mutable unsigned consumed_descriptor_highwater_;
+
+ DISALLOW_COPY_AND_ASSIGN(FileDescriptorSet);
+};
+
+#endif // IPC_FILE_DESCRIPTOR_SET_POSIX_H_
diff --git a/ipc/file_descriptor_set_posix_unittest.cc b/ipc/file_descriptor_set_posix_unittest.cc
new file mode 100644
index 000000000000..5fc8c50fc9ed
--- /dev/null
+++ b/ipc/file_descriptor_set_posix_unittest.cc
@@ -0,0 +1,179 @@
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This test is POSIX only.
+
+#include "ipc/file_descriptor_set_posix.h"
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "base/basictypes.h"
+#include "base/eintr_wrapper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// Get a safe file descriptor for test purposes.
+int GetSafeFd() {
+ return open("/dev/null", O_RDONLY);
+}
+
+// Returns true if fd was already closed. Closes fd if not closed.
+bool VerifyClosed(int fd) {
+ const int duped = dup(fd);
+ if (duped != -1) {
+ EXPECT_NE(HANDLE_EINTR(close(duped)), -1);
+ EXPECT_NE(HANDLE_EINTR(close(fd)), -1);
+ return false;
+ }
+ return true;
+}
+
+// The FileDescriptorSet will try and close some of the descriptor numbers
+// which we given it. This is the base descriptor value. It's great enough such
+// that no real descriptor will accidently be closed.
+static const int kFDBase = 50000;
+
+TEST(FileDescriptorSet, BasicAdd) {
+ scoped_refptr<FileDescriptorSet> set(new FileDescriptorSet);
+
+ ASSERT_EQ(set->size(), 0u);
+ ASSERT_TRUE(set->empty());
+ ASSERT_TRUE(set->Add(kFDBase));
+ ASSERT_EQ(set->size(), 1u);
+ ASSERT_TRUE(!set->empty());
+
+ // Empties the set and stops a warning about deleting a set with unconsumed
+ // descriptors
+ set->CommitAll();
+}
+
+TEST(FileDescriptorSet, BasicAddAndClose) {
+ scoped_refptr<FileDescriptorSet> set(new FileDescriptorSet);
+
+ ASSERT_EQ(set->size(), 0u);
+ ASSERT_TRUE(set->empty());
+ const int fd = GetSafeFd();
+ ASSERT_TRUE(set->AddAndAutoClose(fd));
+ ASSERT_EQ(set->size(), 1u);
+ ASSERT_TRUE(!set->empty());
+
+ set->CommitAll();
+
+ ASSERT_TRUE(VerifyClosed(fd));
+}
+TEST(FileDescriptorSet, MaxSize) {
+ scoped_refptr<FileDescriptorSet> set(new FileDescriptorSet);
+
+ for (unsigned i = 0;
+ i < FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE; ++i) {
+ ASSERT_TRUE(set->Add(kFDBase + 1 + i));
+ }
+
+ ASSERT_TRUE(!set->Add(kFDBase));
+
+ set->CommitAll();
+}
+
+TEST(FileDescriptorSet, SetDescriptors) {
+ scoped_refptr<FileDescriptorSet> set(new FileDescriptorSet);
+
+ ASSERT_TRUE(set->empty());
+ set->SetDescriptors(NULL, 0);
+ ASSERT_TRUE(set->empty());
+
+ const int fd = GetSafeFd();
+ static const int fds[] = {fd};
+ set->SetDescriptors(fds, 1);
+ ASSERT_TRUE(!set->empty());
+ ASSERT_EQ(set->size(), 1u);
+
+ set->CommitAll();
+
+ ASSERT_TRUE(VerifyClosed(fd));
+}
+
+TEST(FileDescriptorSet, GetDescriptors) {
+ scoped_refptr<FileDescriptorSet> set(new FileDescriptorSet);
+
+ set->GetDescriptors(NULL);
+ ASSERT_TRUE(set->Add(kFDBase));
+
+ int fds[1];
+ fds[0] = 0;
+ set->GetDescriptors(fds);
+ ASSERT_EQ(fds[0], kFDBase);
+ set->CommitAll();
+ ASSERT_TRUE(set->empty());
+}
+
+TEST(FileDescriptorSet, WalkInOrder) {
+ scoped_refptr<FileDescriptorSet> set(new FileDescriptorSet);
+
+ ASSERT_TRUE(set->Add(kFDBase));
+ ASSERT_TRUE(set->Add(kFDBase + 1));
+ ASSERT_TRUE(set->Add(kFDBase + 2));
+
+ ASSERT_EQ(set->GetDescriptorAt(0), kFDBase);
+ ASSERT_EQ(set->GetDescriptorAt(1), kFDBase + 1);
+ ASSERT_EQ(set->GetDescriptorAt(2), kFDBase + 2);
+
+ set->CommitAll();
+}
+
+TEST(FileDescriptorSet, WalkWrongOrder) {
+ scoped_refptr<FileDescriptorSet> set(new FileDescriptorSet);
+
+ ASSERT_TRUE(set->Add(kFDBase));
+ ASSERT_TRUE(set->Add(kFDBase + 1));
+ ASSERT_TRUE(set->Add(kFDBase + 2));
+
+ ASSERT_EQ(set->GetDescriptorAt(0), kFDBase);
+ ASSERT_EQ(set->GetDescriptorAt(2), -1);
+
+ set->CommitAll();
+}
+
+TEST(FileDescriptorSet, WalkCycle) {
+ scoped_refptr<FileDescriptorSet> set(new FileDescriptorSet);
+
+ ASSERT_TRUE(set->Add(kFDBase));
+ ASSERT_TRUE(set->Add(kFDBase + 1));
+ ASSERT_TRUE(set->Add(kFDBase + 2));
+
+ ASSERT_EQ(set->GetDescriptorAt(0), kFDBase);
+ ASSERT_EQ(set->GetDescriptorAt(1), kFDBase + 1);
+ ASSERT_EQ(set->GetDescriptorAt(2), kFDBase + 2);
+ ASSERT_EQ(set->GetDescriptorAt(0), kFDBase);
+ ASSERT_EQ(set->GetDescriptorAt(1), kFDBase + 1);
+ ASSERT_EQ(set->GetDescriptorAt(2), kFDBase + 2);
+ ASSERT_EQ(set->GetDescriptorAt(0), kFDBase);
+ ASSERT_EQ(set->GetDescriptorAt(1), kFDBase + 1);
+ ASSERT_EQ(set->GetDescriptorAt(2), kFDBase + 2);
+
+ set->CommitAll();
+}
+
+TEST(FileDescriptorSet, DontClose) {
+ scoped_refptr<FileDescriptorSet> set(new FileDescriptorSet);
+
+ const int fd = GetSafeFd();
+ ASSERT_TRUE(set->Add(fd));
+ set->CommitAll();
+
+ ASSERT_FALSE(VerifyClosed(fd));
+}
+
+TEST(FileDescriptorSet, DoClose) {
+ scoped_refptr<FileDescriptorSet> set(new FileDescriptorSet);
+
+ const int fd = GetSafeFd();
+ ASSERT_TRUE(set->AddAndAutoClose(fd));
+ set->CommitAll();
+
+ ASSERT_TRUE(VerifyClosed(fd));
+}
+
+} // namespace
diff --git a/ipc/ipc.gyp b/ipc/ipc.gyp
new file mode 100644
index 000000000000..ab57cd9b4dd2
--- /dev/null
+++ b/ipc/ipc.gyp
@@ -0,0 +1,90 @@
+# Copyright (c) 2009 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'variables': {
+ 'chromium_code': 1,
+ },
+ 'target_defaults': {
+ 'sources/': [
+ ['exclude', '/win/'],
+ ['exclude', '_(posix|win)(_unittest)?\\.(cc|mm?)$'],
+ ['exclude', '/win_[^/]*\\.cc$'],
+ ],
+ 'conditions': [
+ ['os_posix == 1 and OS != "mac"', {'sources/': [
+ ['include', '_posix(_unittest)?\\.cc$'],
+ ]}],
+ ['OS=="mac"', {'sources/': [
+ ['include', '_posix(_unittest)?\\.(cc|mm?)$'],
+ ]}],
+ ['OS=="win"', {'sources/': [
+ ['include', '_win(_unittest)?\\.cc$'],
+ ['include', '/win/'],
+ ['include', '/win_[^/]*\\.cc$'],
+ ]}],
+ ],
+ },
+ 'includes': [
+ 'ipc.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'ipc_tests',
+ 'type': 'executable',
+ 'dependencies': [
+ 'ipc',
+ '../base/base.gyp:base',
+ '../base/base.gyp:base_i18n',
+ '../base/base.gyp:test_support_base',
+ '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+ '../testing/gtest.gyp:gtest',
+ ],
+ 'include_dirs': [
+ '..'
+ ],
+ 'sources': [
+ 'file_descriptor_set_posix_unittest.cc',
+ 'ipc_channel_posix_unittest.cc',
+ 'ipc_fuzzing_tests.cc',
+ 'ipc_message_unittest.cc',
+ 'ipc_send_fds_test.cc',
+ 'ipc_sync_channel_unittest.cc',
+ 'ipc_sync_message_unittest.cc',
+ 'ipc_sync_message_unittest.h',
+ 'ipc_tests.cc',
+ 'ipc_tests.h',
+ 'sync_socket_unittest.cc',
+ ],
+ 'conditions': [
+ ['toolkit_uses_gtk == 1', {
+ 'dependencies': [
+ '../build/linux/system.gyp:gtk',
+ ],
+ }],
+ ['os_posix == 1 and OS != "mac"', {
+ 'conditions': [
+ ['linux_use_tcmalloc==1', {
+ 'dependencies': [
+ '../base/allocator/allocator.gyp:allocator',
+ ],
+ }],
+ ],
+ }]
+ ],
+ },
+ {
+ 'target_name': 'test_support_ipc',
+ 'type': 'static_library',
+ 'dependencies': [
+ 'ipc',
+ '../base/base.gyp:base',
+ ],
+ 'sources': [
+ 'ipc_test_sink.cc',
+ 'ipc_test_sink.h',
+ ],
+ },
+ ],
+}
diff --git a/ipc/ipc.gypi b/ipc/ipc.gypi
new file mode 100644
index 000000000000..7791934eabe0
--- /dev/null
+++ b/ipc/ipc.gypi
@@ -0,0 +1,109 @@
+# 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.
+
+{
+ 'target_defaults': {
+ 'variables': {
+ 'ipc_target': 0,
+ },
+ 'target_conditions': [
+ # This part is shared between the targets defined below.
+ ['ipc_target==1', {
+ 'sources': [
+ 'file_descriptor_set_posix.cc',
+ 'file_descriptor_set_posix.h',
+ 'ipc_channel.h',
+ 'ipc_channel_handle.h',
+ 'ipc_channel_posix.cc',
+ 'ipc_channel_posix.h',
+ 'ipc_channel_proxy.cc',
+ 'ipc_channel_proxy.h',
+ 'ipc_channel_win.cc',
+ 'ipc_channel_win.h',
+ 'ipc_descriptors.h',
+ 'ipc_export.h',
+ 'ipc_logging.cc',
+ 'ipc_logging.h',
+ 'ipc_message.cc',
+ 'ipc_message.h',
+ 'ipc_message_macros.h',
+ 'ipc_message_utils.cc',
+ 'ipc_message_utils.h',
+ 'ipc_param_traits.h',
+ 'ipc_platform_file.cc',
+ 'ipc_platform_file.h',
+ 'ipc_switches.cc',
+ 'ipc_switches.h',
+ 'ipc_sync_channel.cc',
+ 'ipc_sync_channel.h',
+ 'ipc_sync_message.cc',
+ 'ipc_sync_message.h',
+ 'ipc_sync_message_filter.cc',
+ 'ipc_sync_message_filter.h',
+ 'param_traits_log_macros.h',
+ 'param_traits_macros.h',
+ 'param_traits_read_macros.h',
+ 'param_traits_write_macros.h',
+ 'struct_constructor_macros.h',
+ 'struct_destructor_macros.h',
+ ],
+ 'defines': [
+ 'IPC_IMPLEMENTATION',
+ ],
+ 'include_dirs': [
+ '..',
+ ],
+ }],
+ ],
+ },
+ 'targets': [
+ {
+ 'target_name': 'ipc',
+ 'type': '<(component)',
+ 'variables': {
+ 'ipc_target': 1,
+ },
+ 'dependencies': [
+ '../base/base.gyp:base',
+ '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+ ],
+ # TODO(gregoryd): direct_dependent_settings should be shared with the
+ # 64-bit target, but it doesn't work due to a bug in gyp
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '..',
+ ],
+ },
+ },
+ ],
+ 'conditions': [
+ ['OS=="win"', {
+ 'targets': [
+ {
+ 'target_name': 'ipc_win64',
+ 'type': '<(component)',
+ 'variables': {
+ 'ipc_target': 1,
+ },
+ 'dependencies': [
+ '../base/base.gyp:base_nacl_win64',
+ '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations_win64',
+ ],
+ # TODO(gregoryd): direct_dependent_settings should be shared with the
+ # 32-bit target, but it doesn't work due to a bug in gyp
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '..',
+ ],
+ },
+ 'configurations': {
+ 'Common_Base': {
+ 'msvs_target_platform': 'x64',
+ },
+ },
+ },
+ ],
+ }],
+ ],
+}
diff --git a/ipc/ipc_channel.h b/ipc/ipc_channel.h
new file mode 100644
index 000000000000..cd57b4b89548
--- /dev/null
+++ b/ipc/ipc_channel.h
@@ -0,0 +1,204 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IPC_IPC_CHANNEL_H_
+#define IPC_IPC_CHANNEL_H_
+#pragma once
+
+#include "base/compiler_specific.h"
+#include "ipc/ipc_channel_handle.h"
+#include "ipc/ipc_message.h"
+
+namespace IPC {
+
+//------------------------------------------------------------------------------
+// See
+// http://www.chromium.org/developers/design-documents/inter-process-communication
+// for overview of IPC in Chromium.
+
+// Channels are implemented using named pipes on Windows, and
+// socket pairs (or in some special cases unix domain sockets) on POSIX.
+// On Windows we access pipes in various processes by name.
+// On POSIX we pass file descriptors to child processes and assign names to them
+// in a lookup table.
+// In general on POSIX we do not use unix domain sockets due to security
+// concerns and the fact that they can leave garbage around the file system
+// (MacOS does not support abstract named unix domain sockets).
+// You can use unix domain sockets if you like on POSIX by constructing the
+// the channel with the mode set to one of the NAMED modes. NAMED modes are
+// currently used by automation and service processes.
+
+class IPC_EXPORT Channel : public Message::Sender {
+ // Security tests need access to the pipe handle.
+ friend class ChannelTest;
+
+ public:
+ // Implemented by consumers of a Channel to receive messages.
+ class IPC_EXPORT Listener {
+ public:
+ virtual ~Listener() {}
+
+ // Called when a message is received. Returns true iff the message was
+ // handled.
+ virtual bool OnMessageReceived(const Message& message) = 0;
+
+ // Called when the channel is connected and we have received the internal
+ // Hello message from the peer.
+ virtual void OnChannelConnected(int32 peer_pid) {}
+
+ // Called when an error is detected that causes the channel to close.
+ // This method is not called when a channel is closed normally.
+ virtual void OnChannelError() {}
+
+#if defined(OS_POSIX)
+ // Called on the server side when a channel that listens for connections
+ // denies an attempt to connect.
+ virtual void OnChannelDenied() {}
+
+ // Called on the server side when a channel that listens for connections
+ // has an error that causes the listening channel to close.
+ virtual void OnChannelListenError() {}
+#endif // OS_POSIX
+ };
+
+ // Flags to test modes
+ enum ModeFlags {
+ MODE_NO_FLAG = 0x0,
+ MODE_SERVER_FLAG = 0x1,
+ MODE_CLIENT_FLAG = 0x2,
+ MODE_NAMED_FLAG = 0x4,
+#if defined(OS_POSIX)
+ MODE_OPEN_ACCESS_FLAG = 0x8, // Don't restrict access based on client UID.
+#endif
+ };
+
+ // Some Standard Modes
+ enum Mode {
+ MODE_NONE = MODE_NO_FLAG,
+ MODE_SERVER = MODE_SERVER_FLAG,
+ MODE_CLIENT = MODE_CLIENT_FLAG,
+ // Channels on Windows are named by default and accessible from other
+ // processes. On POSIX channels are anonymous by default and not accessible
+ // from other processes. Named channels work via named unix domain sockets.
+ // On Windows MODE_NAMED_SERVER is equivalent to MODE_SERVER and
+ // MODE_NAMED_CLIENT is equivalent to MODE_CLIENT.
+ MODE_NAMED_SERVER = MODE_SERVER_FLAG | MODE_NAMED_FLAG,
+ MODE_NAMED_CLIENT = MODE_CLIENT_FLAG | MODE_NAMED_FLAG,
+#if defined(OS_POSIX)
+ // An "open" named server accepts connections from ANY client.
+ // The caller must then implement their own access-control based on the
+ // client process' user Id.
+ MODE_OPEN_NAMED_SERVER = MODE_OPEN_ACCESS_FLAG | MODE_SERVER_FLAG |
+ MODE_NAMED_FLAG
+#endif
+ };
+
+ enum {
+ // The maximum message size in bytes. Attempting to receive a
+ // message of this size or bigger results in a channel error.
+ kMaximumMessageSize = 128 * 1024 * 1024,
+
+ // Ammount of data to read at once from the pipe.
+ kReadBufferSize = 4 * 1024
+ };
+
+ // Initialize a Channel.
+ //
+ // |channel_handle| identifies the communication Channel. For POSIX, if
+ // the file descriptor in the channel handle is != -1, the channel takes
+ // ownership of the file descriptor and will close it appropriately, otherwise
+ // it will create a new descriptor internally.
+ // |mode| specifies whether this Channel is to operate in server mode or
+ // client mode. In server mode, the Channel is responsible for setting up the
+ // IPC object, whereas in client mode, the Channel merely connects to the
+ // already established IPC object.
+ // |listener| receives a callback on the current thread for each newly
+ // received message.
+ //
+ Channel(const IPC::ChannelHandle &channel_handle, Mode mode,
+ Listener* listener);
+
+ virtual ~Channel();
+
+ // Connect the pipe. On the server side, this will initiate
+ // waiting for connections. On the client, it attempts to
+ // connect to a pre-existing pipe. Note, calling Connect()
+ // will not block the calling thread and may complete
+ // asynchronously.
+ bool Connect() WARN_UNUSED_RESULT;
+
+ // Close this Channel explicitly. May be called multiple times.
+ // On POSIX calling close on an IPC channel that listens for connections will
+ // cause it to close any accepted connections, and it will stop listening for
+ // new connections. If you just want to close the currently accepted
+ // connection and listen for new ones, use ResetToAcceptingConnectionState.
+ void Close();
+
+ // Modify the Channel's listener.
+ void set_listener(Listener* listener);
+
+ // Send a message over the Channel to the listener on the other end.
+ //
+ // |message| must be allocated using operator new. This object will be
+ // deleted once the contents of the Message have been sent.
+ virtual bool Send(Message* message);
+
+#if defined(OS_POSIX) && !defined(OS_NACL)
+ // On POSIX an IPC::Channel wraps a socketpair(), this method returns the
+ // FD # for the client end of the socket.
+ // This method may only be called on the server side of a channel.
+ int GetClientFileDescriptor() const;
+
+ // On POSIX an IPC::Channel can either wrap an established socket, or it
+ // can wrap a socket that is listening for connections. Currently an
+ // IPC::Channel that listens for connections can only accept one connection
+ // at a time.
+
+ // Returns true if the channel supports listening for connections.
+ bool AcceptsConnections() const;
+
+ // Returns true if the channel supports listening for connections and is
+ // currently connected.
+ bool HasAcceptedConnection() const;
+
+ // Returns true if the peer process' effective user id can be determined, in
+ // which case the supplied client_euid is updated with it.
+ bool GetClientEuid(uid_t* client_euid) const;
+
+ // Closes any currently connected socket, and returns to a listening state
+ // for more connections.
+ void ResetToAcceptingConnectionState();
+#endif // defined(OS_POSIX) && !defined(OS_NACL)
+
+ // Returns true if a named server channel is initialized on the given channel
+ // ID. Even if true, the server may have already accepted a connection.
+ static bool IsNamedServerInitialized(const std::string& channel_id);
+
+ protected:
+ // Used in Chrome by the TestSink to provide a dummy channel implementation
+ // for testing. TestSink overrides the "interesting" functions in Channel so
+ // no actual implementation is needed. This will cause un-overridden calls to
+ // segfault. Do not use outside of test code!
+ Channel() : channel_impl_(0) { }
+
+ private:
+ // PIMPL to which all channel calls are delegated.
+ class ChannelImpl;
+ ChannelImpl *channel_impl_;
+
+ // The Hello message is internal to the Channel class. It is sent
+ // by the peer when the channel is connected. The message contains
+ // just the process id (pid). The message has a special routing_id
+ // (MSG_ROUTING_NONE) and type (HELLO_MESSAGE_TYPE).
+ enum {
+ HELLO_MESSAGE_TYPE = kuint16max // Maximum value of message type (uint16),
+ // to avoid conflicting with normal
+ // message types, which are enumeration
+ // constants starting from 0.
+ };
+};
+
+} // namespace IPC
+
+#endif // IPC_IPC_CHANNEL_H_
diff --git a/ipc/ipc_channel_handle.h b/ipc/ipc_channel_handle.h
new file mode 100644
index 000000000000..ba034cca23b8
--- /dev/null
+++ b/ipc/ipc_channel_handle.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IPC_IPC_CHANNEL_HANDLE_H_
+#define IPC_IPC_CHANNEL_HANDLE_H_
+#pragma once
+
+#include <string>
+
+#include "build/build_config.h"
+
+#if defined(OS_POSIX)
+#include "base/file_descriptor_posix.h"
+#endif
+
+// On Windows, any process can create an IPC channel and others can fetch
+// it by name. We pass around the channel names over IPC.
+// On POSIX, we instead pass around handles to channel endpoints via IPC.
+// When it's time to IPC a new channel endpoint around, we send both the
+// channel name as well as a base::FileDescriptor, which is itself a special
+// type that knows how to copy a socket endpoint over IPC.
+//
+// In sum, when passing a handle to a channel over IPC, use this data structure
+// to work on both Windows and POSIX.
+
+namespace IPC {
+
+struct ChannelHandle {
+ // Note that serialization for this object is defined in the ParamTraits
+ // template specialization in ipc_message_utils.h.
+ ChannelHandle() {}
+ // The name that is passed in should be an absolute path for Posix.
+ // Otherwise there may be a problem in IPC communication between
+ // processes with different working directories.
+ ChannelHandle(const std::string& n) : name(n) {}
+ ChannelHandle(const char* n) : name(n) {}
+#if defined(OS_POSIX)
+ ChannelHandle(const std::string& n, const base::FileDescriptor& s)
+ : name(n), socket(s) {}
+#endif // defined(OS_POSIX)
+
+ std::string name;
+#if defined(OS_POSIX)
+ base::FileDescriptor socket;
+#endif // defined(OS_POSIX)
+
+};
+
+} // namespace IPC
+
+#endif // IPC_IPC_CHANNEL_HANDLE_H_
diff --git a/ipc/ipc_channel_posix.cc b/ipc/ipc_channel_posix.cc
new file mode 100644
index 000000000000..c358d35c6519
--- /dev/null
+++ b/ipc/ipc_channel_posix.cc
@@ -0,0 +1,1217 @@
+// 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 "ipc/ipc_channel_posix.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+
+#include <string>
+#include <map>
+
+#include "base/command_line.h"
+#include "base/eintr_wrapper.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/global_descriptors_posix.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/singleton.h"
+#include "base/process_util.h"
+#include "base/stl_util.h"
+#include "base/string_util.h"
+#include "base/synchronization/lock.h"
+#include "ipc/ipc_descriptors.h"
+#include "ipc/ipc_switches.h"
+#include "ipc/file_descriptor_set_posix.h"
+#include "ipc/ipc_logging.h"
+#include "ipc/ipc_message_utils.h"
+
+namespace IPC {
+
+// IPC channels on Windows use named pipes (CreateNamedPipe()) with
+// channel ids as the pipe names. Channels on POSIX use sockets as
+// pipes These don't quite line up.
+//
+// When creating a child subprocess we use a socket pair and the parent side of
+// the fork arranges it such that the initial control channel ends up on the
+// magic file descriptor kPrimaryIPCChannel in the child. Future
+// connections (file descriptors) can then be passed via that
+// connection via sendmsg().
+//
+// A POSIX IPC channel can also be set up as a server for a bound UNIX domain
+// socket, and will handle multiple connect and disconnect sequences. Currently
+// it is limited to one connection at a time.
+
+//------------------------------------------------------------------------------
+namespace {
+
+// The PipeMap class works around this quirk related to unit tests:
+//
+// When running as a server, we install the client socket in a
+// specific file descriptor number (@kPrimaryIPCChannel). However, we
+// also have to support the case where we are running unittests in the
+// same process. (We do not support forking without execing.)
+//
+// Case 1: normal running
+// The IPC server object will install a mapping in PipeMap from the
+// name which it was given to the client pipe. When forking the client, the
+// GetClientFileDescriptorMapping will ensure that the socket is installed in
+// the magic slot (@kPrimaryIPCChannel). The client will search for the
+// mapping, but it won't find any since we are in a new process. Thus the
+// magic fd number is returned. Once the client connects, the server will
+// close its copy of the client socket and remove the mapping.
+//
+// Case 2: unittests - client and server in the same process
+// The IPC server will install a mapping as before. The client will search
+// for a mapping and find out. It duplicates the file descriptor and
+// connects. Once the client connects, the server will close the original
+// copy of the client socket and remove the mapping. Thus, when the client
+// object closes, it will close the only remaining copy of the client socket
+// in the fd table and the server will see EOF on its side.
+//
+// TODO(port): a client process cannot connect to multiple IPC channels with
+// this scheme.
+
+class PipeMap {
+ public:
+ static PipeMap* GetInstance() {
+ return Singleton<PipeMap>::get();
+ }
+
+ ~PipeMap() {
+ // Shouldn't have left over pipes.
+ DCHECK(map_.empty());
+ }
+
+ // Lookup a given channel id. Return -1 if not found.
+ int Lookup(const std::string& channel_id) {
+ base::AutoLock locked(lock_);
+
+ ChannelToFDMap::const_iterator i = map_.find(channel_id);
+ if (i == map_.end())
+ return -1;
+ return i->second;
+ }
+
+ // Remove the mapping for the given channel id. No error is signaled if the
+ // channel_id doesn't exist
+ void RemoveAndClose(const std::string& channel_id) {
+ base::AutoLock locked(lock_);
+
+ ChannelToFDMap::iterator i = map_.find(channel_id);
+ if (i != map_.end()) {
+ if (HANDLE_EINTR(close(i->second)) < 0)
+ PLOG(ERROR) << "close " << channel_id;
+ map_.erase(i);
+ }
+ }
+
+ // Insert a mapping from @channel_id to @fd. It's a fatal error to insert a
+ // mapping if one already exists for the given channel_id
+ void Insert(const std::string& channel_id, int fd) {
+ base::AutoLock locked(lock_);
+ DCHECK_NE(-1, fd);
+
+ ChannelToFDMap::const_iterator i = map_.find(channel_id);
+ CHECK(i == map_.end()) << "Creating second IPC server (fd " << fd << ") "
+ << "for '" << channel_id << "' while first "
+ << "(fd " << i->second << ") still exists";
+ map_[channel_id] = fd;
+ }
+
+ private:
+ base::Lock lock_;
+ typedef std::map<std::string, int> ChannelToFDMap;
+ ChannelToFDMap map_;
+
+ friend struct DefaultSingletonTraits<PipeMap>;
+};
+
+//------------------------------------------------------------------------------
+// Verify that kMaxPipeNameLength is a decent size.
+COMPILE_ASSERT(sizeof(((sockaddr_un*)0)->sun_path) >= kMaxPipeNameLength,
+ BAD_SUN_PATH_LENGTH);
+
+// Creates a unix domain socket bound to the specified name that is listening
+// for connections.
+bool CreateServerUnixDomainSocket(const std::string& pipe_name,
+ int* server_listen_fd) {
+ DCHECK(server_listen_fd);
+ DCHECK_GT(pipe_name.length(), 0u);
+ DCHECK_LT(pipe_name.length(), kMaxPipeNameLength);
+
+ if (pipe_name.length() == 0 || pipe_name.length() >= kMaxPipeNameLength) {
+ return false;
+ }
+
+ // Create socket.
+ int fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (fd < 0) {
+ return false;
+ }
+
+ // Make socket non-blocking
+ if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
+ PLOG(ERROR) << "fcntl(O_NONBLOCK) " << pipe_name;
+ if (HANDLE_EINTR(close(fd)) < 0)
+ PLOG(ERROR) << "close " << pipe_name;
+ return false;
+ }
+
+ // Delete any old FS instances.
+ unlink(pipe_name.c_str());
+
+ // Make sure the path we need exists.
+ FilePath path(pipe_name);
+ FilePath dir_path = path.DirName();
+ if (!file_util::CreateDirectory(dir_path)) {
+ return false;
+ }
+
+ // Create unix_addr structure.
+ struct sockaddr_un unix_addr;
+ memset(&unix_addr, 0, sizeof(unix_addr));
+ unix_addr.sun_family = AF_UNIX;
+ int path_len = snprintf(unix_addr.sun_path, IPC::kMaxPipeNameLength,
+ "%s", pipe_name.c_str());
+ DCHECK_EQ(static_cast<int>(pipe_name.length()), path_len);
+ size_t unix_addr_len = offsetof(struct sockaddr_un,
+ sun_path) + path_len + 1;
+
+ // Bind the socket.
+ if (bind(fd, reinterpret_cast<const sockaddr*>(&unix_addr),
+ unix_addr_len) != 0) {
+ PLOG(ERROR) << "bind " << pipe_name;
+ if (HANDLE_EINTR(close(fd)) < 0)
+ PLOG(ERROR) << "close " << pipe_name;
+ return false;
+ }
+
+ // Start listening on the socket.
+ const int listen_queue_length = 1;
+ if (listen(fd, listen_queue_length) != 0) {
+ PLOG(ERROR) << "listen " << pipe_name;
+ if (HANDLE_EINTR(close(fd)) < 0)
+ PLOG(ERROR) << "close " << pipe_name;
+ return false;
+ }
+
+ *server_listen_fd = fd;
+ return true;
+}
+
+// Accept a connection on a socket we are listening to.
+bool ServerAcceptConnection(int server_listen_fd, int* server_socket) {
+ DCHECK(server_socket);
+
+ int accept_fd = HANDLE_EINTR(accept(server_listen_fd, NULL, 0));
+ if (accept_fd < 0)
+ return false;
+ if (fcntl(accept_fd, F_SETFL, O_NONBLOCK) == -1) {
+ PLOG(ERROR) << "fcntl(O_NONBLOCK) " << accept_fd;
+ if (HANDLE_EINTR(close(accept_fd)) < 0)
+ PLOG(ERROR) << "close " << accept_fd;
+ return false;
+ }
+
+ *server_socket = accept_fd;
+ return true;
+}
+
+bool CreateClientUnixDomainSocket(const std::string& pipe_name,
+ int* client_socket) {
+ DCHECK(client_socket);
+ DCHECK_GT(pipe_name.length(), 0u);
+ DCHECK_LT(pipe_name.length(), kMaxPipeNameLength);
+
+ if (pipe_name.length() == 0 || pipe_name.length() >= kMaxPipeNameLength) {
+ return false;
+ }
+
+ // Create socket.
+ int fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (fd < 0) {
+ PLOG(ERROR) << "socket " << pipe_name;
+ return false;
+ }
+
+ // Make socket non-blocking
+ if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
+ PLOG(ERROR) << "fcntl(O_NONBLOCK) " << pipe_name;
+ if (HANDLE_EINTR(close(fd)) < 0)
+ PLOG(ERROR) << "close " << pipe_name;
+ return false;
+ }
+
+ // Create server side of socket.
+ struct sockaddr_un server_unix_addr;
+ memset(&server_unix_addr, 0, sizeof(server_unix_addr));
+ server_unix_addr.sun_family = AF_UNIX;
+ int path_len = snprintf(server_unix_addr.sun_path, IPC::kMaxPipeNameLength,
+ "%s", pipe_name.c_str());
+ DCHECK_EQ(static_cast<int>(pipe_name.length()), path_len);
+ size_t server_unix_addr_len = offsetof(struct sockaddr_un,
+ sun_path) + path_len + 1;
+
+ if (HANDLE_EINTR(connect(fd, reinterpret_cast<sockaddr*>(&server_unix_addr),
+ server_unix_addr_len)) != 0) {
+ PLOG(ERROR) << "connect " << pipe_name;
+ if (HANDLE_EINTR(close(fd)) < 0)
+ PLOG(ERROR) << "close " << pipe_name;
+ return false;
+ }
+
+ *client_socket = fd;
+ return true;
+}
+
+bool SocketWriteErrorIsRecoverable() {
+#if defined(OS_MACOSX)
+ // On OS X if sendmsg() is trying to send fds between processes and there
+ // isn't enough room in the output buffer to send the fd structure over
+ // atomically then EMSGSIZE is returned.
+ //
+ // EMSGSIZE presents a problem since the system APIs can only call us when
+ // there's room in the socket buffer and not when there is "enough" room.
+ //
+ // The current behavior is to return to the event loop when EMSGSIZE is
+ // received and hopefull service another FD. This is however still
+ // technically a busy wait since the event loop will call us right back until
+ // the receiver has read enough data to allow passing the FD over atomically.
+ return errno == EAGAIN || errno == EMSGSIZE;
+#else
+ return errno == EAGAIN;
+#endif // OS_MACOSX
+}
+
+} // namespace
+//------------------------------------------------------------------------------
+
+Channel::ChannelImpl::ChannelImpl(const IPC::ChannelHandle& channel_handle,
+ Mode mode, Listener* listener)
+ : mode_(mode),
+ is_blocked_on_write_(false),
+ waiting_connect_(true),
+ message_send_bytes_written_(0),
+ server_listen_pipe_(-1),
+ pipe_(-1),
+ client_pipe_(-1),
+#if defined(IPC_USES_READWRITE)
+ fd_pipe_(-1),
+ remote_fd_pipe_(-1),
+#endif // IPC_USES_READWRITE
+ pipe_name_(channel_handle.name),
+ listener_(listener),
+ must_unlink_(false) {
+ memset(input_buf_, 0, sizeof(input_buf_));
+ memset(input_cmsg_buf_, 0, sizeof(input_cmsg_buf_));
+ if (!CreatePipe(channel_handle)) {
+ // The pipe may have been closed already.
+ const char *modestr = (mode_ & MODE_SERVER_FLAG) ? "server" : "client";
+ // The pipe may have been closed already.
+ LOG(WARNING) << "Unable to create pipe named \"" << channel_handle.name
+ << "\" in " << modestr << " mode";
+ }
+}
+
+Channel::ChannelImpl::~ChannelImpl() {
+ Close();
+}
+
+bool SocketPair(int* fd1, int* fd2) {
+ int pipe_fds[2];
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, pipe_fds) != 0) {
+ PLOG(ERROR) << "socketpair()";
+ return false;
+ }
+
+ // Set both ends to be non-blocking.
+ if (fcntl(pipe_fds[0], F_SETFL, O_NONBLOCK) == -1 ||
+ fcntl(pipe_fds[1], F_SETFL, O_NONBLOCK) == -1) {
+ PLOG(ERROR) << "fcntl(O_NONBLOCK)";
+ if (HANDLE_EINTR(close(pipe_fds[0])) < 0)
+ PLOG(ERROR) << "close";
+ if (HANDLE_EINTR(close(pipe_fds[1])) < 0)
+ PLOG(ERROR) << "close";
+ return false;
+ }
+
+ *fd1 = pipe_fds[0];
+ *fd2 = pipe_fds[1];
+
+ return true;
+}
+
+bool Channel::ChannelImpl::CreatePipe(
+ const IPC::ChannelHandle& channel_handle) {
+ DCHECK(server_listen_pipe_ == -1 && pipe_ == -1);
+
+ // Four possible cases:
+ // 1) It's a channel wrapping a pipe that is given to us.
+ // 2) It's for a named channel, so we create it.
+ // 3) It's for a client that we implement ourself. This is used
+ // in unittesting.
+ // 4) It's the initial IPC channel:
+ // 4a) Client side: Pull the pipe out of the GlobalDescriptors set.
+ // 4b) Server side: create the pipe.
+
+ int local_pipe = -1;
+ if (channel_handle.socket.fd != -1) {
+ // Case 1 from comment above.
+ local_pipe = channel_handle.socket.fd;
+#if defined(IPC_USES_READWRITE)
+ // Test the socket passed into us to make sure it is nonblocking.
+ // We don't want to call read/write on a blocking socket.
+ int value = fcntl(local_pipe, F_GETFL);
+ if (value == -1) {
+ PLOG(ERROR) << "fcntl(F_GETFL) " << pipe_name_;
+ return false;
+ }
+ if (!(value & O_NONBLOCK)) {
+ LOG(ERROR) << "Socket " << pipe_name_ << " must be O_NONBLOCK";
+ return false;
+ }
+#endif // IPC_USES_READWRITE
+ } else if (mode_ & MODE_NAMED_FLAG) {
+ // Case 2 from comment above.
+ if (mode_ & MODE_SERVER_FLAG) {
+ if (!CreateServerUnixDomainSocket(pipe_name_, &local_pipe)) {
+ return false;
+ }
+ must_unlink_ = true;
+ } else if (mode_ & MODE_CLIENT_FLAG) {
+ if (!CreateClientUnixDomainSocket(pipe_name_, &local_pipe)) {
+ return false;
+ }
+ } else {
+ LOG(ERROR) << "Bad mode: " << mode_;
+ return false;
+ }
+ } else {
+ local_pipe = PipeMap::GetInstance()->Lookup(pipe_name_);
+ if (mode_ & MODE_CLIENT_FLAG) {
+ if (local_pipe != -1) {
+ // Case 3 from comment above.
+ // We only allow one connection.
+ local_pipe = HANDLE_EINTR(dup(local_pipe));
+ PipeMap::GetInstance()->RemoveAndClose(pipe_name_);
+ } else {
+ // Case 4a from comment above.
+ // Guard against inappropriate reuse of the initial IPC channel. If
+ // an IPC channel closes and someone attempts to reuse it by name, the
+ // initial channel must not be recycled here. http://crbug.com/26754.
+ static bool used_initial_channel = false;
+ if (used_initial_channel) {
+ LOG(FATAL) << "Denying attempt to reuse initial IPC channel for "
+ << pipe_name_;
+ return false;
+ }
+ used_initial_channel = true;
+
+ local_pipe =
+ base::GlobalDescriptors::GetInstance()->Get(kPrimaryIPCChannel);
+ }
+ } else if (mode_ & MODE_SERVER_FLAG) {
+ // Case 4b from comment above.
+ if (local_pipe != -1) {
+ LOG(ERROR) << "Server already exists for " << pipe_name_;
+ return false;
+ }
+ if (!SocketPair(&local_pipe, &client_pipe_))
+ return false;
+ PipeMap::GetInstance()->Insert(pipe_name_, client_pipe_);
+ } else {
+ LOG(ERROR) << "Bad mode: " << mode_;
+ return false;
+ }
+ }
+
+#if defined(IPC_USES_READWRITE)
+ // Create a dedicated socketpair() for exchanging file descriptors.
+ // See comments for IPC_USES_READWRITE for details.
+ if (mode_ & MODE_CLIENT_FLAG) {
+ if (!SocketPair(&fd_pipe_, &remote_fd_pipe_)) {
+ return false;
+ }
+ }
+#endif // IPC_USES_READWRITE
+
+ if ((mode_ & MODE_SERVER_FLAG) && (mode_ & MODE_NAMED_FLAG)) {
+ server_listen_pipe_ = local_pipe;
+ local_pipe = -1;
+ }
+
+ pipe_ = local_pipe;
+ return true;
+}
+
+bool Channel::ChannelImpl::Connect() {
+ if (server_listen_pipe_ == -1 && pipe_ == -1) {
+ DLOG(INFO) << "Channel creation failed: " << pipe_name_;
+ return false;
+ }
+
+ bool did_connect = true;
+ if (server_listen_pipe_ != -1) {
+ // Watch the pipe for connections, and turn any connections into
+ // active sockets.
+ MessageLoopForIO::current()->WatchFileDescriptor(
+ server_listen_pipe_,
+ true,
+ MessageLoopForIO::WATCH_READ,
+ &server_listen_connection_watcher_,
+ this);
+ } else {
+ did_connect = AcceptConnection();
+ }
+ return did_connect;
+}
+
+bool Channel::ChannelImpl::ProcessIncomingMessages() {
+ ssize_t bytes_read = 0;
+
+ struct msghdr msg = {0};
+ struct iovec iov = {input_buf_, Channel::kReadBufferSize};
+
+ msg.msg_iovlen = 1;
+ msg.msg_control = input_cmsg_buf_;
+
+ for (;;) {
+ msg.msg_iov = &iov;
+
+ if (bytes_read == 0) {
+ if (pipe_ == -1)
+ return false;
+
+ // Read from pipe.
+ // recvmsg() returns 0 if the connection has closed or EAGAIN if no data
+ // is waiting on the pipe.
+#if defined(IPC_USES_READWRITE)
+ if (fd_pipe_ >= 0) {
+ bytes_read = HANDLE_EINTR(read(pipe_, input_buf_,
+ Channel::kReadBufferSize));
+ msg.msg_controllen = 0;
+ } else
+#endif // IPC_USES_READWRITE
+ {
+ msg.msg_controllen = sizeof(input_cmsg_buf_);
+ bytes_read = HANDLE_EINTR(recvmsg(pipe_, &msg, MSG_DONTWAIT));
+ }
+ if (bytes_read < 0) {
+ if (errno == EAGAIN) {
+ return true;
+#if defined(OS_MACOSX)
+ } else if (errno == EPERM) {
+ // On OSX, reading from a pipe with no listener returns EPERM
+ // treat this as a special case to prevent spurious error messages
+ // to the console.
+ return false;
+#endif // OS_MACOSX
+ } else if (errno == ECONNRESET || errno == EPIPE) {
+ return false;
+ } else {
+ PLOG(ERROR) << "pipe error (" << pipe_ << ")";
+ return false;
+ }
+ } else if (bytes_read == 0) {
+ // The pipe has closed...
+ return false;
+ }
+ }
+ DCHECK(bytes_read);
+
+ if (client_pipe_ != -1) {
+ PipeMap::GetInstance()->RemoveAndClose(pipe_name_);
+ client_pipe_ = -1;
+ }
+
+ // a pointer to an array of |num_wire_fds| file descriptors from the read
+ const int* wire_fds = NULL;
+ unsigned num_wire_fds = 0;
+
+ // walk the list of control messages and, if we find an array of file
+ // descriptors, save a pointer to the array
+
+ // This next if statement is to work around an OSX issue where
+ // CMSG_FIRSTHDR will return non-NULL in the case that controllen == 0.
+ // Here's a test case:
+ //
+ // int main() {
+ // struct msghdr msg;
+ // msg.msg_control = &msg;
+ // msg.msg_controllen = 0;
+ // if (CMSG_FIRSTHDR(&msg))
+ // printf("Bug found!\n");
+ // }
+ if (msg.msg_controllen > 0) {
+ // On OSX, CMSG_FIRSTHDR doesn't handle the case where controllen is 0
+ // and will return a pointer into nowhere.
+ for (struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); cmsg;
+ cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+ if (cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SCM_RIGHTS) {
+ const unsigned payload_len = cmsg->cmsg_len - CMSG_LEN(0);
+ DCHECK_EQ(0U, payload_len % sizeof(int));
+ wire_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
+ num_wire_fds = payload_len / 4;
+
+ if (msg.msg_flags & MSG_CTRUNC) {
+ LOG(ERROR) << "SCM_RIGHTS message was truncated"
+ << " cmsg_len:" << cmsg->cmsg_len
+ << " fd:" << pipe_;
+ for (unsigned i = 0; i < num_wire_fds; ++i)
+ if (HANDLE_EINTR(close(wire_fds[i])) < 0)
+ PLOG(ERROR) << "close " << i;
+ return false;
+ }
+ break;
+ }
+ }
+ }
+
+ // Process messages from input buffer.
+ const char *p;
+ const char *end;
+ if (input_overflow_buf_.empty()) {
+ p = input_buf_;
+ end = p + bytes_read;
+ } else {
+ if (input_overflow_buf_.size() >
+ static_cast<size_t>(kMaximumMessageSize - bytes_read)) {
+ input_overflow_buf_.clear();
+ LOG(ERROR) << "IPC message is too big";
+ return false;
+ }
+ input_overflow_buf_.append(input_buf_, bytes_read);
+ p = input_overflow_buf_.data();
+ end = p + input_overflow_buf_.size();
+ }
+
+ // A pointer to an array of |num_fds| file descriptors which includes any
+ // fds that have spilled over from a previous read.
+ const int* fds = NULL;
+ unsigned num_fds = 0;
+ unsigned fds_i = 0; // the index of the first unused descriptor
+
+ if (input_overflow_fds_.empty()) {
+ fds = wire_fds;
+ num_fds = num_wire_fds;
+ } else {
+ if (num_wire_fds > 0) {
+ const size_t prev_size = input_overflow_fds_.size();
+ input_overflow_fds_.resize(prev_size + num_wire_fds);
+ memcpy(&input_overflow_fds_[prev_size], wire_fds,
+ num_wire_fds * sizeof(int));
+ }
+ fds = &input_overflow_fds_[0];
+ num_fds = input_overflow_fds_.size();
+ }
+
+ while (p < end) {
+ const char* message_tail = Message::FindNext(p, end);
+ if (message_tail) {
+ int len = static_cast<int>(message_tail - p);
+ Message m(p, len);
+ const uint16 header_fds = m.header()->num_fds;
+ if (header_fds) {
+ // the message has file descriptors
+ const char* error = NULL;
+ if (header_fds > num_fds - fds_i) {
+ // the message has been completely received, but we didn't get
+ // enough file descriptors.
+#if defined(IPC_USES_READWRITE)
+ char dummy;
+ struct iovec fd_pipe_iov = { &dummy, 1 };
+ msg.msg_iov = &fd_pipe_iov;
+ msg.msg_controllen = sizeof(input_cmsg_buf_);
+ ssize_t n = HANDLE_EINTR(recvmsg(fd_pipe_, &msg, MSG_DONTWAIT));
+ if (n == 1 && msg.msg_controllen > 0) {
+ for (struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); cmsg;
+ cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+ if (cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SCM_RIGHTS) {
+ const unsigned payload_len = cmsg->cmsg_len - CMSG_LEN(0);
+ DCHECK_EQ(0U, payload_len % sizeof(int));
+ wire_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
+ num_wire_fds = payload_len / 4;
+
+ if (msg.msg_flags & MSG_CTRUNC) {
+ LOG(ERROR) << "SCM_RIGHTS message was truncated"
+ << " cmsg_len:" << cmsg->cmsg_len
+ << " fd:" << pipe_;
+ for (unsigned i = 0; i < num_wire_fds; ++i)
+ if (HANDLE_EINTR(close(wire_fds[i])) < 0)
+ PLOG(ERROR) << "close " << i;
+ return false;
+ }
+ break;
+ }
+ }
+ if (input_overflow_fds_.empty()) {
+ fds = wire_fds;
+ num_fds = num_wire_fds;
+ } else {
+ if (num_wire_fds > 0) {
+ const size_t prev_size = input_overflow_fds_.size();
+ input_overflow_fds_.resize(prev_size + num_wire_fds);
+ memcpy(&input_overflow_fds_[prev_size], wire_fds,
+ num_wire_fds * sizeof(int));
+ }
+ fds = &input_overflow_fds_[0];
+ num_fds = input_overflow_fds_.size();
+ }
+ }
+ if (header_fds > num_fds - fds_i)
+#endif // IPC_USES_READWRITE
+ error = "Message needs unreceived descriptors";
+ }
+
+ if (header_fds >
+ FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE) {
+ // There are too many descriptors in this message
+ error = "Message requires an excessive number of descriptors";
+ }
+
+ if (error) {
+ LOG(WARNING) << error
+ << " channel:" << this
+ << " message-type:" << m.type()
+ << " header()->num_fds:" << header_fds
+ << " num_fds:" << num_fds
+ << " fds_i:" << fds_i;
+#if defined(CHROMIUM_SELINUX)
+ LOG(WARNING) << "In the case of SELinux this can be caused when "
+ "using a --user-data-dir to which the default "
+ "policy doesn't give the renderer access to. ";
+#endif // CHROMIUM_SELINUX
+ // close the existing file descriptors so that we don't leak them
+ for (unsigned i = fds_i; i < num_fds; ++i)
+ if (HANDLE_EINTR(close(fds[i])) < 0)
+ PLOG(ERROR) << "close " << i;
+ input_overflow_fds_.clear();
+ // abort the connection
+ return false;
+ }
+
+ m.file_descriptor_set()->SetDescriptors(
+ &fds[fds_i], header_fds);
+ fds_i += header_fds;
+ }
+ DVLOG(2) << "received message on channel @" << this
+ << " with type " << m.type() << " on fd " << pipe_;
+ if (IsHelloMessage(&m)) {
+ // The Hello message contains only the process id.
+ void *iter = NULL;
+ int pid;
+ if (!m.ReadInt(&iter, &pid)) {
+ NOTREACHED();
+ }
+#if defined(IPC_USES_READWRITE)
+ if (mode_ & MODE_SERVER_FLAG) {
+ // With IPC_USES_READWRITE, the Hello message from the client to the
+ // server also contains the fd_pipe_, which will be used for all
+ // subsequent file descriptor passing.
+ DCHECK_EQ(m.file_descriptor_set()->size(), 1U);
+ base::FileDescriptor descriptor;
+ if (!m.ReadFileDescriptor(&iter, &descriptor)) {
+ NOTREACHED();
+ }
+ fd_pipe_ = descriptor.fd;
+ CHECK(descriptor.auto_close);
+ }
+#endif // IPC_USES_READWRITE
+ listener_->OnChannelConnected(pid);
+ } else {
+ listener_->OnMessageReceived(m);
+ }
+ p = message_tail;
+ } else {
+ // Last message is partial.
+ break;
+ }
+ input_overflow_fds_ = std::vector<int>(&fds[fds_i], &fds[num_fds]);
+ fds_i = 0;
+ fds = vector_as_array(&input_overflow_fds_);
+ num_fds = input_overflow_fds_.size();
+ }
+ input_overflow_buf_.assign(p, end - p);
+ input_overflow_fds_ = std::vector<int>(&fds[fds_i], &fds[num_fds]);
+
+ // When the input data buffer is empty, the overflow fds should be too. If
+ // this is not the case, we probably have a rogue renderer which is trying
+ // to fill our descriptor table.
+ if (input_overflow_buf_.empty() && !input_overflow_fds_.empty()) {
+ // We close these descriptors in Close()
+ return false;
+ }
+
+ bytes_read = 0; // Get more data.
+ }
+}
+
+bool Channel::ChannelImpl::ProcessOutgoingMessages() {
+ DCHECK(!waiting_connect_); // Why are we trying to send messages if there's
+ // no connection?
+ if (output_queue_.empty())
+ return true;
+
+ if (pipe_ == -1)
+ return false;
+
+ // Write out all the messages we can till the write blocks or there are no
+ // more outgoing messages.
+ while (!output_queue_.empty()) {
+ Message* msg = output_queue_.front();
+
+ size_t amt_to_write = msg->size() - message_send_bytes_written_;
+ DCHECK_NE(0U, amt_to_write);
+ const char* out_bytes = reinterpret_cast<const char*>(msg->data()) +
+ message_send_bytes_written_;
+
+ struct msghdr msgh = {0};
+ struct iovec iov = {const_cast<char*>(out_bytes), amt_to_write};
+ msgh.msg_iov = &iov;
+ msgh.msg_iovlen = 1;
+ char buf[CMSG_SPACE(
+ sizeof(int[FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE]))];
+
+ ssize_t bytes_written = 1;
+ int fd_written = -1;
+/*
+ if (message_send_bytes_written_ == 0 &&
+ !msg->file_descriptor_set()->empty()) {
+ // This is the first chunk of a message which has descriptors to send
+ struct cmsghdr *cmsg;
+ const unsigned num_fds = msg->file_descriptor_set()->size();
+
+ DCHECK_LE(num_fds, FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE);
+ if (msg->file_descriptor_set()->ContainsDirectoryDescriptor()) {
+ LOG(FATAL) << "Panic: attempting to transport directory descriptor over"
+ " IPC. Aborting to maintain sandbox isolation.";
+ // If you have hit this then something tried to send a file descriptor
+ // to a directory over an IPC channel. Since IPC channels span
+ // sandboxes this is very bad: the receiving process can use openat
+ // with ".." elements in the path in order to reach the real
+ // filesystem.
+ }
+
+ msgh.msg_control = buf;
+ msgh.msg_controllen = CMSG_SPACE(sizeof(int) * num_fds);
+ cmsg = CMSG_FIRSTHDR(&msgh);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(int) * num_fds);
+ msg->file_descriptor_set()->GetDescriptors(
+ reinterpret_cast<int*>(CMSG_DATA(cmsg)));
+ msgh.msg_controllen = cmsg->cmsg_len;
+
+ // DCHECK_LE above already checks that
+ // num_fds < MAX_DESCRIPTORS_PER_MESSAGE so no danger of overflow.
+ msg->header()->num_fds = static_cast<uint16>(num_fds);
+
+#if defined(IPC_USES_READWRITE)
+ if (!IsHelloMessage(msg)) {
+ // Only the Hello message sends the file descriptor with the message.
+ // Subsequently, we can send file descriptors on the dedicated
+ // fd_pipe_ which makes Seccomp sandbox operation more efficient.
+ struct iovec fd_pipe_iov = { const_cast<char *>(""), 1 };
+ msgh.msg_iov = &fd_pipe_iov;
+ fd_written = fd_pipe_;
+ bytes_written = HANDLE_EINTR(sendmsg(fd_pipe_, &msgh, MSG_DONTWAIT));
+ msgh.msg_iov = &iov;
+ msgh.msg_controllen = 0;
+ if (bytes_written > 0) {
+ msg->file_descriptor_set()->CommitAll();
+ }
+ }
+#endif // IPC_USES_READWRITE
+ }
+
+*/
+ if (bytes_written == 1) {
+ fd_written = pipe_;
+#if defined(IPC_USES_READWRITE)
+ if ((mode_ & MODE_CLIENT_FLAG) && IsHelloMessage(msg)) {
+ DCHECK_EQ(msg->file_descriptor_set()->size(), 1U);
+ }
+ if (!msgh.msg_controllen) {
+ bytes_written = HANDLE_EINTR(write(pipe_, out_bytes, amt_to_write));
+ } else
+#endif // IPC_USES_READWRITE
+ {
+ bytes_written = HANDLE_EINTR(sendmsg(pipe_, &msgh, MSG_DONTWAIT));
+ }
+ }
+ if (bytes_written > 0)
+ msg->file_descriptor_set()->CommitAll();
+
+ if (bytes_written < 0 && !SocketWriteErrorIsRecoverable()) {
+#if defined(OS_MACOSX)
+ // On OSX writing to a pipe with no listener returns EPERM.
+ if (errno == EPERM) {
+ Close();
+ return false;
+ }
+#endif // OS_MACOSX
+ if (errno == EPIPE) {
+ Close();
+ return false;
+ }
+ PLOG(ERROR) << "pipe error on "
+ << fd_written
+ << " Currently writing message of size: "
+ << msg->size();
+ return false;
+ }
+
+ if (static_cast<size_t>(bytes_written) != amt_to_write) {
+ if (bytes_written > 0) {
+ // If write() fails with EAGAIN then bytes_written will be -1.
+ message_send_bytes_written_ += bytes_written;
+ }
+
+ // Tell libevent to call us back once things are unblocked.
+ is_blocked_on_write_ = true;
+ MessageLoopForIO::current()->WatchFileDescriptor(
+ pipe_,
+ false, // One shot
+ MessageLoopForIO::WATCH_WRITE,
+ &write_watcher_,
+ this);
+ return true;
+ } else {
+ message_send_bytes_written_ = 0;
+
+ // Message sent OK!
+ DVLOG(2) << "sent message @" << msg << " on channel @" << this
+ << " with type " << msg->type() << " on fd " << pipe_;
+ delete output_queue_.front();
+ output_queue_.pop();
+ }
+ }
+ return true;
+}
+
+bool Channel::ChannelImpl::Send(Message* message) {
+ DVLOG(2) << "sending message @" << message << " on channel @" << this
+ << " with type " << message->type()
+ << " (" << output_queue_.size() << " in queue)";
+
+#ifdef IPC_MESSAGE_LOG_ENABLED
+ Logging::GetInstance()->OnSendMessage(message, "");
+#endif // IPC_MESSAGE_LOG_ENABLED
+
+ output_queue_.push(message);
+ if (!is_blocked_on_write_ && !waiting_connect_) {
+ return ProcessOutgoingMessages();
+ }
+
+ return true;
+}
+
+int Channel::ChannelImpl::GetClientFileDescriptor() const {
+ return client_pipe_;
+}
+
+bool Channel::ChannelImpl::AcceptsConnections() const {
+ return server_listen_pipe_ != -1;
+}
+
+bool Channel::ChannelImpl::HasAcceptedConnection() const {
+ return AcceptsConnections() && pipe_ != -1;
+}
+
+bool Channel::ChannelImpl::GetClientEuid(uid_t* client_euid) const {
+ DCHECK(HasAcceptedConnection());
+#if defined(OS_MACOSX)
+ uid_t peer_euid;
+ gid_t peer_gid;
+ if (getpeereid(pipe_, &peer_euid, &peer_gid) != 0) {
+ PLOG(ERROR) << "getpeereid " << pipe_;
+ return false;
+ }
+ *client_euid = peer_euid;
+ return true;
+#elif defined(OS_SOLARIS)
+ return false;
+#else
+ struct ucred cred;
+ socklen_t cred_len = sizeof(cred);
+ if (getsockopt(pipe_, SOL_SOCKET, SO_PEERCRED, &cred, &cred_len) != 0) {
+ PLOG(ERROR) << "getsockopt " << pipe_;
+ return false;
+ }
+ if (cred_len < sizeof(cred)) {
+ NOTREACHED() << "Truncated ucred from SO_PEERCRED?";
+ return false;
+ }
+ *client_euid = cred.uid;
+ return true;
+#endif
+}
+
+void Channel::ChannelImpl::ResetToAcceptingConnectionState() {
+ // Unregister libevent for the unix domain socket and close it.
+ read_watcher_.StopWatchingFileDescriptor();
+ write_watcher_.StopWatchingFileDescriptor();
+ if (pipe_ != -1) {
+ if (HANDLE_EINTR(close(pipe_)) < 0)
+ PLOG(ERROR) << "close pipe_ " << pipe_name_;
+ pipe_ = -1;
+ }
+#if defined(IPC_USES_READWRITE)
+ if (fd_pipe_ != -1) {
+ if (HANDLE_EINTR(close(fd_pipe_)) < 0)
+ PLOG(ERROR) << "close fd_pipe_ " << pipe_name_;
+ fd_pipe_ = -1;
+ }
+ if (remote_fd_pipe_ != -1) {
+ if (HANDLE_EINTR(close(remote_fd_pipe_)) < 0)
+ PLOG(ERROR) << "close remote_fd_pipe_ " << pipe_name_;
+ remote_fd_pipe_ = -1;
+ }
+#endif // IPC_USES_READWRITE
+
+ while (!output_queue_.empty()) {
+ Message* m = output_queue_.front();
+ output_queue_.pop();
+ delete m;
+ }
+
+ // Close any outstanding, received file descriptors.
+ for (std::vector<int>::iterator
+ i = input_overflow_fds_.begin(); i != input_overflow_fds_.end(); ++i) {
+ if (HANDLE_EINTR(close(*i)) < 0)
+ PLOG(ERROR) << "close";
+ }
+ input_overflow_fds_.clear();
+}
+
+// static
+bool Channel::ChannelImpl::IsNamedServerInitialized(
+ const std::string& channel_id) {
+ return file_util::PathExists(FilePath(channel_id));
+}
+
+// Called by libevent when we can read from the pipe without blocking.
+void Channel::ChannelImpl::OnFileCanReadWithoutBlocking(int fd) {
+ bool send_server_hello_msg = false;
+ if (fd == server_listen_pipe_) {
+ int new_pipe = 0;
+ if (!ServerAcceptConnection(server_listen_pipe_, &new_pipe)) {
+ Close();
+ listener_->OnChannelListenError();
+ }
+
+ if (pipe_ != -1) {
+ // We already have a connection. We only handle one at a time.
+ // close our new descriptor.
+ if (HANDLE_EINTR(shutdown(new_pipe, SHUT_RDWR)) < 0)
+ PLOG(ERROR) << "shutdown " << pipe_name_;
+ if (HANDLE_EINTR(close(new_pipe)) < 0)
+ PLOG(ERROR) << "close " << pipe_name_;
+ listener_->OnChannelDenied();
+ return;
+ }
+ pipe_ = new_pipe;
+
+ if ((mode_ & MODE_OPEN_ACCESS_FLAG) == 0) {
+ // Verify that the IPC channel peer is running as the same user.
+ uid_t client_euid;
+ if (!GetClientEuid(&client_euid)) {
+ LOG(ERROR) << "Unable to query client euid";
+ ResetToAcceptingConnectionState();
+ return;
+ }
+ if (client_euid != geteuid()) {
+ LOG(WARNING) << "Client euid is not authorised";
+ ResetToAcceptingConnectionState();
+ return;
+ }
+ }
+
+ if (!AcceptConnection()) {
+ NOTREACHED() << "AcceptConnection should not fail on server";
+ }
+ send_server_hello_msg = true;
+ waiting_connect_ = false;
+ } else if (fd == pipe_) {
+ if (waiting_connect_ && (mode_ & MODE_SERVER_FLAG)) {
+ send_server_hello_msg = true;
+ waiting_connect_ = false;
+ }
+ if (!ProcessIncomingMessages()) {
+ // ClosePipeOnError may delete this object, so we mustn't call
+ // ProcessOutgoingMessages.
+ send_server_hello_msg = false;
+ ClosePipeOnError();
+ }
+ } else {
+ NOTREACHED() << "Unknown pipe " << fd;
+ }
+
+ // If we're a server and handshaking, then we want to make sure that we
+ // only send our handshake message after we've processed the client's.
+ // This gives us a chance to kill the client if the incoming handshake
+ // is invalid.
+ if (send_server_hello_msg) {
+ ProcessOutgoingMessages();
+ }
+}
+
+// Called by libevent when we can write to the pipe without blocking.
+void Channel::ChannelImpl::OnFileCanWriteWithoutBlocking(int fd) {
+ DCHECK_EQ(pipe_, fd);
+ is_blocked_on_write_ = false;
+ if (!ProcessOutgoingMessages()) {
+ ClosePipeOnError();
+ }
+}
+
+bool Channel::ChannelImpl::AcceptConnection() {
+ MessageLoopForIO::current()->WatchFileDescriptor(pipe_,
+ true,
+ MessageLoopForIO::WATCH_READ,
+ &read_watcher_,
+ this);
+ QueueHelloMessage();
+
+ if (mode_ & MODE_CLIENT_FLAG) {
+ // If we are a client we want to send a hello message out immediately.
+ // In server mode we will send a hello message when we receive one from a
+ // client.
+ waiting_connect_ = false;
+ return ProcessOutgoingMessages();
+ } else if (mode_ & MODE_SERVER_FLAG) {
+ waiting_connect_ = true;
+ return true;
+ } else {
+ NOTREACHED();
+ return false;
+ }
+}
+
+void Channel::ChannelImpl::ClosePipeOnError() {
+ if (HasAcceptedConnection()) {
+ ResetToAcceptingConnectionState();
+ listener_->OnChannelError();
+ } else {
+ Close();
+ if (AcceptsConnections()) {
+ listener_->OnChannelListenError();
+ } else {
+ listener_->OnChannelError();
+ }
+ }
+}
+
+void Channel::ChannelImpl::QueueHelloMessage() {
+ // Create the Hello message
+ scoped_ptr<Message> msg(new Message(MSG_ROUTING_NONE,
+ HELLO_MESSAGE_TYPE,
+ IPC::Message::PRIORITY_NORMAL));
+
+ if (!msg->WriteInt(base::GetCurrentProcId())) {
+ NOTREACHED() << "Unable to pickle hello message proc id";
+ }
+#if defined(IPC_USES_READWRITE)
+ scoped_ptr<Message> hello;
+ if (remote_fd_pipe_ != -1) {
+ if (!msg->WriteFileDescriptor(base::FileDescriptor(remote_fd_pipe_,
+ false))) {
+ NOTREACHED() << "Unable to pickle hello message file descriptors";
+ }
+ DCHECK_EQ(msg->file_descriptor_set()->size(), 1U);
+ }
+#endif // IPC_USES_READWRITE
+ output_queue_.push(msg.release());
+}
+
+bool Channel::ChannelImpl::IsHelloMessage(const Message* m) const {
+ return m->routing_id() == MSG_ROUTING_NONE && m->type() == HELLO_MESSAGE_TYPE;
+}
+
+void Channel::ChannelImpl::Close() {
+ // Close can be called multiple time, so we need to make sure we're
+ // idempotent.
+
+ ResetToAcceptingConnectionState();
+
+ if (must_unlink_) {
+ unlink(pipe_name_.c_str());
+ must_unlink_ = false;
+ }
+ if (server_listen_pipe_ != -1) {
+ if (HANDLE_EINTR(close(server_listen_pipe_)) < 0)
+ PLOG(ERROR) << "close " << server_listen_pipe_;
+ server_listen_pipe_ = -1;
+ // Unregister libevent for the listening socket and close it.
+ server_listen_connection_watcher_.StopWatchingFileDescriptor();
+ }
+
+ if (client_pipe_ != -1) {
+ PipeMap::GetInstance()->RemoveAndClose(pipe_name_);
+ client_pipe_ = -1;
+ }
+}
+
+//------------------------------------------------------------------------------
+// Channel's methods simply call through to ChannelImpl.
+Channel::Channel(const IPC::ChannelHandle& channel_handle, Mode mode,
+ Listener* listener)
+ : channel_impl_(new ChannelImpl(channel_handle, mode, listener)) {
+}
+
+Channel::~Channel() {
+ delete channel_impl_;
+}
+
+bool Channel::Connect() {
+ return channel_impl_->Connect();
+}
+
+void Channel::Close() {
+ channel_impl_->Close();
+}
+
+void Channel::set_listener(Listener* listener) {
+ channel_impl_->set_listener(listener);
+}
+
+bool Channel::Send(Message* message) {
+ return channel_impl_->Send(message);
+}
+
+int Channel::GetClientFileDescriptor() const {
+ return channel_impl_->GetClientFileDescriptor();
+}
+
+bool Channel::AcceptsConnections() const {
+ return channel_impl_->AcceptsConnections();
+}
+
+bool Channel::HasAcceptedConnection() const {
+ return channel_impl_->HasAcceptedConnection();
+}
+
+bool Channel::GetClientEuid(uid_t* client_euid) const {
+ return channel_impl_->GetClientEuid(client_euid);
+}
+
+void Channel::ResetToAcceptingConnectionState() {
+ channel_impl_->ResetToAcceptingConnectionState();
+}
+
+// static
+bool Channel::IsNamedServerInitialized(const std::string& channel_id) {
+ return ChannelImpl::IsNamedServerInitialized(channel_id);
+}
+
+} // namespace IPC
diff --git a/ipc/ipc_channel_posix.h b/ipc/ipc_channel_posix.h
new file mode 100644
index 000000000000..b66b1fcaf9b4
--- /dev/null
+++ b/ipc/ipc_channel_posix.h
@@ -0,0 +1,161 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IPC_IPC_CHANNEL_POSIX_H_
+#define IPC_IPC_CHANNEL_POSIX_H_
+#pragma once
+
+#include "ipc/ipc_channel.h"
+
+#include <sys/socket.h> // for CMSG macros
+
+#include <queue>
+#include <string>
+#include <vector>
+
+#include "base/message_loop.h"
+#include "ipc/file_descriptor_set_posix.h"
+
+#if !defined(OS_MACOSX)
+// On Linux, the seccomp sandbox makes it very expensive to call
+// recvmsg() and sendmsg(). The restriction on calling read() and write(), which
+// are cheap, is that we can't pass file descriptors over them.
+//
+// As we cannot anticipate when the sender will provide us with file
+// descriptors, we have to make the decision about whether we call read() or
+// recvmsg() before we actually make the call. The easiest option is to
+// create a dedicated socketpair() for exchanging file descriptors. Any file
+// descriptors are split out of a message, with the non-file-descriptor payload
+// going over the normal connection, and the file descriptors being sent
+// separately over the other channel. When read()ing from a channel, we'll
+// notice if the message was supposed to have come with file descriptors and
+// use recvmsg on the other socketpair to retrieve them and combine them
+// back with the rest of the message.
+//
+// Mac can also run in IPC_USES_READWRITE mode if necessary, but at this time
+// doesn't take a performance hit from recvmsg and sendmsg, so it doesn't
+// make sense to waste resources on having the separate dedicated socketpair.
+// It is however useful for debugging between Linux and Mac to be able to turn
+// this switch 'on' on the Mac as well.
+//
+// The HELLO message from the client to the server is always sent using
+// sendmsg because it will contain the file descriptor that the server
+// needs to send file descriptors in later messages.
+#define IPC_USES_READWRITE 1
+#endif
+
+namespace IPC {
+
+class Channel::ChannelImpl : public MessageLoopForIO::Watcher {
+ public:
+ // Mirror methods of Channel, see ipc_channel.h for description.
+ ChannelImpl(const IPC::ChannelHandle& channel_handle, Mode mode,
+ Listener* listener);
+ virtual ~ChannelImpl();
+ bool Connect();
+ void Close();
+ void set_listener(Listener* listener) { listener_ = listener; }
+ bool Send(Message* message);
+ int GetClientFileDescriptor() const;
+ bool AcceptsConnections() const;
+ bool HasAcceptedConnection() const;
+ bool GetClientEuid(uid_t* client_euid) const;
+ void ResetToAcceptingConnectionState();
+ static bool IsNamedServerInitialized(const std::string& channel_id);
+
+ private:
+ bool CreatePipe(const IPC::ChannelHandle& channel_handle);
+
+ bool ProcessIncomingMessages();
+ bool ProcessOutgoingMessages();
+
+ bool AcceptConnection();
+ void ClosePipeOnError();
+ void QueueHelloMessage();
+ bool IsHelloMessage(const Message* m) const;
+
+ // MessageLoopForIO::Watcher implementation.
+ virtual void OnFileCanReadWithoutBlocking(int fd);
+ virtual void OnFileCanWriteWithoutBlocking(int fd);
+
+ Mode mode_;
+
+ // After accepting one client connection on our server socket we want to
+ // stop listening.
+ MessageLoopForIO::FileDescriptorWatcher server_listen_connection_watcher_;
+ MessageLoopForIO::FileDescriptorWatcher read_watcher_;
+ MessageLoopForIO::FileDescriptorWatcher write_watcher_;
+
+ // Indicates whether we're currently blocked waiting for a write to complete.
+ bool is_blocked_on_write_;
+ bool waiting_connect_;
+
+ // If sending a message blocks then we use this variable
+ // to keep track of where we are.
+ size_t message_send_bytes_written_;
+
+ // File descriptor we're listening on for new connections if we listen
+ // for connections.
+ int server_listen_pipe_;
+
+ // The pipe used for communication.
+ int pipe_;
+
+ // For a server, the client end of our socketpair() -- the other end of our
+ // pipe_ that is passed to the client.
+ int client_pipe_;
+
+#if defined(IPC_USES_READWRITE)
+ // Linux/BSD use a dedicated socketpair() for passing file descriptors.
+ int fd_pipe_;
+ int remote_fd_pipe_;
+#endif
+
+ // The "name" of our pipe. On Windows this is the global identifier for
+ // the pipe. On POSIX it's used as a key in a local map of file descriptors.
+ std::string pipe_name_;
+
+ Listener* listener_;
+
+ // Messages to be sent are queued here.
+ std::queue<Message*> output_queue_;
+
+ // We read from the pipe into this buffer
+ char input_buf_[Channel::kReadBufferSize];
+
+ enum {
+ // We assume a worst case: kReadBufferSize bytes of messages, where each
+ // message has no payload and a full complement of descriptors.
+ MAX_READ_FDS = (Channel::kReadBufferSize / sizeof(IPC::Message::Header)) *
+ FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE,
+ };
+
+ // This is a control message buffer large enough to hold kMaxReadFDs
+#if defined(OS_MACOSX)
+ // TODO(agl): OSX appears to have non-constant CMSG macros!
+ char input_cmsg_buf_[1024];
+#else
+ char input_cmsg_buf_[CMSG_SPACE(sizeof(int) * MAX_READ_FDS)];
+#endif
+
+ // Large messages that span multiple pipe buffers, get built-up using
+ // this buffer.
+ std::string input_overflow_buf_;
+ std::vector<int> input_overflow_fds_;
+
+ // True if we are responsible for unlinking the unix domain socket file.
+ bool must_unlink_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ChannelImpl);
+};
+
+// The maximum length of the name of a pipe for MODE_NAMED_SERVER or
+// MODE_NAMED_CLIENT if you want to pass in your own socket.
+// The standard size on linux is 108, mac is 104. To maintain consistency
+// across platforms we standardize on the smaller value.
+static const size_t kMaxPipeNameLength = 104;
+
+} // namespace IPC
+
+#endif // IPC_IPC_CHANNEL_POSIX_H_
diff --git a/ipc/ipc_channel_posix_unittest.cc b/ipc/ipc_channel_posix_unittest.cc
new file mode 100644
index 000000000000..14ecc6083e54
--- /dev/null
+++ b/ipc/ipc_channel_posix_unittest.cc
@@ -0,0 +1,389 @@
+// 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.
+
+// These tests are POSIX only.
+
+#include "ipc/ipc_channel_posix.h"
+
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include "base/basictypes.h"
+#include "base/eintr_wrapper.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop.h"
+#include "base/test/multiprocess_test.h"
+#include "base/test/test_timeouts.h"
+#include "testing/multiprocess_func_list.h"
+
+namespace {
+
+enum {
+ QUIT_MESSAGE = 47
+};
+
+class IPCChannelPosixTestListener : public IPC::Channel::Listener {
+ public:
+ enum STATUS {
+ DISCONNECTED,
+ MESSAGE_RECEIVED,
+ CHANNEL_ERROR,
+ CONNECTED,
+ DENIED,
+ LISTEN_ERROR
+ };
+
+ IPCChannelPosixTestListener(bool quit_only_on_message)
+ : status_(DISCONNECTED), quit_only_on_message_(quit_only_on_message) {}
+
+ virtual ~IPCChannelPosixTestListener() {}
+
+ virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
+ EXPECT_EQ(message.type(), QUIT_MESSAGE);
+ status_ = MESSAGE_RECEIVED;
+ QuitRunLoop();
+ return true;
+ }
+
+ virtual void OnChannelConnected(int32 peer_pid) OVERRIDE {
+ status_ = CONNECTED;
+ if (!quit_only_on_message_) {
+ QuitRunLoop();
+ }
+ }
+
+ virtual void OnChannelError() OVERRIDE {
+ status_ = CHANNEL_ERROR;
+ if (!quit_only_on_message_) {
+ QuitRunLoop();
+ }
+ }
+
+ virtual void OnChannelDenied() OVERRIDE {
+ status_ = DENIED;
+ if (!quit_only_on_message_) {
+ QuitRunLoop();
+ }
+ }
+
+ virtual void OnChannelListenError() OVERRIDE {
+ status_ = LISTEN_ERROR;
+ if (!quit_only_on_message_) {
+ QuitRunLoop();
+ }
+ }
+
+ STATUS status() { return status_; }
+
+ void QuitRunLoop() {
+ MessageLoopForIO::current()->QuitNow();
+ }
+
+ private:
+ // The current status of the listener.
+ STATUS status_;
+ // If |quit_only_on_message_| then the listener will only break out of
+ // the run loop when the QUIT_MESSAGE is received.
+ bool quit_only_on_message_;
+};
+
+} // namespace
+
+class IPCChannelPosixTest : public base::MultiProcessTest {
+ public:
+ static const char kConnectionSocketTestName[];
+ static void SetUpSocket(IPC::ChannelHandle *handle,
+ IPC::Channel::Mode mode);
+ static void SpinRunLoop(int milliseconds);
+
+ protected:
+ virtual void SetUp();
+ virtual void TearDown();
+
+private:
+ scoped_ptr<MessageLoopForIO> message_loop_;
+};
+
+const char IPCChannelPosixTest::kConnectionSocketTestName[] =
+ "/var/tmp/chrome_IPCChannelPosixTest__ConnectionSocket";
+
+void IPCChannelPosixTest::SetUp() {
+ MultiProcessTest::SetUp();
+ // Construct a fresh IO Message loop for the duration of each test.
+ message_loop_.reset(new MessageLoopForIO());
+}
+
+void IPCChannelPosixTest::TearDown() {
+ message_loop_.reset(NULL);
+ MultiProcessTest::TearDown();
+}
+
+// Create up a socket and bind and listen to it, or connect it
+// depending on the |mode|.
+void IPCChannelPosixTest::SetUpSocket(IPC::ChannelHandle *handle,
+ IPC::Channel::Mode mode) {
+ const std::string& name = handle->name;
+
+ int socket_fd = socket(PF_UNIX, SOCK_STREAM, 0);
+ ASSERT_GE(socket_fd, 0) << name;
+ ASSERT_GE(fcntl(socket_fd, F_SETFL, O_NONBLOCK), 0);
+ struct sockaddr_un server_address = { 0 };
+ memset(&server_address, 0, sizeof(server_address));
+ server_address.sun_family = AF_UNIX;
+ int path_len = snprintf(server_address.sun_path, IPC::kMaxPipeNameLength,
+ "%s", name.c_str());
+ DCHECK_EQ(static_cast<int>(name.length()), path_len);
+ size_t server_address_len = offsetof(struct sockaddr_un,
+ sun_path) + path_len + 1;
+
+ if (mode == IPC::Channel::MODE_NAMED_SERVER) {
+ // Only one server at a time. Cleanup garbage if it exists.
+ unlink(name.c_str());
+ // Make sure the path we need exists.
+ FilePath path(name);
+ FilePath dir_path = path.DirName();
+ ASSERT_TRUE(file_util::CreateDirectory(dir_path));
+ ASSERT_GE(bind(socket_fd,
+ reinterpret_cast<struct sockaddr *>(&server_address),
+ server_address_len), 0) << server_address.sun_path
+ << ": " << strerror(errno)
+ << "(" << errno << ")";
+ ASSERT_GE(listen(socket_fd, SOMAXCONN), 0) << server_address.sun_path
+ << ": " << strerror(errno)
+ << "(" << errno << ")";
+ } else if (mode == IPC::Channel::MODE_NAMED_CLIENT) {
+ ASSERT_GE(connect(socket_fd,
+ reinterpret_cast<struct sockaddr *>(&server_address),
+ server_address_len), 0) << server_address.sun_path
+ << ": " << strerror(errno)
+ << "(" << errno << ")";
+ } else {
+ FAIL() << "Unknown mode " << mode;
+ }
+ handle->socket.fd = socket_fd;
+}
+
+void IPCChannelPosixTest::SpinRunLoop(int milliseconds) {
+ MessageLoopForIO *loop = MessageLoopForIO::current();
+ // Post a quit task so that this loop eventually ends and we don't hang
+ // in the case of a bad test. Usually, the run loop will quit sooner than
+ // that because all tests use a IPCChannelPosixTestListener which quits the
+ // current run loop on any channel activity.
+ loop->PostDelayedTask(FROM_HERE, new MessageLoop::QuitTask(), milliseconds);
+ loop->Run();
+}
+
+TEST_F(IPCChannelPosixTest, BasicListen) {
+ // Test creating a socket that is listening.
+ IPC::ChannelHandle handle("/var/tmp/IPCChannelPosixTest_BasicListen");
+ SetUpSocket(&handle, IPC::Channel::MODE_NAMED_SERVER);
+ unlink(handle.name.c_str());
+ IPC::Channel channel(handle, IPC::Channel::MODE_NAMED_SERVER, NULL);
+ ASSERT_TRUE(channel.Connect());
+ ASSERT_TRUE(channel.AcceptsConnections());
+ ASSERT_FALSE(channel.HasAcceptedConnection());
+ channel.ResetToAcceptingConnectionState();
+ ASSERT_FALSE(channel.HasAcceptedConnection());
+}
+
+TEST_F(IPCChannelPosixTest, BasicConnected) {
+ // Test creating a socket that is connected.
+ int pipe_fds[2];
+ ASSERT_EQ(0, socketpair(AF_UNIX, SOCK_STREAM, 0, pipe_fds));
+ std::string socket_name("/var/tmp/IPCChannelPosixTest_BasicConnected");
+ ASSERT_GE(fcntl(pipe_fds[0], F_SETFL, O_NONBLOCK), 0);
+
+ base::FileDescriptor fd(pipe_fds[0], false);
+ IPC::ChannelHandle handle(socket_name, fd);
+ IPC::Channel channel(handle, IPC::Channel::MODE_SERVER, NULL);
+ ASSERT_TRUE(channel.Connect());
+ ASSERT_FALSE(channel.AcceptsConnections());
+ channel.Close();
+ ASSERT_TRUE(HANDLE_EINTR(close(pipe_fds[1])) == 0);
+
+ // Make sure that we can use the socket that is created for us by
+ // a standard channel.
+ IPC::Channel channel2(socket_name, IPC::Channel::MODE_SERVER, NULL);
+ ASSERT_TRUE(channel2.Connect());
+ ASSERT_FALSE(channel2.AcceptsConnections());
+}
+
+TEST_F(IPCChannelPosixTest, AdvancedConnected) {
+ // Test creating a connection to an external process.
+ IPCChannelPosixTestListener listener(false);
+ IPC::ChannelHandle chan_handle(kConnectionSocketTestName);
+ SetUpSocket(&chan_handle, IPC::Channel::MODE_NAMED_SERVER);
+ IPC::Channel channel(chan_handle, IPC::Channel::MODE_NAMED_SERVER, &listener);
+ ASSERT_TRUE(channel.Connect());
+ ASSERT_TRUE(channel.AcceptsConnections());
+ ASSERT_FALSE(channel.HasAcceptedConnection());
+
+ base::ProcessHandle handle = SpawnChild("IPCChannelPosixTestConnectionProc",
+ false);
+ ASSERT_TRUE(handle);
+ SpinRunLoop(TestTimeouts::action_max_timeout_ms());
+ ASSERT_EQ(IPCChannelPosixTestListener::CONNECTED, listener.status());
+ ASSERT_TRUE(channel.HasAcceptedConnection());
+ IPC::Message* message = new IPC::Message(0, // routing_id
+ QUIT_MESSAGE, // message type
+ IPC::Message::PRIORITY_NORMAL);
+ channel.Send(message);
+ SpinRunLoop(TestTimeouts::action_timeout_ms());
+ int exit_code = 0;
+ EXPECT_TRUE(base::WaitForExitCode(handle, &exit_code));
+ EXPECT_EQ(0, exit_code);
+ ASSERT_EQ(IPCChannelPosixTestListener::CHANNEL_ERROR, listener.status());
+ ASSERT_FALSE(channel.HasAcceptedConnection());
+}
+
+TEST_F(IPCChannelPosixTest, ResetState) {
+ // Test creating a connection to an external process. Close the connection,
+ // but continue to listen and make sure another external process can connect
+ // to us.
+ IPCChannelPosixTestListener listener(false);
+ IPC::ChannelHandle chan_handle(kConnectionSocketTestName);
+ SetUpSocket(&chan_handle, IPC::Channel::MODE_NAMED_SERVER);
+ IPC::Channel channel(chan_handle, IPC::Channel::MODE_NAMED_SERVER, &listener);
+ ASSERT_TRUE(channel.Connect());
+ ASSERT_TRUE(channel.AcceptsConnections());
+ ASSERT_FALSE(channel.HasAcceptedConnection());
+
+ base::ProcessHandle handle = SpawnChild("IPCChannelPosixTestConnectionProc",
+ false);
+ ASSERT_TRUE(handle);
+ SpinRunLoop(TestTimeouts::action_max_timeout_ms());
+ ASSERT_EQ(IPCChannelPosixTestListener::CONNECTED, listener.status());
+ ASSERT_TRUE(channel.HasAcceptedConnection());
+ channel.ResetToAcceptingConnectionState();
+ ASSERT_FALSE(channel.HasAcceptedConnection());
+
+ base::ProcessHandle handle2 = SpawnChild("IPCChannelPosixTestConnectionProc",
+ false);
+ ASSERT_TRUE(handle2);
+ SpinRunLoop(TestTimeouts::action_max_timeout_ms());
+ ASSERT_EQ(IPCChannelPosixTestListener::CONNECTED, listener.status());
+ ASSERT_TRUE(channel.HasAcceptedConnection());
+ IPC::Message* message = new IPC::Message(0, // routing_id
+ QUIT_MESSAGE, // message type
+ IPC::Message::PRIORITY_NORMAL);
+ channel.Send(message);
+ SpinRunLoop(TestTimeouts::action_timeout_ms());
+ EXPECT_TRUE(base::KillProcess(handle, 0, false));
+ int exit_code = 0;
+ EXPECT_TRUE(base::WaitForExitCode(handle2, &exit_code));
+ EXPECT_EQ(0, exit_code);
+ ASSERT_EQ(IPCChannelPosixTestListener::CHANNEL_ERROR, listener.status());
+ ASSERT_FALSE(channel.HasAcceptedConnection());
+}
+
+TEST_F(IPCChannelPosixTest, MultiConnection) {
+ // Test setting up a connection to an external process, and then have
+ // another external process attempt to connect to us.
+ IPCChannelPosixTestListener listener(false);
+ IPC::ChannelHandle chan_handle(kConnectionSocketTestName);
+ SetUpSocket(&chan_handle, IPC::Channel::MODE_NAMED_SERVER);
+ IPC::Channel channel(chan_handle, IPC::Channel::MODE_NAMED_SERVER, &listener);
+ ASSERT_TRUE(channel.Connect());
+ ASSERT_TRUE(channel.AcceptsConnections());
+ ASSERT_FALSE(channel.HasAcceptedConnection());
+
+ base::ProcessHandle handle = SpawnChild("IPCChannelPosixTestConnectionProc",
+ false);
+ ASSERT_TRUE(handle);
+ SpinRunLoop(TestTimeouts::action_max_timeout_ms());
+ ASSERT_EQ(IPCChannelPosixTestListener::CONNECTED, listener.status());
+ ASSERT_TRUE(channel.HasAcceptedConnection());
+ base::ProcessHandle handle2 = SpawnChild("IPCChannelPosixFailConnectionProc",
+ false);
+ ASSERT_TRUE(handle2);
+ SpinRunLoop(TestTimeouts::action_max_timeout_ms());
+ int exit_code = 0;
+ EXPECT_TRUE(base::WaitForExitCode(handle2, &exit_code));
+ EXPECT_EQ(exit_code, 0);
+ ASSERT_EQ(IPCChannelPosixTestListener::DENIED, listener.status());
+ ASSERT_TRUE(channel.HasAcceptedConnection());
+ IPC::Message* message = new IPC::Message(0, // routing_id
+ QUIT_MESSAGE, // message type
+ IPC::Message::PRIORITY_NORMAL);
+ channel.Send(message);
+ SpinRunLoop(TestTimeouts::action_timeout_ms());
+ EXPECT_TRUE(base::WaitForExitCode(handle, &exit_code));
+ EXPECT_EQ(exit_code, 0);
+ ASSERT_EQ(IPCChannelPosixTestListener::CHANNEL_ERROR, listener.status());
+ ASSERT_FALSE(channel.HasAcceptedConnection());
+}
+
+TEST_F(IPCChannelPosixTest, DoubleServer) {
+ // Test setting up two servers with the same name.
+ IPCChannelPosixTestListener listener(false);
+ IPCChannelPosixTestListener listener2(false);
+ IPC::ChannelHandle chan_handle(kConnectionSocketTestName);
+ IPC::Channel channel(chan_handle, IPC::Channel::MODE_SERVER, &listener);
+ IPC::Channel channel2(chan_handle, IPC::Channel::MODE_SERVER, &listener2);
+ ASSERT_TRUE(channel.Connect());
+ ASSERT_FALSE(channel2.Connect());
+}
+
+TEST_F(IPCChannelPosixTest, BadMode) {
+ // Test setting up two servers with a bad mode.
+ IPCChannelPosixTestListener listener(false);
+ IPC::ChannelHandle chan_handle(kConnectionSocketTestName);
+ IPC::Channel channel(chan_handle, IPC::Channel::MODE_NONE, &listener);
+ ASSERT_FALSE(channel.Connect());
+}
+
+TEST_F(IPCChannelPosixTest, IsNamedServerInitialized) {
+ IPCChannelPosixTestListener listener(false);
+ IPC::ChannelHandle chan_handle(kConnectionSocketTestName);
+ ASSERT_TRUE(file_util::Delete(FilePath(kConnectionSocketTestName), false));
+ ASSERT_FALSE(IPC::Channel::IsNamedServerInitialized(
+ kConnectionSocketTestName));
+ IPC::Channel channel(chan_handle, IPC::Channel::MODE_NAMED_SERVER, &listener);
+ ASSERT_TRUE(IPC::Channel::IsNamedServerInitialized(
+ kConnectionSocketTestName));
+ channel.Close();
+ ASSERT_FALSE(IPC::Channel::IsNamedServerInitialized(
+ kConnectionSocketTestName));
+}
+
+// A long running process that connects to us
+MULTIPROCESS_TEST_MAIN(IPCChannelPosixTestConnectionProc) {
+ MessageLoopForIO message_loop;
+ IPCChannelPosixTestListener listener(true);
+ IPC::ChannelHandle handle(IPCChannelPosixTest::kConnectionSocketTestName);
+ IPCChannelPosixTest::SetUpSocket(&handle, IPC::Channel::MODE_NAMED_CLIENT);
+ IPC::Channel channel(handle, IPC::Channel::MODE_NAMED_CLIENT, &listener);
+ EXPECT_TRUE(channel.Connect());
+ IPCChannelPosixTest::SpinRunLoop(TestTimeouts::action_max_timeout_ms());
+ EXPECT_EQ(IPCChannelPosixTestListener::MESSAGE_RECEIVED, listener.status());
+ return 0;
+}
+
+// Simple external process that shouldn't be able to connect to us.
+MULTIPROCESS_TEST_MAIN(IPCChannelPosixFailConnectionProc) {
+ MessageLoopForIO message_loop;
+ IPCChannelPosixTestListener listener(false);
+ IPC::ChannelHandle handle(IPCChannelPosixTest::kConnectionSocketTestName);
+ IPCChannelPosixTest::SetUpSocket(&handle, IPC::Channel::MODE_NAMED_CLIENT);
+ IPC::Channel channel(handle, IPC::Channel::MODE_NAMED_CLIENT, &listener);
+
+ // In this case connect may succeed or fail depending on if the packet
+ // actually gets sent at sendmsg. Since we never delay on send, we may not
+ // see the error. However even if connect succeeds, eventually we will get an
+ // error back since the channel will be closed when we attempt to read from
+ // it.
+ bool connected = channel.Connect();
+ if (connected) {
+ IPCChannelPosixTest::SpinRunLoop(TestTimeouts::action_max_timeout_ms());
+ EXPECT_EQ(IPCChannelPosixTestListener::CHANNEL_ERROR, listener.status());
+ } else {
+ EXPECT_EQ(IPCChannelPosixTestListener::DISCONNECTED, listener.status());
+ }
+ return 0;
+}
+
diff --git a/ipc/ipc_channel_proxy.cc b/ipc/ipc_channel_proxy.cc
new file mode 100644
index 000000000000..dc990c26184a
--- /dev/null
+++ b/ipc/ipc_channel_proxy.cc
@@ -0,0 +1,397 @@
+// 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/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "ipc/ipc_channel_proxy.h"
+#include "ipc/ipc_logging.h"
+#include "ipc/ipc_message_utils.h"
+
+namespace IPC {
+
+//------------------------------------------------------------------------------
+
+// This task ensures the message is deleted if the task is deleted without
+// having been run.
+class SendTask : public Task {
+ public:
+ SendTask(ChannelProxy::Context* context, Message* message)
+ : context_(context),
+ message_(message) {
+ }
+
+ virtual void Run() {
+ context_->OnSendMessage(message_.release());
+ }
+
+ private:
+ scoped_refptr<ChannelProxy::Context> context_;
+ scoped_ptr<Message> message_;
+
+ DISALLOW_COPY_AND_ASSIGN(SendTask);
+};
+
+//------------------------------------------------------------------------------
+
+ChannelProxy::MessageFilter::MessageFilter() {}
+
+ChannelProxy::MessageFilter::~MessageFilter() {}
+
+void ChannelProxy::MessageFilter::OnFilterAdded(Channel* channel) {}
+
+void ChannelProxy::MessageFilter::OnFilterRemoved() {}
+
+void ChannelProxy::MessageFilter::OnChannelConnected(int32 peer_pid) {}
+
+void ChannelProxy::MessageFilter::OnChannelError() {}
+
+void ChannelProxy::MessageFilter::OnChannelClosing() {}
+
+bool ChannelProxy::MessageFilter::OnMessageReceived(const Message& message) {
+ return false;
+}
+
+void ChannelProxy::MessageFilter::OnDestruct() const {
+ delete this;
+}
+
+//------------------------------------------------------------------------------
+
+ChannelProxy::Context::Context(Channel::Listener* listener,
+ base::MessageLoopProxy* ipc_message_loop)
+ : listener_message_loop_(base::MessageLoopProxy::current()),
+ listener_(listener),
+ ipc_message_loop_(ipc_message_loop),
+ peer_pid_(0),
+ channel_connected_called_(false) {
+}
+
+ChannelProxy::Context::~Context() {
+}
+
+void ChannelProxy::Context::CreateChannel(const IPC::ChannelHandle& handle,
+ const Channel::Mode& mode) {
+ DCHECK(channel_.get() == NULL);
+ channel_id_ = handle.name;
+ channel_.reset(new Channel(handle, mode, this));
+}
+
+bool ChannelProxy::Context::TryFilters(const Message& message) {
+#ifdef IPC_MESSAGE_LOG_ENABLED
+ Logging* logger = Logging::GetInstance();
+ if (logger->Enabled())
+ logger->OnPreDispatchMessage(message);
+#endif
+
+ for (size_t i = 0; i < filters_.size(); ++i) {
+ if (filters_[i]->OnMessageReceived(message)) {
+#ifdef IPC_MESSAGE_LOG_ENABLED
+ if (logger->Enabled())
+ logger->OnPostDispatchMessage(message, channel_id_);
+#endif
+ return true;
+ }
+ }
+ return false;
+}
+
+// Called on the IPC::Channel thread
+bool ChannelProxy::Context::OnMessageReceived(const Message& message) {
+ // First give a chance to the filters to process this message.
+ if (!TryFilters(message))
+ OnMessageReceivedNoFilter(message);
+ return true;
+}
+
+// Called on the IPC::Channel thread
+bool ChannelProxy::Context::OnMessageReceivedNoFilter(const Message& message) {
+ // NOTE: This code relies on the listener's message loop not going away while
+ // this thread is active. That should be a reasonable assumption, but it
+ // feels risky. We may want to invent some more indirect way of referring to
+ // a MessageLoop if this becomes a problem.
+ listener_message_loop_->PostTask(FROM_HERE, NewRunnableMethod(
+ this, &Context::OnDispatchMessage, message));
+ return true;
+}
+
+// Called on the IPC::Channel thread
+void ChannelProxy::Context::OnChannelConnected(int32 peer_pid) {
+ // Add any pending filters. This avoids a race condition where someone
+ // creates a ChannelProxy, calls AddFilter, and then right after starts the
+ // peer process. The IO thread could receive a message before the task to add
+ // the filter is run on the IO thread.
+ OnAddFilter();
+
+ peer_pid_ = peer_pid;
+ for (size_t i = 0; i < filters_.size(); ++i)
+ filters_[i]->OnChannelConnected(peer_pid);
+
+ // See above comment about using listener_message_loop_ here.
+ listener_message_loop_->PostTask(FROM_HERE, NewRunnableMethod(
+ this, &Context::OnDispatchConnected));
+}
+
+// Called on the IPC::Channel thread
+void ChannelProxy::Context::OnChannelError() {
+ for (size_t i = 0; i < filters_.size(); ++i)
+ filters_[i]->OnChannelError();
+
+ // See above comment about using listener_message_loop_ here.
+ listener_message_loop_->PostTask(FROM_HERE, NewRunnableMethod(
+ this, &Context::OnDispatchError));
+}
+
+// Called on the IPC::Channel thread
+void ChannelProxy::Context::OnChannelOpened() {
+ DCHECK(channel_ != NULL);
+
+ // Assume a reference to ourselves on behalf of this thread. This reference
+ // will be released when we are closed.
+ AddRef();
+
+ if (!channel_->Connect()) {
+ OnChannelError();
+ return;
+ }
+
+ for (size_t i = 0; i < filters_.size(); ++i)
+ filters_[i]->OnFilterAdded(channel_.get());
+}
+
+// Called on the IPC::Channel thread
+void ChannelProxy::Context::OnChannelClosed() {
+ // It's okay for IPC::ChannelProxy::Close to be called more than once, which
+ // would result in this branch being taken.
+ if (!channel_.get())
+ return;
+
+ for (size_t i = 0; i < filters_.size(); ++i) {
+ filters_[i]->OnChannelClosing();
+ filters_[i]->OnFilterRemoved();
+ }
+
+ // We don't need the filters anymore.
+ filters_.clear();
+
+ channel_.reset();
+
+ // Balance with the reference taken during startup. This may result in
+ // self-destruction.
+ Release();
+}
+
+// Called on the IPC::Channel thread
+void ChannelProxy::Context::OnSendMessage(Message* message) {
+ if (!channel_.get()) {
+ delete message;
+ OnChannelClosed();
+ return;
+ }
+ if (!channel_->Send(message))
+ OnChannelError();
+}
+
+// Called on the IPC::Channel thread
+void ChannelProxy::Context::OnAddFilter() {
+ std::vector<scoped_refptr<MessageFilter> > new_filters;
+ {
+ base::AutoLock auto_lock(pending_filters_lock_);
+ new_filters.swap(pending_filters_);
+ }
+
+ for (size_t i = 0; i < new_filters.size(); ++i) {
+ filters_.push_back(new_filters[i]);
+
+ // If the channel has already been created, then we need to send this
+ // message so that the filter gets access to the Channel.
+ if (channel_.get())
+ new_filters[i]->OnFilterAdded(channel_.get());
+ // Ditto for if the channel has been connected.
+ if (peer_pid_)
+ new_filters[i]->OnChannelConnected(peer_pid_);
+ }
+}
+
+// Called on the IPC::Channel thread
+void ChannelProxy::Context::OnRemoveFilter(MessageFilter* filter) {
+ for (size_t i = 0; i < filters_.size(); ++i) {
+ if (filters_[i].get() == filter) {
+ filter->OnFilterRemoved();
+ filters_.erase(filters_.begin() + i);
+ return;
+ }
+ }
+
+ NOTREACHED() << "filter to be removed not found";
+}
+
+// Called on the listener's thread
+void ChannelProxy::Context::AddFilter(MessageFilter* filter) {
+ base::AutoLock auto_lock(pending_filters_lock_);
+ pending_filters_.push_back(make_scoped_refptr(filter));
+ ipc_message_loop_->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &Context::OnAddFilter));
+}
+
+// Called on the listener's thread
+void ChannelProxy::Context::OnDispatchMessage(const Message& message) {
+ if (!listener_)
+ return;
+
+ OnDispatchConnected();
+
+#ifdef IPC_MESSAGE_LOG_ENABLED
+ Logging* logger = Logging::GetInstance();
+ if (message.type() == IPC_LOGGING_ID) {
+ logger->OnReceivedLoggingMessage(message);
+ return;
+ }
+
+ if (logger->Enabled())
+ logger->OnPreDispatchMessage(message);
+#endif
+
+ listener_->OnMessageReceived(message);
+
+#ifdef IPC_MESSAGE_LOG_ENABLED
+ if (logger->Enabled())
+ logger->OnPostDispatchMessage(message, channel_id_);
+#endif
+}
+
+// Called on the listener's thread
+void ChannelProxy::Context::OnDispatchConnected() {
+ if (channel_connected_called_)
+ return;
+
+ channel_connected_called_ = true;
+ if (listener_)
+ listener_->OnChannelConnected(peer_pid_);
+}
+
+// Called on the listener's thread
+void ChannelProxy::Context::OnDispatchError() {
+ if (listener_)
+ listener_->OnChannelError();
+}
+
+//-----------------------------------------------------------------------------
+
+ChannelProxy::ChannelProxy(const IPC::ChannelHandle& channel_handle,
+ Channel::Mode mode,
+ Channel::Listener* listener,
+ base::MessageLoopProxy* ipc_thread)
+ : context_(new Context(listener, ipc_thread)),
+ outgoing_message_filter_(NULL) {
+ Init(channel_handle, mode, ipc_thread, true);
+}
+
+ChannelProxy::ChannelProxy(const IPC::ChannelHandle& channel_handle,
+ Channel::Mode mode,
+ base::MessageLoopProxy* ipc_thread,
+ Context* context,
+ bool create_pipe_now)
+ : context_(context),
+ outgoing_message_filter_(NULL) {
+ Init(channel_handle, mode, ipc_thread, create_pipe_now);
+}
+
+ChannelProxy::~ChannelProxy() {
+ Close();
+}
+
+void ChannelProxy::Init(const IPC::ChannelHandle& channel_handle,
+ Channel::Mode mode,
+ base::MessageLoopProxy* ipc_thread_loop,
+ bool create_pipe_now) {
+#if defined(OS_POSIX)
+ // When we are creating a server on POSIX, we need its file descriptor
+ // to be created immediately so that it can be accessed and passed
+ // to other processes. Forcing it to be created immediately avoids
+ // race conditions that may otherwise arise.
+ if (mode & Channel::MODE_SERVER_FLAG) {
+ create_pipe_now = true;
+ }
+#endif // defined(OS_POSIX)
+
+ if (create_pipe_now) {
+ // Create the channel immediately. This effectively sets up the
+ // low-level pipe so that the client can connect. Without creating
+ // the pipe immediately, it is possible for a listener to attempt
+ // to connect and get an error since the pipe doesn't exist yet.
+ context_->CreateChannel(channel_handle, mode);
+ } else {
+ context_->ipc_message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
+ context_.get(), &Context::CreateChannel, channel_handle, mode));
+ }
+
+ // complete initialization on the background thread
+ context_->ipc_message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
+ context_.get(), &Context::OnChannelOpened));
+}
+
+void ChannelProxy::Close() {
+ // Clear the backpointer to the listener so that any pending calls to
+ // Context::OnDispatchMessage or OnDispatchError will be ignored. It is
+ // possible that the channel could be closed while it is receiving messages!
+ context_->Clear();
+
+ if (context_->ipc_message_loop()) {
+ context_->ipc_message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
+ context_.get(), &Context::OnChannelClosed));
+ }
+}
+
+bool ChannelProxy::Send(Message* message) {
+ if (outgoing_message_filter())
+ message = outgoing_message_filter()->Rewrite(message);
+
+#ifdef IPC_MESSAGE_LOG_ENABLED
+ Logging::GetInstance()->OnSendMessage(message, context_->channel_id());
+#endif
+
+ context_->ipc_message_loop()->PostTask(FROM_HERE,
+ new SendTask(context_.get(), message));
+ return true;
+}
+
+void ChannelProxy::AddFilter(MessageFilter* filter) {
+ context_->AddFilter(filter);
+}
+
+void ChannelProxy::RemoveFilter(MessageFilter* filter) {
+ context_->ipc_message_loop()->PostTask(
+ FROM_HERE, NewRunnableMethod(
+ context_.get(),
+ &Context::OnRemoveFilter,
+ make_scoped_refptr(filter)));
+}
+
+void ChannelProxy::ClearIPCMessageLoop() {
+ context()->ClearIPCMessageLoop();
+}
+
+#if defined(OS_POSIX) && !defined(OS_NACL)
+// See the TODO regarding lazy initialization of the channel in
+// ChannelProxy::Init().
+// We assume that IPC::Channel::GetClientFileDescriptorMapping() is thread-safe.
+int ChannelProxy::GetClientFileDescriptor() const {
+ Channel *channel = context_.get()->channel_.get();
+ // Channel must have been created first.
+ DCHECK(channel) << context_.get()->channel_id_;
+ return channel->GetClientFileDescriptor();
+}
+
+bool ChannelProxy::GetClientEuid(uid_t* client_euid) const {
+ Channel *channel = context_.get()->channel_.get();
+ // Channel must have been created first.
+ DCHECK(channel) << context_.get()->channel_id_;
+ return channel->GetClientEuid(client_euid);
+}
+#endif
+
+//-----------------------------------------------------------------------------
+
+} // namespace IPC
diff --git a/ipc/ipc_channel_proxy.h b/ipc/ipc_channel_proxy.h
new file mode 100644
index 000000000000..792e3d6a506e
--- /dev/null
+++ b/ipc/ipc_channel_proxy.h
@@ -0,0 +1,272 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IPC_IPC_CHANNEL_PROXY_H_
+#define IPC_IPC_CHANNEL_PROXY_H_
+#pragma once
+
+#include <vector>
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop_proxy.h"
+#include "base/synchronization/lock.h"
+#include "ipc/ipc_channel.h"
+#include "ipc/ipc_channel_handle.h"
+
+namespace IPC {
+
+class SendTask;
+
+//-----------------------------------------------------------------------------
+// IPC::ChannelProxy
+//
+// This class is a helper class that is useful when you wish to run an IPC
+// channel on a background thread. It provides you with the option of either
+// handling IPC messages on that background thread or having them dispatched to
+// your main thread (the thread on which the IPC::ChannelProxy is created).
+//
+// The API for an IPC::ChannelProxy is very similar to that of an IPC::Channel.
+// When you send a message to an IPC::ChannelProxy, the message is routed to
+// the background thread, where it is then passed to the IPC::Channel's Send
+// method. This means that you can send a message from your thread and your
+// message will be sent over the IPC channel when possible instead of being
+// delayed until your thread returns to its message loop. (Often IPC messages
+// will queue up on the IPC::Channel when there is a lot of traffic, and the
+// channel will not get cycles to flush its message queue until the thread, on
+// which it is running, returns to its message loop.)
+//
+// An IPC::ChannelProxy can have a MessageFilter associated with it, which will
+// be notified of incoming messages on the IPC::Channel's thread. This gives
+// the consumer of IPC::ChannelProxy the ability to respond to incoming
+// messages on this background thread instead of on their own thread, which may
+// be bogged down with other processing. The result can be greatly improved
+// latency for messages that can be handled on a background thread.
+//
+// The consumer of IPC::ChannelProxy is responsible for allocating the Thread
+// instance where the IPC::Channel will be created and operated.
+//
+class IPC_EXPORT ChannelProxy : public Message::Sender {
+ public:
+
+ struct MessageFilterTraits;
+
+ // A class that receives messages on the thread where the IPC channel is
+ // running. It can choose to prevent the default action for an IPC message.
+ class IPC_EXPORT MessageFilter
+ : public base::RefCountedThreadSafe<MessageFilter, MessageFilterTraits> {
+ public:
+ MessageFilter();
+ virtual ~MessageFilter();
+
+ // Called on the background thread to provide the filter with access to the
+ // channel. Called when the IPC channel is initialized or when AddFilter
+ // is called if the channel is already initialized.
+ virtual void OnFilterAdded(Channel* channel);
+
+ // Called on the background thread when the filter has been removed from
+ // the ChannelProxy and when the Channel is closing. After a filter is
+ // removed, it will not be called again.
+ virtual void OnFilterRemoved();
+
+ // Called to inform the filter that the IPC channel is connected and we
+ // have received the internal Hello message from the peer.
+ virtual void OnChannelConnected(int32 peer_pid);
+
+ // Called when there is an error on the channel, typically that the channel
+ // has been closed.
+ virtual void OnChannelError();
+
+ // Called to inform the filter that the IPC channel will be destroyed.
+ // OnFilterRemoved is called immediately after this.
+ virtual void OnChannelClosing();
+
+ // Return true to indicate that the message was handled, or false to let
+ // the message be handled in the default way.
+ virtual bool OnMessageReceived(const Message& message);
+
+ // Called when the message filter is about to be deleted. This gives
+ // derived classes the option of controlling which thread they're deleted
+ // on etc.
+ virtual void OnDestruct() const;
+ };
+
+ struct MessageFilterTraits {
+ static void Destruct(const MessageFilter* filter) {
+ filter->OnDestruct();
+ }
+ };
+
+ // Interface for a filter to be imposed on outgoing messages which can
+ // re-write the message. Used mainly for testing.
+ class OutgoingMessageFilter {
+ public:
+ // Returns a re-written message, freeing the original, or simply the
+ // original unchanged if no rewrite indicated.
+ virtual Message *Rewrite(Message *message) = 0;
+ };
+
+ // Initializes a channel proxy. The channel_handle and mode parameters are
+ // passed directly to the underlying IPC::Channel. The listener is called on
+ // the thread that creates the ChannelProxy. The filter's OnMessageReceived
+ // method is called on the thread where the IPC::Channel is running. The
+ // filter may be null if the consumer is not interested in handling messages
+ // on the background thread. Any message not handled by the filter will be
+ // dispatched to the listener. The given message loop indicates where the
+ // IPC::Channel should be created.
+ ChannelProxy(const IPC::ChannelHandle& channel_handle,
+ Channel::Mode mode,
+ Channel::Listener* listener,
+ base::MessageLoopProxy* ipc_thread_loop);
+
+ virtual ~ChannelProxy();
+
+ // Close the IPC::Channel. This operation completes asynchronously, once the
+ // background thread processes the command to close the channel. It is ok to
+ // call this method multiple times. Redundant calls are ignored.
+ //
+ // WARNING: The MessageFilter object held by the ChannelProxy is also
+ // released asynchronously, and it may in fact have its final reference
+ // released on the background thread. The caller should be careful to deal
+ // with / allow for this possibility.
+ void Close();
+
+ // Send a message asynchronously. The message is routed to the background
+ // thread where it is passed to the IPC::Channel's Send method.
+ virtual bool Send(Message* message);
+
+ // Used to intercept messages as they are received on the background thread.
+ //
+ // Ordinarily, messages sent to the ChannelProxy are routed to the matching
+ // listener on the worker thread. This API allows code to intercept messages
+ // before they are sent to the worker thread.
+ // If you call this before the target process is launched, then you're
+ // guaranteed to not miss any messages. But if you call this anytime after,
+ // then some messages might be missed since the filter is added internally on
+ // the IO thread.
+ void AddFilter(MessageFilter* filter);
+ void RemoveFilter(MessageFilter* filter);
+
+ void set_outgoing_message_filter(OutgoingMessageFilter* filter) {
+ outgoing_message_filter_ = filter;
+ }
+
+ // Called to clear the pointer to the IPC message loop when it's going away.
+ void ClearIPCMessageLoop();
+
+#if defined(OS_POSIX)
+ // Calls through to the underlying channel's methods.
+ int GetClientFileDescriptor() const;
+ bool GetClientEuid(uid_t* client_euid) const;
+#endif // defined(OS_POSIX)
+
+ protected:
+ class Context;
+ // A subclass uses this constructor if it needs to add more information
+ // to the internal state. If create_pipe_now is true, the pipe is created
+ // immediately. Otherwise it's created on the IO thread.
+ ChannelProxy(const IPC::ChannelHandle& channel_handle,
+ Channel::Mode mode,
+ base::MessageLoopProxy* ipc_thread_loop,
+ Context* context,
+ bool create_pipe_now);
+
+ // Used internally to hold state that is referenced on the IPC thread.
+ class Context : public base::RefCountedThreadSafe<Context>,
+ public Channel::Listener {
+ public:
+ Context(Channel::Listener* listener, base::MessageLoopProxy* ipc_thread);
+ void ClearIPCMessageLoop() { ipc_message_loop_ = NULL; }
+ base::MessageLoopProxy* ipc_message_loop() const {
+ return ipc_message_loop_.get();
+ }
+ const std::string& channel_id() const { return channel_id_; }
+
+ // Dispatches a message on the listener thread.
+ void OnDispatchMessage(const Message& message);
+
+ protected:
+ friend class base::RefCountedThreadSafe<Context>;
+ virtual ~Context();
+
+ // IPC::Channel::Listener methods:
+ virtual bool OnMessageReceived(const Message& message) OVERRIDE;
+ virtual void OnChannelConnected(int32 peer_pid) OVERRIDE;
+ virtual void OnChannelError() OVERRIDE;
+
+ // Like OnMessageReceived but doesn't try the filters.
+ bool OnMessageReceivedNoFilter(const Message& message);
+
+ // Gives the filters a chance at processing |message|.
+ // Returns true if the message was processed, false otherwise.
+ bool TryFilters(const Message& message);
+
+ // Like Open and Close, but called on the IPC thread.
+ virtual void OnChannelOpened();
+ virtual void OnChannelClosed();
+
+ // Called on the consumers thread when the ChannelProxy is closed. At that
+ // point the consumer is telling us that they don't want to receive any
+ // more messages, so we honor that wish by forgetting them!
+ virtual void Clear() { listener_ = NULL; }
+
+ private:
+ friend class ChannelProxy;
+ friend class SendTask;
+
+ // Create the Channel
+ void CreateChannel(const IPC::ChannelHandle& channel_handle,
+ const Channel::Mode& mode);
+
+ // Methods called on the IO thread.
+ void OnSendMessage(Message* message_ptr);
+ void OnAddFilter();
+ void OnRemoveFilter(MessageFilter* filter);
+
+ // Methods called on the listener thread.
+ void AddFilter(MessageFilter* filter);
+ void OnDispatchConnected();
+ void OnDispatchError();
+
+ scoped_refptr<base::MessageLoopProxy> listener_message_loop_;
+ Channel::Listener* listener_;
+
+ // List of filters. This is only accessed on the IPC thread.
+ std::vector<scoped_refptr<MessageFilter> > filters_;
+ scoped_refptr<base::MessageLoopProxy> ipc_message_loop_;
+ scoped_ptr<Channel> channel_;
+ std::string channel_id_;
+ int peer_pid_;
+ bool channel_connected_called_;
+
+ // Holds filters between the AddFilter call on the listerner thread and the
+ // IPC thread when they're added to filters_.
+ std::vector<scoped_refptr<MessageFilter> > pending_filters_;
+ // Lock for pending_filters_.
+ base::Lock pending_filters_lock_;
+ };
+
+ Context* context() { return context_; }
+
+ OutgoingMessageFilter* outgoing_message_filter() {
+ return outgoing_message_filter_;
+ }
+
+ private:
+ friend class SendTask;
+
+ void Init(const IPC::ChannelHandle& channel_handle, Channel::Mode mode,
+ base::MessageLoopProxy* ipc_thread_loop, bool create_pipe_now);
+
+ // By maintaining this indirection (ref-counted) to our internal state, we
+ // can safely be destroyed while the background thread continues to do stuff
+ // that involves this data.
+ scoped_refptr<Context> context_;
+
+ OutgoingMessageFilter* outgoing_message_filter_;
+};
+
+} // namespace IPC
+
+#endif // IPC_IPC_CHANNEL_PROXY_H_
diff --git a/ipc/ipc_channel_win.cc b/ipc/ipc_channel_win.cc
new file mode 100644
index 000000000000..3a85a1651fb4
--- /dev/null
+++ b/ipc/ipc_channel_win.cc
@@ -0,0 +1,430 @@
+// 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 "ipc/ipc_channel_win.h"
+
+#include <windows.h>
+
+#include "base/auto_reset.h"
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/threading/non_thread_safe.h"
+#include "base/utf_string_conversions.h"
+#include "base/win/scoped_handle.h"
+#include "ipc/ipc_logging.h"
+#include "ipc/ipc_message_utils.h"
+
+namespace IPC {
+
+Channel::ChannelImpl::State::State(ChannelImpl* channel) : is_pending(false) {
+ memset(&context.overlapped, 0, sizeof(context.overlapped));
+ context.handler = channel;
+}
+
+Channel::ChannelImpl::State::~State() {
+ COMPILE_ASSERT(!offsetof(Channel::ChannelImpl::State, context),
+ starts_with_io_context);
+}
+
+Channel::ChannelImpl::ChannelImpl(const IPC::ChannelHandle &channel_handle,
+ Mode mode, Listener* listener)
+ : ALLOW_THIS_IN_INITIALIZER_LIST(input_state_(this)),
+ ALLOW_THIS_IN_INITIALIZER_LIST(output_state_(this)),
+ pipe_(INVALID_HANDLE_VALUE),
+ listener_(listener),
+ waiting_connect_(mode & MODE_SERVER_FLAG),
+ processing_incoming_(false),
+ ALLOW_THIS_IN_INITIALIZER_LIST(factory_(this)) {
+ CreatePipe(channel_handle, mode);
+}
+
+Channel::ChannelImpl::~ChannelImpl() {
+ Close();
+}
+
+void Channel::ChannelImpl::Close() {
+ if (thread_check_.get()) {
+ DCHECK(thread_check_->CalledOnValidThread());
+ }
+
+ if (input_state_.is_pending || output_state_.is_pending)
+ CancelIo(pipe_);
+
+ // Closing the handle at this point prevents us from issuing more requests
+ // form OnIOCompleted().
+ if (pipe_ != INVALID_HANDLE_VALUE) {
+ CloseHandle(pipe_);
+ pipe_ = INVALID_HANDLE_VALUE;
+ }
+
+ // Make sure all IO has completed.
+ base::Time start = base::Time::Now();
+ while (input_state_.is_pending || output_state_.is_pending) {
+ MessageLoopForIO::current()->WaitForIOCompletion(INFINITE, this);
+ }
+
+ while (!output_queue_.empty()) {
+ Message* m = output_queue_.front();
+ output_queue_.pop();
+ delete m;
+ }
+}
+
+bool Channel::ChannelImpl::Send(Message* message) {
+ DCHECK(thread_check_->CalledOnValidThread());
+ DVLOG(2) << "sending message @" << message << " on channel @" << this
+ << " with type " << message->type()
+ << " (" << output_queue_.size() << " in queue)";
+
+#ifdef IPC_MESSAGE_LOG_ENABLED
+ Logging::GetInstance()->OnSendMessage(message, "");
+#endif
+
+ output_queue_.push(message);
+ // ensure waiting to write
+ if (!waiting_connect_) {
+ if (!output_state_.is_pending) {
+ if (!ProcessOutgoingMessages(NULL, 0))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// static
+bool Channel::ChannelImpl::IsNamedServerInitialized(
+ const std::string& channel_id) {
+ if (WaitNamedPipe(PipeName(channel_id).c_str(), 1))
+ return true;
+ // If ERROR_SEM_TIMEOUT occurred, the pipe exists but is handling another
+ // connection.
+ return GetLastError() == ERROR_SEM_TIMEOUT;
+}
+
+// static
+const std::wstring Channel::ChannelImpl::PipeName(
+ const std::string& channel_id) {
+ std::string name("\\\\.\\pipe\\chrome.");
+ return ASCIIToWide(name.append(channel_id));
+}
+
+bool Channel::ChannelImpl::CreatePipe(const IPC::ChannelHandle &channel_handle,
+ Mode mode) {
+ DCHECK_EQ(INVALID_HANDLE_VALUE, pipe_);
+ const std::wstring pipe_name = PipeName(channel_handle.name);
+ if (mode & MODE_SERVER_FLAG) {
+ pipe_ = CreateNamedPipeW(pipe_name.c_str(),
+ PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
+ FILE_FLAG_FIRST_PIPE_INSTANCE,
+ PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
+ 1,
+ Channel::kReadBufferSize,
+ Channel::kReadBufferSize,
+ 5000,
+ NULL);
+ } else if (mode & MODE_CLIENT_FLAG) {
+ pipe_ = CreateFileW(pipe_name.c_str(),
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION |
+ FILE_FLAG_OVERLAPPED,
+ NULL);
+ } else {
+ NOTREACHED();
+ }
+ if (pipe_ == INVALID_HANDLE_VALUE) {
+ // If this process is being closed, the pipe may be gone already.
+ LOG(WARNING) << "Unable to create pipe \"" << pipe_name <<
+ "\" in " << (mode == 0 ? "server" : "client")
+ << " mode. Error :" << GetLastError();
+ return false;
+ }
+
+ // Create the Hello message to be sent when Connect is called
+ scoped_ptr<Message> m(new Message(MSG_ROUTING_NONE,
+ HELLO_MESSAGE_TYPE,
+ IPC::Message::PRIORITY_NORMAL));
+ if (!m->WriteInt(GetCurrentProcessId())) {
+ CloseHandle(pipe_);
+ pipe_ = INVALID_HANDLE_VALUE;
+ return false;
+ }
+
+ output_queue_.push(m.release());
+ return true;
+}
+
+bool Channel::ChannelImpl::Connect() {
+ DLOG_IF(WARNING, thread_check_.get()) << "Connect called more than once";
+
+ if (!thread_check_.get())
+ thread_check_.reset(new base::NonThreadSafe());
+
+ if (pipe_ == INVALID_HANDLE_VALUE)
+ return false;
+
+ MessageLoopForIO::current()->RegisterIOHandler(pipe_, this);
+
+ // Check to see if there is a client connected to our pipe...
+ if (waiting_connect_)
+ ProcessConnection();
+
+ if (!input_state_.is_pending) {
+ // Complete setup asynchronously. By not setting input_state_.is_pending
+ // to true, we indicate to OnIOCompleted that this is the special
+ // initialization signal.
+ MessageLoopForIO::current()->PostTask(FROM_HERE, factory_.NewRunnableMethod(
+ &Channel::ChannelImpl::OnIOCompleted, &input_state_.context, 0, 0));
+ }
+
+ if (!waiting_connect_)
+ ProcessOutgoingMessages(NULL, 0);
+ return true;
+}
+
+bool Channel::ChannelImpl::ProcessConnection() {
+ DCHECK(thread_check_->CalledOnValidThread());
+ if (input_state_.is_pending)
+ input_state_.is_pending = false;
+
+ // Do we have a client connected to our pipe?
+ if (INVALID_HANDLE_VALUE == pipe_)
+ return false;
+
+ BOOL ok = ConnectNamedPipe(pipe_, &input_state_.context.overlapped);
+
+ DWORD err = GetLastError();
+ if (ok) {
+ // Uhm, the API documentation says that this function should never
+ // return success when used in overlapped mode.
+ NOTREACHED();
+ return false;
+ }
+
+ switch (err) {
+ case ERROR_IO_PENDING:
+ input_state_.is_pending = true;
+ break;
+ case ERROR_PIPE_CONNECTED:
+ waiting_connect_ = false;
+ break;
+ case ERROR_NO_DATA:
+ // The pipe is being closed.
+ return false;
+ default:
+ NOTREACHED();
+ return false;
+ }
+
+ return true;
+}
+
+bool Channel::ChannelImpl::ProcessIncomingMessages(
+ MessageLoopForIO::IOContext* context,
+ DWORD bytes_read) {
+ DCHECK(thread_check_->CalledOnValidThread());
+ if (input_state_.is_pending) {
+ input_state_.is_pending = false;
+ DCHECK(context);
+
+ if (!context || !bytes_read)
+ return false;
+ } else {
+ // This happens at channel initialization.
+ DCHECK(!bytes_read && context == &input_state_.context);
+ }
+
+ for (;;) {
+ if (bytes_read == 0) {
+ if (INVALID_HANDLE_VALUE == pipe_)
+ return false;
+
+ // Read from pipe...
+ BOOL ok = ReadFile(pipe_,
+ input_buf_,
+ Channel::kReadBufferSize,
+ &bytes_read,
+ &input_state_.context.overlapped);
+ if (!ok) {
+ DWORD err = GetLastError();
+ if (err == ERROR_IO_PENDING) {
+ input_state_.is_pending = true;
+ return true;
+ }
+ LOG(ERROR) << "pipe error: " << err;
+ return false;
+ }
+ input_state_.is_pending = true;
+ return true;
+ }
+ DCHECK(bytes_read);
+
+ // Process messages from input buffer.
+
+ const char* p, *end;
+ if (input_overflow_buf_.empty()) {
+ p = input_buf_;
+ end = p + bytes_read;
+ } else {
+ if (input_overflow_buf_.size() > (kMaximumMessageSize - bytes_read)) {
+ input_overflow_buf_.clear();
+ LOG(ERROR) << "IPC message is too big";
+ return false;
+ }
+ input_overflow_buf_.append(input_buf_, bytes_read);
+ p = input_overflow_buf_.data();
+ end = p + input_overflow_buf_.size();
+ }
+
+ while (p < end) {
+ const char* message_tail = Message::FindNext(p, end);
+ if (message_tail) {
+ int len = static_cast<int>(message_tail - p);
+ const Message m(p, len);
+ DVLOG(2) << "received message on channel @" << this
+ << " with type " << m.type();
+ if (m.routing_id() == MSG_ROUTING_NONE &&
+ m.type() == HELLO_MESSAGE_TYPE) {
+ // The Hello message contains only the process id.
+ listener_->OnChannelConnected(MessageIterator(m).NextInt());
+ } else {
+ listener_->OnMessageReceived(m);
+ }
+ p = message_tail;
+ } else {
+ // Last message is partial.
+ break;
+ }
+ }
+ input_overflow_buf_.assign(p, end - p);
+
+ bytes_read = 0; // Get more data.
+ }
+
+ return true;
+}
+
+bool Channel::ChannelImpl::ProcessOutgoingMessages(
+ MessageLoopForIO::IOContext* context,
+ DWORD bytes_written) {
+ DCHECK(!waiting_connect_); // Why are we trying to send messages if there's
+ // no connection?
+ DCHECK(thread_check_->CalledOnValidThread());
+
+ if (output_state_.is_pending) {
+ DCHECK(context);
+ output_state_.is_pending = false;
+ if (!context || bytes_written == 0) {
+ DWORD err = GetLastError();
+ LOG(ERROR) << "pipe error: " << err;
+ return false;
+ }
+ // Message was sent.
+ DCHECK(!output_queue_.empty());
+ Message* m = output_queue_.front();
+ output_queue_.pop();
+ delete m;
+ }
+
+ if (output_queue_.empty())
+ return true;
+
+ if (INVALID_HANDLE_VALUE == pipe_)
+ return false;
+
+ // Write to pipe...
+ Message* m = output_queue_.front();
+ DCHECK(m->size() <= INT_MAX);
+ BOOL ok = WriteFile(pipe_,
+ m->data(),
+ static_cast<int>(m->size()),
+ &bytes_written,
+ &output_state_.context.overlapped);
+ if (!ok) {
+ DWORD err = GetLastError();
+ if (err == ERROR_IO_PENDING) {
+ output_state_.is_pending = true;
+
+ DVLOG(2) << "sent pending message @" << m << " on channel @" << this
+ << " with type " << m->type();
+
+ return true;
+ }
+ LOG(ERROR) << "pipe error: " << err;
+ return false;
+ }
+
+ DVLOG(2) << "sent message @" << m << " on channel @" << this
+ << " with type " << m->type();
+
+ output_state_.is_pending = true;
+ return true;
+}
+
+void Channel::ChannelImpl::OnIOCompleted(MessageLoopForIO::IOContext* context,
+ DWORD bytes_transfered, DWORD error) {
+ bool ok;
+ DCHECK(thread_check_->CalledOnValidThread());
+ if (context == &input_state_.context) {
+ if (waiting_connect_) {
+ if (!ProcessConnection())
+ return;
+ // We may have some messages queued up to send...
+ if (!output_queue_.empty() && !output_state_.is_pending)
+ ProcessOutgoingMessages(NULL, 0);
+ if (input_state_.is_pending)
+ return;
+ // else, fall-through and look for incoming messages...
+ }
+ // we don't support recursion through OnMessageReceived yet!
+ DCHECK(!processing_incoming_);
+ AutoReset<bool> auto_reset_processing_incoming(&processing_incoming_, true);
+ ok = ProcessIncomingMessages(context, bytes_transfered);
+ } else {
+ DCHECK(context == &output_state_.context);
+ ok = ProcessOutgoingMessages(context, bytes_transfered);
+ }
+ if (!ok && INVALID_HANDLE_VALUE != pipe_) {
+ // We don't want to re-enter Close().
+ Close();
+ listener_->OnChannelError();
+ }
+}
+
+//------------------------------------------------------------------------------
+// Channel's methods simply call through to ChannelImpl.
+Channel::Channel(const IPC::ChannelHandle &channel_handle, Mode mode,
+ Listener* listener)
+ : channel_impl_(new ChannelImpl(channel_handle, mode, listener)) {
+}
+
+Channel::~Channel() {
+ delete channel_impl_;
+}
+
+bool Channel::Connect() {
+ return channel_impl_->Connect();
+}
+
+void Channel::Close() {
+ channel_impl_->Close();
+}
+
+void Channel::set_listener(Listener* listener) {
+ channel_impl_->set_listener(listener);
+}
+
+bool Channel::Send(Message* message) {
+ return channel_impl_->Send(message);
+}
+
+// static
+bool Channel::IsNamedServerInitialized(const std::string& channel_id) {
+ return ChannelImpl::IsNamedServerInitialized(channel_id);
+}
+
+} // namespace IPC
diff --git a/ipc/ipc_channel_win.h b/ipc/ipc_channel_win.h
new file mode 100644
index 000000000000..ada88ac3c0e4
--- /dev/null
+++ b/ipc/ipc_channel_win.h
@@ -0,0 +1,91 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IPC_IPC_CHANNEL_WIN_H_
+#define IPC_IPC_CHANNEL_WIN_H_
+#pragma once
+
+#include "ipc/ipc_channel.h"
+
+#include <queue>
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop.h"
+
+namespace base {
+class NonThreadSafe;
+}
+
+namespace IPC {
+
+class Channel::ChannelImpl : public MessageLoopForIO::IOHandler {
+ public:
+ // Mirror methods of Channel, see ipc_channel.h for description.
+ ChannelImpl(const IPC::ChannelHandle &channel_handle, Mode mode,
+ Listener* listener);
+ ~ChannelImpl();
+ bool Connect();
+ void Close();
+ void set_listener(Listener* listener) { listener_ = listener; }
+ bool Send(Message* message);
+ static bool IsNamedServerInitialized(const std::string& channel_id);
+ private:
+ static const std::wstring PipeName(const std::string& channel_id);
+ bool CreatePipe(const IPC::ChannelHandle &channel_handle, Mode mode);
+
+ bool ProcessConnection();
+ bool ProcessIncomingMessages(MessageLoopForIO::IOContext* context,
+ DWORD bytes_read);
+ bool ProcessOutgoingMessages(MessageLoopForIO::IOContext* context,
+ DWORD bytes_written);
+
+ // MessageLoop::IOHandler implementation.
+ virtual void OnIOCompleted(MessageLoopForIO::IOContext* context,
+ DWORD bytes_transfered, DWORD error);
+ private:
+ struct State {
+ explicit State(ChannelImpl* channel);
+ ~State();
+ MessageLoopForIO::IOContext context;
+ bool is_pending;
+ };
+
+ State input_state_;
+ State output_state_;
+
+ HANDLE pipe_;
+
+ Listener* listener_;
+
+ // Messages to be sent are queued here.
+ std::queue<Message*> output_queue_;
+
+ // We read from the pipe into this buffer
+ char input_buf_[Channel::kReadBufferSize];
+
+ // Large messages that span multiple pipe buffers, get built-up using
+ // this buffer.
+ std::string input_overflow_buf_;
+
+ // In server-mode, we have to wait for the client to connect before we
+ // can begin reading. We make use of the input_state_ when performing
+ // the connect operation in overlapped mode.
+ bool waiting_connect_;
+
+ // This flag is set when processing incoming messages. It is used to
+ // avoid recursing through ProcessIncomingMessages, which could cause
+ // problems. TODO(darin): make this unnecessary
+ bool processing_incoming_;
+
+ ScopedRunnableMethodFactory<ChannelImpl> factory_;
+
+ scoped_ptr<base::NonThreadSafe> thread_check_;
+
+ DISALLOW_COPY_AND_ASSIGN(ChannelImpl);
+};
+
+} // namespace IPC
+
+#endif // IPC_IPC_CHANNEL_WIN_H_
diff --git a/ipc/ipc_descriptors.h b/ipc/ipc_descriptors.h
new file mode 100644
index 000000000000..4750fa8e7633
--- /dev/null
+++ b/ipc/ipc_descriptors.h
@@ -0,0 +1,15 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IPC_IPC_DESCRIPTORS_H_
+#define IPC_IPC_DESCRIPTORS_H_
+#pragma once
+
+// This is a list of global descriptor keys to be used with the
+// base::GlobalDescriptors object (see base/global_descriptors_posix.h)
+enum {
+ kPrimaryIPCChannel = 0,
+};
+
+#endif // IPC_IPC_DESCRIPTORS_H_
diff --git a/ipc/ipc_export.h b/ipc/ipc_export.h
new file mode 100644
index 000000000000..dc38fffa204b
--- /dev/null
+++ b/ipc/ipc_export.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IPC_IPC_OSP_EXPORT_
+#define IPC_IPC_OSP_EXPORT_
+#pragma once
+
+// Defines IPC_EXPORT so that functionality implemented by the IPC module can be
+// exported to consumers.
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(IPC_IMPLEMENTATION)
+#define IPC_EXPORT __declspec(dllexport)
+#else
+#define IPC_EXPORT __declspec(dllimport)
+#endif // defined(IPC_IMPLEMENTATION)
+
+#else // defined(WIN32)
+#define IPC_EXPORT __attribute__((visibility("default")))
+#endif
+
+#else // defined(COMPONENT_BUILD)
+#define IPC_EXPORT
+#endif
+
+#endif // IPC_IPC_OSP_EXPORT_
diff --git a/ipc/ipc_logging.cc b/ipc/ipc_logging.cc
new file mode 100644
index 000000000000..138e6acce735
--- /dev/null
+++ b/ipc/ipc_logging.cc
@@ -0,0 +1,251 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ipc/ipc_logging.h"
+
+#ifdef IPC_MESSAGE_LOG_ENABLED
+#define IPC_MESSAGE_MACROS_LOG_ENABLED
+#endif
+
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "base/process_util.h"
+#include "base/string_number_conversions.h"
+#include "base/string_util.h"
+#include "base/threading/thread.h"
+#include "base/time.h"
+#include "ipc/ipc_switches.h"
+#include "ipc/ipc_sync_message.h"
+#include "ipc/ipc_message_utils.h"
+
+#if defined(OS_POSIX)
+#include <unistd.h>
+#endif
+
+#ifdef IPC_MESSAGE_LOG_ENABLED
+
+using base::Time;
+
+// IPC::Logging is allocated as a singleton, so we don't need any kind of
+// special retention program.
+DISABLE_RUNNABLE_METHOD_REFCOUNT(IPC::Logging);
+
+namespace IPC {
+
+const int kLogSendDelayMs = 100;
+
+// We use a pointer to the function table to avoid any linker dependencies on
+// all the traits used as IPC message parameters.
+LogFunctionMap* Logging::log_function_map_;
+
+Logging::Logging()
+ : enabled_(false),
+ enabled_on_stderr_(false),
+ queue_invoke_later_pending_(false),
+ sender_(NULL),
+ main_thread_(MessageLoop::current()),
+ consumer_(NULL) {
+#if defined(OS_WIN)
+ // getenv triggers an unsafe warning. Simply check how big of a buffer
+ // would be needed to fetch the value to see if the enviornment variable is
+ // set.
+ size_t requiredSize = 0;
+ getenv_s(&requiredSize, NULL, 0, "CHROME_IPC_LOGGING");
+ bool logging_env_var_set = (requiredSize != 0);
+#else // !defined(OS_WIN)
+ bool logging_env_var_set = (getenv("CHROME_IPC_LOGGING") != NULL);
+#endif //defined(OS_WIN)
+ if (logging_env_var_set) {
+ enabled_ = true;
+ enabled_on_stderr_ = true;
+ }
+}
+
+Logging::~Logging() {
+}
+
+Logging* Logging::GetInstance() {
+ return Singleton<Logging>::get();
+}
+
+void Logging::SetConsumer(Consumer* consumer) {
+ consumer_ = consumer;
+}
+
+void Logging::Enable() {
+ enabled_ = true;
+}
+
+void Logging::Disable() {
+ enabled_ = false;
+}
+
+void Logging::OnSendLogs() {
+ queue_invoke_later_pending_ = false;
+ if (!sender_)
+ return;
+
+ Message* msg = new Message(
+ MSG_ROUTING_CONTROL, IPC_LOGGING_ID, Message::PRIORITY_NORMAL);
+ WriteParam(msg, queued_logs_);
+ queued_logs_.clear();
+ sender_->Send(msg);
+}
+
+void Logging::SetIPCSender(IPC::Message::Sender* sender) {
+ sender_ = sender;
+}
+
+void Logging::OnReceivedLoggingMessage(const Message& message) {
+ std::vector<LogData> data;
+ void* iter = NULL;
+ if (!ReadParam(&message, &iter, &data))
+ return;
+
+ for (size_t i = 0; i < data.size(); ++i) {
+ Log(data[i]);
+ }
+}
+
+void Logging::OnSendMessage(Message* message, const std::string& channel_id) {
+ if (!Enabled())
+ return;
+
+ if (message->is_reply()) {
+ LogData* data = message->sync_log_data();
+ if (!data)
+ return;
+
+ // This is actually the delayed reply to a sync message. Create a string
+ // of the output parameters, add it to the LogData that was earlier stashed
+ // with the reply, and log the result.
+ data->channel = channel_id;
+ GenerateLogData("", *message, data);
+ Log(*data);
+ delete data;
+ message->set_sync_log_data(NULL);
+ } else {
+ // If the time has already been set (i.e. by ChannelProxy), keep that time
+ // instead as it's more accurate.
+ if (!message->sent_time())
+ message->set_sent_time(Time::Now().ToInternalValue());
+ }
+}
+
+void Logging::OnPreDispatchMessage(const Message& message) {
+ message.set_received_time(Time::Now().ToInternalValue());
+}
+
+void Logging::OnPostDispatchMessage(const Message& message,
+ const std::string& channel_id) {
+ if (!Enabled() ||
+ !message.sent_time() ||
+ !message.received_time() ||
+ message.dont_log())
+ return;
+
+ LogData data;
+ GenerateLogData(channel_id, message, &data);
+
+ if (MessageLoop::current() == main_thread_) {
+ Log(data);
+ } else {
+ main_thread_->PostTask(FROM_HERE, NewRunnableMethod(
+ this, &Logging::Log, data));
+ }
+}
+
+void Logging::GetMessageText(uint32 type, std::string* name,
+ const Message* message,
+ std::string* params) {
+ if (!log_function_map_)
+ return;
+
+ LogFunctionMap::iterator it = log_function_map_->find(type);
+ if (it == log_function_map_->end()) {
+ if (name) {
+ *name = "[UNKNOWN MSG ";
+ *name += base::IntToString(type);
+ *name += " ]";
+ }
+ return;
+ }
+
+ (*it->second)(name, message, params);
+}
+
+void Logging::Log(const LogData& data) {
+ if (consumer_) {
+ // We're in the browser process.
+ consumer_->Log(data);
+ } else {
+ // We're in the renderer or plugin processes.
+ if (sender_) {
+ queued_logs_.push_back(data);
+ if (!queue_invoke_later_pending_) {
+ queue_invoke_later_pending_ = true;
+ MessageLoop::current()->PostDelayedTask(FROM_HERE, NewRunnableMethod(
+ this, &Logging::OnSendLogs), kLogSendDelayMs);
+ }
+ }
+ }
+ if (enabled_on_stderr_) {
+ std::string message_name;
+ if (data.message_name.empty()) {
+ message_name = StringPrintf("[unknown type %d]", data.type);
+ } else {
+ message_name = data.message_name;
+ }
+ fprintf(stderr, "ipc %s %d %s %s %s\n",
+ data.channel.c_str(),
+ data.routing_id,
+ data.flags.c_str(),
+ message_name.c_str(),
+ data.params.c_str());
+ }
+}
+
+void GenerateLogData(const std::string& channel, const Message& message,
+ LogData* data) {
+ if (message.is_reply()) {
+ // "data" should already be filled in.
+ std::string params;
+ Logging::GetMessageText(data->type, NULL, &message, &params);
+
+ if (!data->params.empty() && !params.empty())
+ data->params += ", ";
+
+ data->flags += " DR";
+
+ data->params += params;
+ } else {
+ std::string flags;
+ if (message.is_sync())
+ flags = "S";
+
+ if (message.is_reply())
+ flags += "R";
+
+ if (message.is_reply_error())
+ flags += "E";
+
+ std::string params, message_name;
+ Logging::GetMessageText(message.type(), &message_name, &message, &params);
+
+ data->channel = channel;
+ data->routing_id = message.routing_id();
+ data->type = message.type();
+ data->flags = flags;
+ data->sent = message.sent_time();
+ data->receive = message.received_time();
+ data->dispatch = Time::Now().ToInternalValue();
+ data->params = params;
+ data->message_name = message_name;
+ }
+}
+
+}
+
+#endif // IPC_MESSAGE_LOG_ENABLED
diff --git a/ipc/ipc_logging.h b/ipc/ipc_logging.h
new file mode 100644
index 000000000000..42237c7ec61e
--- /dev/null
+++ b/ipc/ipc_logging.h
@@ -0,0 +1,112 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IPC_IPC_LOGGING_H_
+#define IPC_IPC_LOGGING_H_
+#pragma once
+
+#include "ipc/ipc_message.h" // For IPC_MESSAGE_LOG_ENABLED.
+
+#ifdef IPC_MESSAGE_LOG_ENABLED
+
+#include <vector>
+
+#include "base/hash_tables.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/singleton.h"
+#include "base/message_loop.h"
+#include "ipc/ipc_export.h"
+
+// Logging function. |name| is a string in ASCII and |params| is a string in
+// UTF-8.
+typedef void (*LogFunction)(std::string* name,
+ const IPC::Message* msg,
+ std::string* params);
+
+typedef base::hash_map<uint32, LogFunction > LogFunctionMap;
+
+namespace IPC {
+
+class Message;
+
+// One instance per process. Needs to be created on the main thread (the UI
+// thread in the browser) but OnPreDispatchMessage/OnPostDispatchMessage
+// can be called on other threads.
+class IPC_EXPORT Logging {
+ public:
+ // Implemented by consumers of log messages.
+ class Consumer {
+ public:
+ virtual void Log(const LogData& data) = 0;
+
+ protected:
+ virtual ~Consumer() {}
+ };
+
+ void SetConsumer(Consumer* consumer);
+
+ ~Logging();
+ static Logging* GetInstance();
+
+ // Enable and Disable are NOT cross-process; they only affect the
+ // current thread/process. If you want to modify the value for all
+ // processes, perhaps your intent is to call
+ // g_browser_process->SetIPCLoggingEnabled().
+ void Enable();
+ void Disable();
+ bool Enabled() const { return enabled_; }
+
+ // Called by child processes to give the logger object the channel to send
+ // logging data to the browser process.
+ void SetIPCSender(Message::Sender* sender);
+
+ // Called in the browser process when logging data from a child process is
+ // received.
+ void OnReceivedLoggingMessage(const Message& message);
+
+ void OnSendMessage(Message* message, const std::string& channel_id);
+ void OnPreDispatchMessage(const Message& message);
+ void OnPostDispatchMessage(const Message& message,
+ const std::string& channel_id);
+
+ // Like the *MsgLog functions declared for each message class, except this
+ // calls the correct one based on the message type automatically. Defined in
+ // ipc_logging.cc.
+ static void GetMessageText(uint32 type, std::string* name,
+ const Message* message, std::string* params);
+
+ static void set_log_function_map(LogFunctionMap* functions) {
+ log_function_map_ = functions;
+ }
+
+ static LogFunctionMap* log_function_map() {
+ return log_function_map_;
+ }
+
+ private:
+ friend struct DefaultSingletonTraits<Logging>;
+ Logging();
+
+ void OnSendLogs();
+ void Log(const LogData& data);
+
+ bool enabled_;
+ bool enabled_on_stderr_; // only used on POSIX for now
+
+ std::vector<LogData> queued_logs_;
+ bool queue_invoke_later_pending_;
+
+ Message::Sender* sender_;
+ MessageLoop* main_thread_;
+
+ Consumer* consumer_;
+
+ static LogFunctionMap* log_function_map_;
+};
+
+} // namespace IPC
+
+#endif // IPC_MESSAGE_LOG_ENABLED
+
+#endif // IPC_IPC_LOGGING_H_
diff --git a/ipc/ipc_message.cc b/ipc/ipc_message.cc
new file mode 100644
index 000000000000..235a7d592eca
--- /dev/null
+++ b/ipc/ipc_message.cc
@@ -0,0 +1,128 @@
+// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ipc/ipc_message.h"
+
+//#include "base/logging.h"
+#include "log.h"
+#include "build/build_config.h"
+
+#if defined(OS_POSIX)
+//#include "ipc/file_descriptor_set_posix.h"
+#endif
+
+namespace IPC {
+
+//------------------------------------------------------------------------------
+
+Message::~Message() {
+}
+
+Message::Message()
+ : Pickle(sizeof(Header)) {
+ header()->routing = header()->type = header()->flags = 0;
+#if defined(OS_POSIX)
+ header()->num_fds = 0;
+ header()->pad = 0;
+#endif
+ InitLoggingVariables();
+}
+
+Message::Message(int32 routing_id, uint32 type, PriorityValue priority)
+ : Pickle(sizeof(Header)) {
+ header()->routing = routing_id;
+ header()->type = type;
+ header()->flags = priority;
+#if defined(OS_POSIX)
+ header()->num_fds = 0;
+ header()->pad = 0;
+#endif
+ InitLoggingVariables();
+}
+
+Message::Message(const char* data, int data_len) : Pickle(data, data_len) {
+ InitLoggingVariables();
+}
+
+Message::Message(const Message& other) : Pickle(other) {
+ InitLoggingVariables();
+#if defined(OS_POSIX)
+// file_descriptor_set_ = other.file_descriptor_set_;
+#endif
+}
+
+void Message::InitLoggingVariables() {
+#ifdef IPC_MESSAGE_LOG_ENABLED
+ received_time_ = 0;
+ dont_log_ = false;
+ log_data_ = NULL;
+#endif
+}
+
+Message& Message::operator=(const Message& other) {
+ *static_cast<Pickle*>(this) = other;
+#if defined(OS_POSIX)
+// file_descriptor_set_ = other.file_descriptor_set_;
+#endif
+ return *this;
+}
+
+#ifdef IPC_MESSAGE_LOG_ENABLED
+void Message::set_sent_time(int64 time) {
+ DCHECK((header()->flags & HAS_SENT_TIME_BIT) == 0);
+ header()->flags |= HAS_SENT_TIME_BIT;
+ WriteInt64(time);
+}
+
+int64 Message::sent_time() const {
+ if ((header()->flags & HAS_SENT_TIME_BIT) == 0)
+ return 0;
+
+ const char* data = end_of_payload();
+ data -= sizeof(int64);
+ return *(reinterpret_cast<const int64*>(data));
+}
+
+void Message::set_received_time(int64 time) const {
+ received_time_ = time;
+}
+#endif
+
+#if defined(OS_POSIX)
+/*
+bool Message::WriteFileDescriptor(const base::FileDescriptor& descriptor) {
+ // We write the index of the descriptor so that we don't have to
+ // keep the current descriptor as extra decoding state when deserialising.
+ WriteInt(file_descriptor_set()->size());
+ if (descriptor.auto_close) {
+ return file_descriptor_set()->AddAndAutoClose(descriptor.fd);
+ } else {
+ return file_descriptor_set()->Add(descriptor.fd);
+ }
+}
+
+bool Message::ReadFileDescriptor(void** iter,
+ base::FileDescriptor* descriptor) const {
+ int descriptor_index;
+ if (!ReadInt(iter, &descriptor_index))
+ return false;
+
+ FileDescriptorSet* file_descriptor_set = file_descriptor_set_.get();
+ if (!file_descriptor_set)
+ return false;
+
+ descriptor->fd = file_descriptor_set->GetDescriptorAt(descriptor_index);
+ descriptor->auto_close = true;
+
+ return descriptor->fd >= 0;
+}
+
+void Message::EnsureFileDescriptorSet() {
+ if (file_descriptor_set_.get() == NULL)
+ file_descriptor_set_ = new FileDescriptorSet;
+}
+*/
+#endif
+
+} // namespace IPC
diff --git a/ipc/ipc_message.h b/ipc/ipc_message.h
new file mode 100644
index 000000000000..11ed17c4672c
--- /dev/null
+++ b/ipc/ipc_message.h
@@ -0,0 +1,284 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IPC_IPC_MESSAGE_H_
+#define IPC_IPC_MESSAGE_H_
+#pragma once
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/pickle.h"
+#include "ipc/ipc_export.h"
+
+#ifndef NDEBUG
+//#define IPC_MESSAGE_LOG_ENABLED
+#endif
+
+#if defined(OS_POSIX)
+#include "base/memory/ref_counted.h"
+#endif
+
+namespace base {
+struct FileDescriptor;
+}
+
+class FileDescriptorSet;
+
+namespace IPC {
+
+//------------------------------------------------------------------------------
+
+class Channel;
+class Message;
+struct LogData;
+
+class IPC_EXPORT Message : public Pickle {
+ public:
+ // Implemented by objects that can send IPC messages across a channel.
+ class IPC_EXPORT Sender {
+ public:
+ virtual ~Sender() {}
+
+ // Sends the given IPC message. The implementor takes ownership of the
+ // given Message regardless of whether or not this method succeeds. This
+ // is done to make this method easier to use. Returns true on success and
+ // false otherwise.
+ virtual bool Send(Message* msg) = 0;
+ };
+
+ enum PriorityValue {
+ PRIORITY_LOW = 1,
+ PRIORITY_NORMAL,
+ PRIORITY_HIGH
+ };
+
+ virtual ~Message();
+
+ Message();
+
+ // Initialize a message with a user-defined type, priority value, and
+ // destination WebView ID.
+ Message(int32 routing_id, uint32 type, PriorityValue priority);
+
+ // Initializes a message from a const block of data. The data is not copied;
+ // instead the data is merely referenced by this message. Only const methods
+ // should be used on the message when initialized this way.
+ Message(const char* data, int data_len);
+
+ Message(const Message& other);
+ Message& operator=(const Message& other);
+
+ PriorityValue priority() const {
+ return static_cast<PriorityValue>(header()->flags & PRIORITY_MASK);
+ }
+
+ // True if this is a synchronous message.
+ bool is_sync() const {
+ return (header()->flags & SYNC_BIT) != 0;
+ }
+
+ // Set this on a reply to a synchronous message.
+ void set_reply() {
+ header()->flags |= REPLY_BIT;
+ }
+
+ bool is_reply() const {
+ return (header()->flags & REPLY_BIT) != 0;
+ }
+
+ // Set this on a reply to a synchronous message to indicate that no receiver
+ // was found.
+ void set_reply_error() {
+ header()->flags |= REPLY_ERROR_BIT;
+ }
+
+ bool is_reply_error() const {
+ return (header()->flags & REPLY_ERROR_BIT) != 0;
+ }
+
+ // Normally when a receiver gets a message and they're blocked on a
+ // synchronous message Send, they buffer a message. Setting this flag causes
+ // the receiver to be unblocked and the message to be dispatched immediately.
+ void set_unblock(bool unblock) {
+ if (unblock) {
+ header()->flags |= UNBLOCK_BIT;
+ } else {
+ header()->flags &= ~UNBLOCK_BIT;
+ }
+ }
+
+ bool should_unblock() const {
+ return (header()->flags & UNBLOCK_BIT) != 0;
+ }
+
+ // Tells the receiver that the caller is pumping messages while waiting
+ // for the result.
+ bool is_caller_pumping_messages() const {
+ return (header()->flags & PUMPING_MSGS_BIT) != 0;
+ }
+
+ uint32 type() const {
+ return header()->type;
+ }
+
+ int32 routing_id() const {
+ return header()->routing;
+ }
+
+ void set_routing_id(int32 new_id) {
+ header()->routing = new_id;
+ }
+
+ template<class T, class S>
+ static bool Dispatch(const Message* msg, T* obj, S* sender,
+ void (T::*func)()) {
+ (obj->*func)();
+ return true;
+ }
+
+ template<class T, class S>
+ static bool Dispatch(const Message* msg, T* obj, S* sender,
+ void (T::*func)() const) {
+ (obj->*func)();
+ return true;
+ }
+
+ template<class T, class S>
+ static bool Dispatch(const Message* msg, T* obj, S* sender,
+ void (T::*func)(const Message&)) {
+ (obj->*func)(*msg);
+ return true;
+ }
+
+ template<class T, class S>
+ static bool Dispatch(const Message* msg, T* obj, S* sender,
+ void (T::*func)(const Message&) const) {
+ (obj->*func)(*msg);
+ return true;
+ }
+
+ // Used for async messages with no parameters.
+ static void Log(std::string* name, const Message* msg, std::string* l) {
+ }
+
+ // Find the end of the message data that starts at range_start. Returns NULL
+ // if the entire message is not found in the given data range.
+ static const char* FindNext(const char* range_start, const char* range_end) {
+ return Pickle::FindNext(sizeof(Header), range_start, range_end);
+ }
+
+#if defined(OS_POSIX)
+ // On POSIX, a message supports reading / writing FileDescriptor objects.
+ // This is used to pass a file descriptor to the peer of an IPC channel.
+
+ // Add a descriptor to the end of the set. Returns false iff the set is full.
+// bool WriteFileDescriptor(const base::FileDescriptor& descriptor);
+ // Get a file descriptor from the message. Returns false on error.
+ // iter: a Pickle iterator to the current location in the message.
+// bool ReadFileDescriptor(void** iter, base::FileDescriptor* descriptor) const;
+#endif
+
+#ifdef IPC_MESSAGE_LOG_ENABLED
+ // Adds the outgoing time from Time::Now() at the end of the message and sets
+ // a bit to indicate that it's been added.
+ void set_sent_time(int64 time);
+ int64 sent_time() const;
+
+ void set_received_time(int64 time) const;
+ int64 received_time() const { return received_time_; }
+ void set_output_params(const std::string& op) const { output_params_ = op; }
+ const std::string& output_params() const { return output_params_; }
+ // The following four functions are needed so we can log sync messages with
+ // delayed replies. We stick the log data from the sent message into the
+ // reply message, so that when it's sent and we have the output parameters
+ // we can log it. As such, we set a flag on the sent message to not log it.
+ void set_sync_log_data(LogData* data) const { log_data_ = data; }
+ LogData* sync_log_data() const { return log_data_; }
+ void set_dont_log() const { dont_log_ = true; }
+ bool dont_log() const { return dont_log_; }
+#endif
+
+ protected:
+ friend class Channel;
+ friend class MessageReplyDeserializer;
+ friend class SyncMessage;
+
+ void set_sync() {
+ header()->flags |= SYNC_BIT;
+ }
+
+ // flags
+ enum {
+ PRIORITY_MASK = 0x0003,
+ SYNC_BIT = 0x0004,
+ REPLY_BIT = 0x0008,
+ REPLY_ERROR_BIT = 0x0010,
+ UNBLOCK_BIT = 0x0020,
+ PUMPING_MSGS_BIT= 0x0040,
+ HAS_SENT_TIME_BIT = 0x0080,
+ };
+
+#pragma pack(push, 4)
+ struct Header : Pickle::Header {
+ int32 routing; // ID of the view that this message is destined for
+ uint32 type; // specifies the user-defined message type
+ uint32 flags; // specifies control flags for the message
+#if defined(OS_POSIX)
+ uint16 num_fds; // the number of descriptors included with this message
+ uint16 pad; // explicitly initialize this to appease valgrind
+#endif
+ };
+#pragma pack(pop)
+
+ Header* header() {
+ return headerT<Header>();
+ }
+ const Header* header() const {
+ return headerT<Header>();
+ }
+
+ void InitLoggingVariables();
+
+#if defined(OS_POSIX)
+ // The set of file descriptors associated with this message.
+// scoped_refptr<FileDescriptorSet> file_descriptor_set_;
+
+ // Ensure that a FileDescriptorSet is allocated
+// void EnsureFileDescriptorSet();
+
+// FileDescriptorSet* file_descriptor_set() {
+// EnsureFileDescriptorSet();
+// return file_descriptor_set_.get();
+// }
+// const FileDescriptorSet* file_descriptor_set() const {
+// return file_descriptor_set_.get();
+// }
+#endif
+
+#ifdef IPC_MESSAGE_LOG_ENABLED
+ // Used for logging.
+ mutable int64 received_time_;
+ mutable std::string output_params_;
+ mutable LogData* log_data_;
+ mutable bool dont_log_;
+#endif
+};
+
+//------------------------------------------------------------------------------
+
+} // namespace IPC
+
+enum SpecialRoutingIDs {
+ // indicates that we don't have a routing ID yet.
+ MSG_ROUTING_NONE = -2,
+
+ // indicates a general message not sent to a particular tab.
+ MSG_ROUTING_CONTROL = kint32max,
+};
+
+#define IPC_REPLY_ID 0xFFFFFFF0 // Special message id for replies
+#define IPC_LOGGING_ID 0xFFFFFFF1 // Special message id for logging
+
+#endif // IPC_IPC_MESSAGE_H_
diff --git a/ipc/ipc_message_macros.h b/ipc/ipc_message_macros.h
new file mode 100644
index 000000000000..302d12544e4e
--- /dev/null
+++ b/ipc/ipc_message_macros.h
@@ -0,0 +1,822 @@
+// 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.
+
+// Defining IPC Messages
+//
+// Your IPC messages will be defined by macros inside of an XXX_messages.h
+// header file. Most of the time, the system can automatically generate all
+// of messaging mechanism from these definitions, but sometimes some manual
+// coding is required. In these cases, you will also have an XXX_messages.cc
+// implemation file as well.
+//
+// The senders of your messages will include your XXX_messages.h file to
+// get the full set of definitions they need to send your messages.
+//
+// Each XXX_messages.h file must be registered with the IPC system. This
+// requires adding two things:
+// - An XXXMsgStart value to the IPCMessageStart enum in ipc_message_utils.h
+// - An inclusion of XXX_messages.h file in a message generator .h file
+//
+// The XXXMsgStart value is an enumeration that ensures uniqueness for
+// each different message file. Later, you will use this inside your
+// XXX_messages.h file before invoking message declatation macros:
+// #define IPC_MESSAGE_START XXXMsgStart
+// ( ... your macro invocations go here ... )
+//
+// Message Generator Files
+//
+// A message generator .h header file pulls in all other message-declaring
+// headers for a given component. It is included by a message generator
+// .cc file, which is where all the generated code will wind up. Typically,
+// you will use an existing generator (e.g. common_message_generator.cc
+// in /chrome/common), but there are circumstances where you may add a
+// new one.
+//
+// In the rare cicrucmstances where you can't re-use an existing file,
+// your YYY_message_generator.cc file for a component YYY would contain
+// the following code:
+// // Get basic type definitions.
+// #define IPC_MESSAGE_IMPL
+// #include "path/to/YYY_message_generator.h"
+// // Generate constructors.
+// #include "ipc/struct_constructor_macros.h"
+// #include "path/to/YYY_message_generator.h"
+// // Generate destructors.
+// #include "ipc/struct_destructor_macros.h"
+// #include "path/to/YYY_message_generator.h"
+// // Generate param traits write methods.
+// #include "ipc/param_traits_write_macros.h"
+// namespace IPC {
+// #include "path/to/YYY_message_generator.h"
+// } // namespace IPC
+// // Generate param traits read methods.
+// #include "ipc/param_traits_read_macros.h"
+// namespace IPC {
+// #include "path/to/YYY_message_generator.h"
+// } // namespace IPC
+// // Generate param traits log methods.
+// #include "ipc/param_traits_log_macros.h"
+// namespace IPC {
+// #include "path/to/YYY_message_generator.h"
+// } // namespace IPC
+//
+// In cases where manual generation is required, in your XXX_messages.cc
+// file, put the following after all the includes for param types:
+// #define IPC_MESSAGE_IMPL
+// #include "XXX_messages.h"
+// (... implementation of traits not auto-generated ...)
+//
+// Multiple Inclusion
+//
+// The XXX_messages.h file will be multiply-included by the
+// YYY_message_generator.cc file, so your XXX_messages file can't be
+// guarded in the usual manner. Ideally, there will be no need for any
+// inclusion guard, since the XXX_messages.h file should consist soley
+// of inclusions of other headers (which are self-guarding) and IPC
+// macros (which are multiply evaluating).
+//
+// Note that there is no #pragma once either; doing so would mark the whole
+// file as being singly-included. Since your XXX_messages.h file is only
+// partially-guarded, care must be taken to ensure that it is only included
+// by other .cc files (and the YYY_message_generator.h file). Including an
+// XXX_messages.h file in some other .h file may result in duplicate
+// declarations and a compilation failure.
+//
+// Type Declarations
+//
+// It is generally a bad idea to have type definitions in a XXX_messages.h
+// file; most likely the typedef will then be used in the message, as opposed
+// to the struct iself. Later, an IPC message dispatcher wil need to call
+// a function taking that type, and that function is declared in some other
+// header. Thus, in order to get the type definition, the other header
+// would have to include the XXX_messages.h file, violating the rule above
+// about not including XXX_messages.h file in other .h files.
+//
+// One approach here is to move these type definitions to another (guarded)
+// .h file and include this second .h in your XXX_messages.h file. This
+// is still less than ideal, because the dispatched function would have to
+// redeclare the typedef or include this second header. This may be
+// reasonable in a few cases.
+//
+// Failing all of the above, then you will want to bracket the smallest
+// possible section of your XXX_messages.h file containing these types
+// with an include guard macro. Be aware that providing an incomplete
+// class type declaration to avoid pulling in a long chain of headers is
+// acceptable when your XXX_messages.h header is being included by the
+// message sending caller's code, but not when the YYY_message_generator.c
+// is building the messages. In addtion, due to the multiple inclusion
+// restriction, these type ought to be guarded. Follow a convention like:
+// #ifndef SOME_GUARD_MACRO
+// #define SOME_GUARD_MACRO
+// class some_class; // One incomplete class declaration
+// class_some_other_class; // Another incomplete class declaration
+// #endif // SOME_GUARD_MACRO
+// #ifdef IPC_MESSAGE_IMPL
+// #inlcude "path/to/some_class.h" // Full class declaration
+// #inlcude "path/to/some_other_class.h" // Full class declaration
+// #endif // IPC_MESSAGE_IMPL
+// (.. IPC macros using some_class and some_other_class ...)
+//
+// Macro Invocations
+//
+// You will use IPC message macro invocations for three things:
+// - New struct definitions for IPC
+// - Registering existing struct and enum definitions with IPC
+// - Defining the messages themselves
+//
+// New structs are defined with IPC_STRUCT_BEGIN(), IPC_STRUCT_MEMBER(),
+// IPC_STRUCT_END() family of macros. These cause the XXX_messages.h
+// to proclaim equivalent struct declarations for use by callers, as well
+// as later registering the type with the message generation. Note that
+// IPC_STRUCT_MEMBER() is only permitted inside matching calls to
+// IPC_STRUCT_BEGIN() / IPC_STRUCT_END().
+//
+// Externally-defined structs are registered with IPC_STRUCT_TRAITS_BEGIN(),
+// IPC_STRUCT_TRAITS_MEMBER(), and IPC_STRUCT_TRAITS_END() macros. These
+// cause registration of the types with message generation only.
+// There's also IPC_STRUCT_TRAITS_PARENT, which is used to register a parent
+// class (whose own traits are already defined). Note that
+// IPC_STRUCT_TRAITS_MEMBER() and IPC_STRUCT_TRAITS_PARENT are only permitted
+// inside matching calls to IPC_STRUCT_TRAITS_BEGIN() /
+// IPC_STRUCT_TRAITS_END().
+//
+// Enum types are registered with a single IPC_ENUM_TRAITS() macro. There
+// is no need to enumerate each value to the IPC mechanism.
+//
+// Do not place semicolons following these IPC_ macro invocations. There
+// is no reason to expect that their expansion corresponds one-to-one with
+// C++ statements.
+//
+// Once the types have been declared / registered, message definitions follow.
+// "Sync" messages are just synchronous calls, the Send() call doesn't return
+// until a reply comes back. Input parameters are first (const TYPE&), and
+// To declare a sync message, use the IPC_SYNC_ macros. The numbers at the
+// end show how many input/output parameters there are (i.e. 1_2 is 1 in, 2
+// out). The caller does a Send([route id, ], in1, &out1, &out2).
+// The receiver's handler function will be
+// void OnSyncMessageName(const type1& in1, type2* out1, type3* out2)
+//
+// A caller can also send a synchronous message, while the receiver can respond
+// at a later time. This is transparent from the sender's side. The receiver
+// needs to use a different handler that takes in a IPC::Message* as the output
+// type, stash the message, and when it has the data it can Send the message.
+//
+// Use the IPC_MESSAGE_HANDLER_DELAY_REPLY macro instead of IPC_MESSAGE_HANDLER
+// IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_SyncMessageName,
+// OnSyncMessageName)
+//
+// The handler function will look like:
+// void OnSyncMessageName(const type1& in1, IPC::Message* reply_msg);
+//
+// Receiver stashes the IPC::Message* pointer, and when it's ready, it does:
+// ViewHostMsg_SyncMessageName::WriteReplyParams(reply_msg, out1, out2);
+// Send(reply_msg);
+
+#ifndef IPC_IPC_MESSAGE_MACROS_H_
+#define IPC_IPC_MESSAGE_MACROS_H_
+
+#include "ipc/ipc_message_utils.h"
+#include "ipc/param_traits_macros.h"
+
+#if defined(IPC_MESSAGE_IMPL)
+#include "ipc/ipc_message_utils_impl.h"
+#endif
+
+// Macros for defining structs. May be subsequently redefined.
+#define IPC_STRUCT_BEGIN(struct_name) \
+ struct struct_name; \
+ IPC_STRUCT_TRAITS_BEGIN(struct_name) \
+ IPC_STRUCT_TRAITS_END() \
+ struct struct_name : IPC::NoParams { \
+ struct_name(); \
+ ~struct_name();
+#define IPC_STRUCT_MEMBER(type, name) type name;
+#define IPC_STRUCT_END() };
+
+// Message macros collect specific numbers of arguments and funnel them into
+// the common message generation macro. These should never be redefined.
+#define IPC_MESSAGE_CONTROL0(msg_class) \
+ IPC_MESSAGE_DECL(EMPTY, CONTROL, msg_class, 0, 0, (), ())
+
+#define IPC_MESSAGE_CONTROL1(msg_class, type1) \
+ IPC_MESSAGE_DECL(ASYNC, CONTROL, msg_class, 1, 0, (type1), ())
+
+#define IPC_MESSAGE_CONTROL2(msg_class, type1, type2) \
+ IPC_MESSAGE_DECL(ASYNC, CONTROL, msg_class, 2, 0, (type1, type2), ())
+
+#define IPC_MESSAGE_CONTROL3(msg_class, type1, type2, type3) \
+ IPC_MESSAGE_DECL(ASYNC, CONTROL, msg_class, 3, 0, (type1, type2, type3), ())
+
+#define IPC_MESSAGE_CONTROL4(msg_class, type1, type2, type3, type4) \
+ IPC_MESSAGE_DECL(ASYNC, CONTROL, msg_class, 4, 0, (type1, type2, type3, type4), ())
+
+#define IPC_MESSAGE_CONTROL5(msg_class, type1, type2, type3, type4, type5) \
+ IPC_MESSAGE_DECL(ASYNC, CONTROL, msg_class, 5, 0, (type1, type2, type3, type4, type5), ())
+
+#define IPC_MESSAGE_CONTROL6(msg_class, type1, type2, type3, type4, type5, type6) \
+ IPC_MESSAGE_DECL(ASYNC, CONTROL, msg_class, 6, 0, (type1, type2, type3, type4, type5, type6), ())
+
+
+#define IPC_MESSAGE_ROUTED0(msg_class) \
+ IPC_MESSAGE_DECL(EMPTY, ROUTED, msg_class, 0, 0, (), ())
+
+#define IPC_MESSAGE_ROUTED1(msg_class, type1) \
+ IPC_MESSAGE_DECL(ASYNC, ROUTED, msg_class, 1, 0, (type1), ())
+
+#define IPC_MESSAGE_ROUTED2(msg_class, type1, type2) \
+ IPC_MESSAGE_DECL(ASYNC, ROUTED, msg_class, 2, 0, (type1, type2), ())
+
+#define IPC_MESSAGE_ROUTED3(msg_class, type1, type2, type3) \
+ IPC_MESSAGE_DECL(ASYNC, ROUTED, msg_class, 3, 0, (type1, type2, type3), ())
+
+#define IPC_MESSAGE_ROUTED4(msg_class, type1, type2, type3, type4) \
+ IPC_MESSAGE_DECL(ASYNC, ROUTED, msg_class, 4, 0, (type1, type2, type3, type4), ())
+
+#define IPC_MESSAGE_ROUTED5(msg_class, type1, type2, type3, type4, type5) \
+ IPC_MESSAGE_DECL(ASYNC, ROUTED, msg_class, 5, 0, (type1, type2, type3, type4, type5), ())
+
+#define IPC_MESSAGE_ROUTED6(msg_class, type1, type2, type3, type4, type5, type6) \
+ IPC_MESSAGE_DECL(ASYNC, ROUTED, msg_class, 6, 0, (type1, type2, type3, type4, type5, type6), ())
+
+#define IPC_SYNC_MESSAGE_CONTROL0_0(msg_class) \
+ IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 0, 0, (), ())
+
+#define IPC_SYNC_MESSAGE_CONTROL0_1(msg_class, type1_out) \
+ IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 0, 1, (), (type1_out))
+
+#define IPC_SYNC_MESSAGE_CONTROL0_2(msg_class, type1_out, type2_out) \
+ IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 0, 2, (), (type1_out, type2_out))
+
+#define IPC_SYNC_MESSAGE_CONTROL0_3(msg_class, type1_out, type2_out, type3_out) \
+ IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 0, 3, (), (type1_out, type2_out, type3_out))
+
+#define IPC_SYNC_MESSAGE_CONTROL0_4(msg_class, type1_out, type2_out, type3_out, type4_out) \
+ IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 0, 4, (), (type1_out, type2_out, type3_out, type4_out))
+
+#define IPC_SYNC_MESSAGE_CONTROL1_0(msg_class, type1_in) \
+ IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 1, 0, (type1_in), ())
+
+#define IPC_SYNC_MESSAGE_CONTROL1_1(msg_class, type1_in, type1_out) \
+ IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 1, 1, (type1_in), (type1_out))
+
+#define IPC_SYNC_MESSAGE_CONTROL1_2(msg_class, type1_in, type1_out, type2_out) \
+ IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 1, 2, (type1_in), (type1_out, type2_out))
+
+#define IPC_SYNC_MESSAGE_CONTROL1_3(msg_class, type1_in, type1_out, type2_out, type3_out) \
+ IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 1, 3, (type1_in), (type1_out, type2_out, type3_out))
+
+#define IPC_SYNC_MESSAGE_CONTROL1_4(msg_class, type1_in, type1_out, type2_out, type3_out, type4_out) \
+ IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 1, 4, (type1_in), (type1_out, type2_out, type3_out, type4_out))
+
+#define IPC_SYNC_MESSAGE_CONTROL2_0(msg_class, type1_in, type2_in) \
+ IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 2, 0, (type1_in, type2_in), ())
+
+#define IPC_SYNC_MESSAGE_CONTROL2_1(msg_class, type1_in, type2_in, type1_out) \
+ IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 2, 1, (type1_in, type2_in), (type1_out))
+
+#define IPC_SYNC_MESSAGE_CONTROL2_2(msg_class, type1_in, type2_in, type1_out, type2_out) \
+ IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 2, 2, (type1_in, type2_in), (type1_out, type2_out))
+
+#define IPC_SYNC_MESSAGE_CONTROL2_3(msg_class, type1_in, type2_in, type1_out, type2_out, type3_out) \
+ IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 2, 3, (type1_in, type2_in), (type1_out, type2_out, type3_out))
+
+#define IPC_SYNC_MESSAGE_CONTROL2_4(msg_class, type1_in, type2_in, type1_out, type2_out, type3_out, type4_out) \
+ IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 2, 4, (type1_in, type2_in), (type1_out, type2_out, type3_out, type4_out))
+
+#define IPC_SYNC_MESSAGE_CONTROL3_0(msg_class, type1_in, type2_in, type3_in) \
+ IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 3, 0, (type1_in, type2_in, type3_in), ())
+
+#define IPC_SYNC_MESSAGE_CONTROL3_1(msg_class, type1_in, type2_in, type3_in, type1_out) \
+ IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 3, 1, (type1_in, type2_in, type3_in), (type1_out))
+
+#define IPC_SYNC_MESSAGE_CONTROL3_2(msg_class, type1_in, type2_in, type3_in, type1_out, type2_out) \
+ IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 3, 2, (type1_in, type2_in, type3_in), (type1_out, type2_out))
+
+#define IPC_SYNC_MESSAGE_CONTROL3_3(msg_class, type1_in, type2_in, type3_in, type1_out, type2_out, type3_out) \
+ IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 3, 3, (type1_in, type2_in, type3_in), (type1_out, type2_out, type3_out))
+
+#define IPC_SYNC_MESSAGE_CONTROL3_4(msg_class, type1_in, type2_in, type3_in, type1_out, type2_out, type3_out, type4_out) \
+ IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 3, 4, (type1_in, type2_in, type3_in), (type1_out, type2_out, type3_out, type4_out))
+
+#define IPC_SYNC_MESSAGE_CONTROL4_0(msg_class, type1_in, type2_in, type3_in, type4_in) \
+ IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 4, 0, (type1_in, type2_in, type3_in, type4_in), ())
+
+#define IPC_SYNC_MESSAGE_CONTROL4_1(msg_class, type1_in, type2_in, type3_in, type4_in, type1_out) \
+ IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 4, 1, (type1_in, type2_in, type3_in, type4_in), (type1_out))
+
+#define IPC_SYNC_MESSAGE_CONTROL4_2(msg_class, type1_in, type2_in, type3_in, type4_in, type1_out, type2_out) \
+ IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 4, 2, (type1_in, type2_in, type3_in, type4_in), (type1_out, type2_out))
+
+#define IPC_SYNC_MESSAGE_CONTROL4_3(msg_class, type1_in, type2_in, type3_in, type4_in, type1_out, type2_out, type3_out) \
+ IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 4, 3, (type1_in, type2_in, type3_in, type4_in), (type1_out, type2_out, type3_out))
+
+#define IPC_SYNC_MESSAGE_CONTROL4_4(msg_class, type1_in, type2_in, type3_in, type4_in, type1_out, type2_out, type3_out, type4_out) \
+ IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 4, 4, (type1_in, type2_in, type3_in, type4_in), (type1_out, type2_out, type3_out, type4_out))
+
+#define IPC_SYNC_MESSAGE_CONTROL5_0(msg_class, type1_in, type2_in, type3_in, type4_in, type5_in) \
+ IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 5, 0, (type1_in, type2_in, type3_in, type4_in, type5_in), ())
+
+#define IPC_SYNC_MESSAGE_CONTROL5_1(msg_class, type1_in, type2_in, type3_in, type4_in, type5_in, type1_out) \
+ IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 5, 1, (type1_in, type2_in, type3_in, type4_in, type5_in), (type1_out))
+
+#define IPC_SYNC_MESSAGE_CONTROL5_2(msg_class, type1_in, type2_in, type3_in, type4_in, type5_in, type1_out, type2_out) \
+ IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 5, 2, (type1_in, type2_in, type3_in, type4_in, type5_in), (type1_out, type2_out))
+
+#define IPC_SYNC_MESSAGE_CONTROL5_3(msg_class, type1_in, type2_in, type3_in, type4_in, type5_in, type1_out, type2_out, type3_out) \
+ IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 5, 3, (type1_in, type2_in, type3_in, type4_in, type5_in), (type1_out, type2_out, type3_out))
+
+#define IPC_SYNC_MESSAGE_CONTROL5_4(msg_class, type1_in, type2_in, type3_in, type4_in, type5_in, type1_out, type2_out, type3_out, type4_out) \
+ IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 5, 4, (type1_in, type2_in, type3_in, type4_in, type5_in), (type1_out, type2_out, type3_out, type4_out))
+
+#define IPC_SYNC_MESSAGE_CONTROL6_0(msg_class, type1_in, type2_in, type3_in, type4_in, type5_in, type6_in) \
+ IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 6, 0, (type1_in, type2_in, type3_in, type4_in, type5_in, type6_in), ())
+
+#define IPC_SYNC_MESSAGE_CONTROL6_1(msg_class, type1_in, type2_in, type3_in, type4_in, type5_in, type6_in, type1_out) \
+ IPC_MESSAGE_DECL(SYNC, CONTROL, msg_class, 6, 1, (type1_in, type2_in, type3_in, type4_in, type5_in, type6_in), (type1_out))
+
+#define IPC_SYNC_MESSAGE_ROUTED0_0(msg_class) \
+ IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 0, 0, (), ())
+
+#define IPC_SYNC_MESSAGE_ROUTED0_1(msg_class, type1_out) \
+ IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 0, 1, (), (type1_out))
+
+#define IPC_SYNC_MESSAGE_ROUTED0_2(msg_class, type1_out, type2_out) \
+ IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 0, 2, (), (type1_out, type2_out))
+
+#define IPC_SYNC_MESSAGE_ROUTED0_3(msg_class, type1_out, type2_out, type3_out) \
+ IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 0, 3, (), (type1_out, type2_out, type3_out))
+
+#define IPC_SYNC_MESSAGE_ROUTED0_4(msg_class, type1_out, type2_out, type3_out, type4_out) \
+ IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 0, 4, (), (type1_out, type2_out, type3_out, type4_out))
+
+#define IPC_SYNC_MESSAGE_ROUTED1_0(msg_class, type1_in) \
+ IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 1, 0, (type1_in), ())
+
+#define IPC_SYNC_MESSAGE_ROUTED1_1(msg_class, type1_in, type1_out) \
+ IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 1, 1, (type1_in), (type1_out))
+
+#define IPC_SYNC_MESSAGE_ROUTED1_2(msg_class, type1_in, type1_out, type2_out) \
+ IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 1, 2, (type1_in), (type1_out, type2_out))
+
+#define IPC_SYNC_MESSAGE_ROUTED1_3(msg_class, type1_in, type1_out, type2_out, type3_out) \
+ IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 1, 3, (type1_in), (type1_out, type2_out, type3_out))
+
+#define IPC_SYNC_MESSAGE_ROUTED1_4(msg_class, type1_in, type1_out, type2_out, type3_out, type4_out) \
+ IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 1, 4, (type1_in), (type1_out, type2_out, type3_out, type4_out))
+
+#define IPC_SYNC_MESSAGE_ROUTED2_0(msg_class, type1_in, type2_in) \
+ IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 2, 0, (type1_in, type2_in), ())
+
+#define IPC_SYNC_MESSAGE_ROUTED2_1(msg_class, type1_in, type2_in, type1_out) \
+ IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 2, 1, (type1_in, type2_in), (type1_out))
+
+#define IPC_SYNC_MESSAGE_ROUTED2_2(msg_class, type1_in, type2_in, type1_out, type2_out) \
+ IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 2, 2, (type1_in, type2_in), (type1_out, type2_out))
+
+#define IPC_SYNC_MESSAGE_ROUTED2_3(msg_class, type1_in, type2_in, type1_out, type2_out, type3_out) \
+ IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 2, 3, (type1_in, type2_in), (type1_out, type2_out, type3_out))
+
+#define IPC_SYNC_MESSAGE_ROUTED2_4(msg_class, type1_in, type2_in, type1_out, type2_out, type3_out, type4_out) \
+ IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 2, 4, (type1_in, type2_in), (type1_out, type2_out, type3_out, type4_out))
+
+#define IPC_SYNC_MESSAGE_ROUTED3_0(msg_class, type1_in, type2_in, type3_in) \
+ IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 3, 0, (type1_in, type2_in, type3_in), ())
+
+#define IPC_SYNC_MESSAGE_ROUTED3_1(msg_class, type1_in, type2_in, type3_in, type1_out) \
+ IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 3, 1, (type1_in, type2_in, type3_in), (type1_out))
+
+#define IPC_SYNC_MESSAGE_ROUTED3_2(msg_class, type1_in, type2_in, type3_in, type1_out, type2_out) \
+ IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 3, 2, (type1_in, type2_in, type3_in), (type1_out, type2_out))
+
+#define IPC_SYNC_MESSAGE_ROUTED3_3(msg_class, type1_in, type2_in, type3_in, type1_out, type2_out, type3_out) \
+ IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 3, 3, (type1_in, type2_in, type3_in), (type1_out, type2_out, type3_out))
+
+#define IPC_SYNC_MESSAGE_ROUTED3_4(msg_class, type1_in, type2_in, type3_in, type1_out, type2_out, type3_out, type4_out) \
+ IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 3, 4, (type1_in, type2_in, type3_in), (type1_out, type2_out, type3_out, type4_out))
+
+#define IPC_SYNC_MESSAGE_ROUTED4_0(msg_class, type1_in, type2_in, type3_in, type4_in) \
+ IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 4, 1, (type1_in, type2_in, type3_in, type4_in), ())
+
+#define IPC_SYNC_MESSAGE_ROUTED4_1(msg_class, type1_in, type2_in, type3_in, type4_in, type1_out) \
+ IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 4, 1, (type1_in, type2_in, type3_in, type4_in), (type1_out))
+
+#define IPC_SYNC_MESSAGE_ROUTED4_2(msg_class, type1_in, type2_in, type3_in, type4_in, type1_out, type2_out) \
+ IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 4, 2, (type1_in, type2_in, type3_in, type4_in), (type1_out, type2_out))
+
+#define IPC_SYNC_MESSAGE_ROUTED4_3(msg_class, type1_in, type2_in, type3_in, type4_in, type1_out, type2_out, type3_out) \
+ IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 4, 3, (type1_in, type2_in, type3_in, type4_in), (type1_out, type2_out, type3_out))
+
+#define IPC_SYNC_MESSAGE_ROUTED4_4(msg_class, type1_in, type2_in, type3_in, type4_in, type1_out, type2_out, type3_out, type4_out) \
+ IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 4, 4, (type1_in, type2_in, type3_in, type4_in), (type1_out, type2_out, type3_out, type4_out))
+
+#define IPC_SYNC_MESSAGE_ROUTED5_0(msg_class, type1_in, type2_in, type3_in, type4_in, type5_in) \
+ IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 5, 1, (type1_in, type2_in, type3_in, type4_in, type5_in), ())
+
+#define IPC_SYNC_MESSAGE_ROUTED5_1(msg_class, type1_in, type2_in, type3_in, type4_in, type5_in, type1_out) \
+ IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 5, 1, (type1_in, type2_in, type3_in, type4_in, type5_in), (type1_out))
+
+#define IPC_SYNC_MESSAGE_ROUTED5_2(msg_class, type1_in, type2_in, type3_in, type4_in, type5_in, type1_out, type2_out) \
+ IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 5, 2, (type1_in, type2_in, type3_in, type4_in, type5_in), (type1_out, type2_out))
+
+#define IPC_SYNC_MESSAGE_ROUTED5_3(msg_class, type1_in, type2_in, type3_in, type4_in, type5_in, type1_out, type2_out, type3_out) \
+ IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 5, 3, (type1_in, type2_in, type3_in, type4_in, type5_in), (type1_out, type2_out, type3_out))
+
+#define IPC_SYNC_MESSAGE_ROUTED5_4(msg_class, type1_in, type2_in, type3_in, type4_in, type5_in, type1_out, type2_out, type3_out, type4_out) \
+ IPC_MESSAGE_DECL(SYNC, ROUTED, msg_class, 5, 4, (type1_in, type2_in, type3_in, type4_in, type5_in), (type1_out, type2_out, type3_out, type4_out))
+
+// Common message macro which dispatches into one of the 6 (sync x kind)
+// routines. There is a way that these 6 cases can be lumped together,
+// but the macros get very complicated in that case.
+// Note: intended be redefined to generate other information.
+#define IPC_MESSAGE_DECL(sync, kind, msg_class, \
+ in_cnt, out_cnt, in_list, out_list) \
+ IPC_##sync##_##kind##_DECL(msg_class, in_cnt, out_cnt, in_list, out_list) \
+ IPC_MESSAGE_EXTRA(sync, kind, msg_class, in_cnt, out_cnt, in_list, out_list)
+
+#define IPC_EMPTY_CONTROL_DECL(msg_class, in_cnt, out_cnt, in_list, out_list) \
+ class __attribute__((visibility("default"))) msg_class : public IPC::Message\
+ { \
+ public: \
+ enum { ID = IPC_MESSAGE_ID() }; \
+ msg_class() : IPC::Message(MSG_ROUTING_CONTROL, ID, PRIORITY_NORMAL) {} \
+ };
+
+#define IPC_EMPTY_ROUTED_DECL(msg_class, in_cnt, out_cnt, in_list, out_list) \
+ class __attribute__((visibility("default"))) msg_class : public IPC::Message\
+ { \
+ public: \
+ enum { ID = IPC_MESSAGE_ID() }; \
+ msg_class(int32 routing_id) \
+ : IPC::Message(routing_id, ID, PRIORITY_NORMAL) {} \
+ };
+
+#define IPC_ASYNC_CONTROL_DECL(msg_class, in_cnt, out_cnt, in_list, out_list) \
+ class __attribute__((visibility("default"))) msg_class : \
+ public IPC::MessageWithTuple<IPC_TUPLE_IN_##in_cnt in_list> { \
+ public: \
+ enum { ID = IPC_MESSAGE_ID() }; \
+ msg_class(IPC_TYPE_IN_##in_cnt in_list); \
+ virtual ~msg_class(); \
+ static void Log(std::string* name, const Message* msg, std::string* l); \
+ };
+
+#define IPC_ASYNC_ROUTED_DECL(msg_class, in_cnt, out_cnt, in_list, out_list) \
+ class __attribute__((visibility("default"))) msg_class : \
+ public IPC::MessageWithTuple<IPC_TUPLE_IN_##in_cnt in_list> { \
+ public: \
+ enum { ID = IPC_MESSAGE_ID() }; \
+ msg_class(int32 routing_id IPC_COMMA_##in_cnt \
+ IPC_TYPE_IN_##in_cnt in_list); \
+ virtual ~msg_class(); \
+ static void Log(std::string* name, const Message* msg, std::string* l); \
+ };
+
+#define IPC_SYNC_CONTROL_DECL(msg_class, in_cnt, out_cnt, in_list, out_list) \
+ class __attribute__((visibility("default"))) msg_class : \
+ public IPC::MessageWithReply<IPC_TUPLE_IN_##in_cnt in_list, \
+ IPC_TUPLE_OUT_##out_cnt out_list> { \
+ public: \
+ enum { ID = IPC_MESSAGE_ID() }; \
+ msg_class(IPC_TYPE_IN_##in_cnt in_list \
+ IPC_COMMA_AND_##in_cnt(IPC_COMMA_##out_cnt) \
+ IPC_TYPE_OUT_##out_cnt out_list); \
+ virtual ~msg_class(); \
+ static void Log(std::string* name, const Message* msg, std::string* l); \
+ };
+
+#define IPC_SYNC_ROUTED_DECL(msg_class, in_cnt, out_cnt, in_list, out_list) \
+ class __attribute__((visibility("default"))) msg_class : \
+ public IPC::MessageWithReply<IPC_TUPLE_IN_##in_cnt in_list, \
+ IPC_TUPLE_OUT_##out_cnt out_list> { \
+ public: \
+ enum { ID = IPC_MESSAGE_ID() }; \
+ msg_class(int32 routing_id \
+ IPC_COMMA_OR_##in_cnt(IPC_COMMA_##out_cnt) \
+ IPC_TYPE_IN_##in_cnt in_list \
+ IPC_COMMA_AND_##in_cnt(IPC_COMMA_##out_cnt) \
+ IPC_TYPE_OUT_##out_cnt out_list); \
+ virtual ~msg_class(); \
+ static void Log(std::string* name, const Message* msg, std::string* l); \
+ };
+
+#if defined(IPC_MESSAGE_IMPL)
+
+// "Implementation" inclusion produces constructors, destructors, and
+// logging functions, except for the no-arg special cases, where the
+// implementation occurs in the declaration, and there is no special
+// logging function.
+#define IPC_MESSAGE_EXTRA(sync, kind, msg_class, \
+ in_cnt, out_cnt, in_list, out_list) \
+ IPC_##sync##_##kind##_IMPL(msg_class, in_cnt, out_cnt, in_list, out_list) \
+ IPC_##sync##_MESSAGE_LOG(msg_class)
+
+#define IPC_EMPTY_CONTROL_IMPL(msg_class, in_cnt, out_cnt, in_list, out_list)
+#define IPC_EMPTY_ROUTED_IMPL(msg_class, in_cnt, out_cnt, in_list, out_list)
+
+#define IPC_ASYNC_CONTROL_IMPL(msg_class, in_cnt, out_cnt, in_list, out_list) \
+ msg_class::msg_class(IPC_TYPE_IN_##in_cnt in_list) : \
+ IPC::MessageWithTuple<IPC_TUPLE_IN_##in_cnt in_list> \
+ (MSG_ROUTING_CONTROL, ID, IPC_NAME_IN_##in_cnt in_list) \
+ {} \
+ msg_class::~msg_class() {}
+
+#define IPC_ASYNC_ROUTED_IMPL(msg_class, in_cnt, out_cnt, in_list, out_list) \
+ msg_class::msg_class(int32 routing_id IPC_COMMA_##in_cnt \
+ IPC_TYPE_IN_##in_cnt in_list) : \
+ IPC::MessageWithTuple<IPC_TUPLE_IN_##in_cnt in_list> \
+ (routing_id, ID, IPC_NAME_IN_##in_cnt in_list) \
+ {} \
+ msg_class::~msg_class() {}
+
+#define IPC_SYNC_CONTROL_IMPL(msg_class, in_cnt, out_cnt, in_list, out_list) \
+ msg_class::msg_class(IPC_TYPE_IN_##in_cnt in_list \
+ IPC_COMMA_AND_##in_cnt(IPC_COMMA_##out_cnt) \
+ IPC_TYPE_OUT_##out_cnt out_list) : \
+ IPC::MessageWithReply<IPC_TUPLE_IN_##in_cnt in_list, \
+ IPC_TUPLE_OUT_##out_cnt out_list> \
+ (MSG_ROUTING_CONTROL, ID, \
+ IPC_NAME_IN_##in_cnt in_list, \
+ IPC_NAME_OUT_##out_cnt out_list) \
+ { \
+ } \
+ msg_class::~msg_class() {}
+
+#define IPC_SYNC_ROUTED_IMPL(msg_class, in_cnt, out_cnt, in_list, out_list) \
+ msg_class::msg_class(int32 routing_id \
+ IPC_COMMA_OR_##in_cnt(IPC_COMMA_##out_cnt) \
+ IPC_TYPE_IN_##in_cnt in_list \
+ IPC_COMMA_AND_##in_cnt(IPC_COMMA_##out_cnt) \
+ IPC_TYPE_OUT_##out_cnt out_list) : \
+ IPC::MessageWithReply<IPC_TUPLE_IN_##in_cnt in_list, \
+ IPC_TUPLE_OUT_##out_cnt out_list> \
+ (routing_id, ID, \
+ IPC_NAME_IN_##in_cnt in_list, \
+ IPC_NAME_OUT_##out_cnt out_list) \
+ {} \
+ msg_class::~msg_class() {}
+
+#define IPC_EMPTY_MESSAGE_LOG(msg_class)
+
+#define IPC_ASYNC_MESSAGE_LOG(msg_class) \
+ void msg_class::Log(std::string* name, \
+ const Message* msg, \
+ std::string* l) { \
+ if (name) \
+ { \
+ *name = #msg_class; \
+ } \
+ if (!msg || !l) \
+ { \
+ return; \
+ } \
+ Param p; \
+ if (Read(msg, &p)) \
+ { \
+ IPC::LogParam(p, l); \
+ } \
+ }
+
+#define IPC_SYNC_MESSAGE_LOG(msg_class) \
+ void msg_class::Log(std::string* name, \
+ const Message* msg, \
+ std::string* l) { \
+ if (name) \
+ { \
+ *name = #msg_class; \
+ } \
+ if (!msg || !l) \
+ { \
+ return; \
+ } \
+ if (msg->is_sync()) { \
+ TupleTypes<SendParam>::ValueTuple p; \
+ if (ReadSendParam(msg, &p)) \
+ { \
+ IPC::LogParam(p, l); \
+ } \
+ AddOutputParamsToLog(msg, l); \
+ } else { \
+ TupleTypes<ReplyParam>::ValueTuple p; \
+ if (ReadReplyParam(msg, &p)) \
+ { \
+ IPC::LogParam(p, l); \
+ } \
+ } \
+ }
+
+#elif defined(IPC_MESSAGE_MACROS_LOG_ENABLED)
+
+#ifndef IPC_LOG_TABLE_CREATED
+#define IPC_LOG_TABLE_CREATED
+
+#include "base/hash_tables.h"
+
+typedef void (*LogFunction)(std::string* name,
+ const IPC::Message* msg,
+ std::string* params);
+
+typedef base::hash_map<uint32, LogFunction > LogFunctionMap;
+LogFunctionMap g_log_function_mapping;
+
+#endif // IPC_LOG_TABLE_CREATED
+
+// "Log table" inclusion produces extra logging registration code.
+#define IPC_MESSAGE_EXTRA(sync, kind, msg_class, \
+ in_cnt, out_cnt, in_list, out_list) \
+ class __attribute__((visibility("default"))) LoggerRegisterHelper##msg_class { \
+ public: \
+ LoggerRegisterHelper##msg_class() { \
+ g_log_function_mapping[msg_class::ID] = msg_class::Log; \
+ } \
+ }; \
+ LoggerRegisterHelper##msg_class g_LoggerRegisterHelper##msg_class;
+
+#else
+
+// Normal inclusion produces nothing extra.
+#define IPC_MESSAGE_EXTRA(sync, kind, msg_class, \
+ in_cnt, out_cnt, in_list, out_list)
+
+#endif // defined(IPC_MESSAGE_IMPL)
+
+// Handle variable sized argument lists. These are usually invoked by token
+// pasting against the argument counts.
+#define IPC_TYPE_IN_0()
+#define IPC_TYPE_IN_1(t1) const t1& arg1
+#define IPC_TYPE_IN_2(t1, t2) const t1& arg1, const t2& arg2
+#define IPC_TYPE_IN_3(t1, t2, t3) const t1& arg1, const t2& arg2, const t3& arg3
+#define IPC_TYPE_IN_4(t1, t2, t3, t4) const t1& arg1, const t2& arg2, const t3& arg3, const t4& arg4
+#define IPC_TYPE_IN_5(t1, t2, t3, t4, t5) const t1& arg1, const t2& arg2, const t3& arg3, const t4& arg4, const t5& arg5
+#define IPC_TYPE_IN_6(t1, t2, t3, t4, t5, t6) const t1& arg1, const t2& arg2, const t3& arg3, const t4& arg4, const t5& arg5, const t6& arg6
+
+#define IPC_TYPE_OUT_0()
+#define IPC_TYPE_OUT_1(t1) t1* arg7
+#define IPC_TYPE_OUT_2(t1, t2) t1* arg7, t2* arg8
+#define IPC_TYPE_OUT_3(t1, t2, t3) t1* arg7, t2* arg8, t3* arg9
+#define IPC_TYPE_OUT_4(t1, t2, t3, t4) t1* arg7, t2* arg8, t3* arg9, t4* arg10
+
+#define IPC_TUPLE_IN_0() Tuple0
+#define IPC_TUPLE_IN_1(t1) Tuple1<t1>
+#define IPC_TUPLE_IN_2(t1, t2) Tuple2<t1, t2>
+#define IPC_TUPLE_IN_3(t1, t2, t3) Tuple3<t1, t2, t3>
+#define IPC_TUPLE_IN_4(t1, t2, t3, t4) Tuple4<t1, t2, t3, t4>
+#define IPC_TUPLE_IN_5(t1, t2, t3, t4, t5) Tuple5<t1, t2, t3, t4, t5>
+#define IPC_TUPLE_IN_6(t1, t2, t3, t4, t5, t6) Tuple6<t1, t2, t3, t4, t5, t6>
+
+#define IPC_TUPLE_OUT_0() Tuple0
+#define IPC_TUPLE_OUT_1(t1) Tuple1<t1&>
+#define IPC_TUPLE_OUT_2(t1, t2) Tuple2<t1&, t2&>
+#define IPC_TUPLE_OUT_3(t1, t2, t3) Tuple3<t1&, t2&, t3&>
+#define IPC_TUPLE_OUT_4(t1, t2, t3, t4) Tuple4<t1&, t2&, t3&, t4&>
+
+#define IPC_NAME_IN_0() MakeTuple()
+#define IPC_NAME_IN_1(t1) MakeRefTuple(arg1)
+#define IPC_NAME_IN_2(t1, t2) MakeRefTuple(arg1, arg2)
+#define IPC_NAME_IN_3(t1, t2, t3) MakeRefTuple(arg1, arg2, arg3)
+#define IPC_NAME_IN_4(t1, t2, t3, t4) MakeRefTuple(arg1, arg2, arg3, arg4)
+#define IPC_NAME_IN_5(t1, t2, t3, t4, t5) MakeRefTuple(arg1, arg2, arg3, arg4, arg5)
+#define IPC_NAME_IN_6(t1, t2, t3, t4, t5, t6) MakeRefTuple(arg1, arg2, arg3, arg4, arg5, arg6)
+
+#define IPC_NAME_OUT_0() MakeTuple()
+#define IPC_NAME_OUT_1(t1) MakeRefTuple(*arg7)
+#define IPC_NAME_OUT_2(t1, t2) MakeRefTuple(*arg7, *arg8)
+#define IPC_NAME_OUT_3(t1, t2, t3) MakeRefTuple(*arg7, *arg8, *arg9)
+#define IPC_NAME_OUT_4(t1, t2, t3, t4) MakeRefTuple(*arg7, *arg8, *arg9, *arg10)
+
+// There are places where the syntax requires a comma if there are input args,
+// if there are input args and output args, or if there are input args or
+// output args. These macros allow generation of the comma as needed; invoke
+// by token pasting against the argument counts.
+#define IPC_COMMA_0
+#define IPC_COMMA_1 ,
+#define IPC_COMMA_2 ,
+#define IPC_COMMA_3 ,
+#define IPC_COMMA_4 ,
+#define IPC_COMMA_5 ,
+#define IPC_COMMA_6 ,
+
+#define IPC_COMMA_AND_0(x)
+#define IPC_COMMA_AND_1(x) x
+#define IPC_COMMA_AND_2(x) x
+#define IPC_COMMA_AND_3(x) x
+#define IPC_COMMA_AND_4(x) x
+#define IPC_COMMA_AND_5(x) x
+#define IPC_COMMA_AND_6(x) x
+
+#define IPC_COMMA_OR_0(x) x
+#define IPC_COMMA_OR_1(x) ,
+#define IPC_COMMA_OR_2(x) ,
+#define IPC_COMMA_OR_3(x) ,
+#define IPC_COMMA_OR_4(x) ,
+#define IPC_COMMA_OR_5(x) ,
+#define IPC_COMMA_OR_6(x) ,
+
+// Message IDs
+// Note: we currently use __LINE__ to give unique IDs to messages within
+// a file. They're globally unique since each file defines its own
+// IPC_MESSAGE_START. Ideally, we wouldn't use line numbers (a possibility
+// is to instead use the __COUNTER__ macro, but it needs gcc 4.3 and xcode
+// doesn't use it yet).
+#define IPC_MESSAGE_ID() ((IPC_MESSAGE_START << 16) + __LINE__)
+#define IPC_MESSAGE_ID_CLASS(id) ((id) >> 16)
+#define IPC_MESSAGE_ID_LINE(id) ((id) & 0xffff)
+
+// Message crackers and handlers.
+// Prefer to use the IPC_BEGIN_MESSAGE_MAP_EX to the older macros since they
+// allow you to detect when a message could not be de-serialized. Usage:
+//
+// bool MyClass::OnMessageReceived(const IPC::Message& msg) {
+// bool handled = true;
+// bool msg_is_good = false;
+// IPC_BEGIN_MESSAGE_MAP_EX(MyClass, msg, msg_is_good)
+// IPC_MESSAGE_HANDLER(MsgClassOne, OnMsgClassOne)
+// ...more handlers here ...
+// IPC_MESSAGE_HANDLER(MsgClassTen, OnMsgClassTen)
+// IPC_MESSAGE_UNHANDLED(handled = false)
+// IPC_END_MESSAGE_MAP_EX()
+// if (!msg_is_good) {
+// // Signal error here or terminate offending process.
+// }
+// return handled;
+// }
+
+
+#define IPC_BEGIN_MESSAGE_MAP_EX(class_name, msg, msg_is_ok) \
+ { \
+ typedef class_name _IpcMessageHandlerClass; \
+ const IPC::Message& ipc_message__ = msg; \
+ bool& msg_is_ok__ = msg_is_ok; \
+ switch (ipc_message__.type()) { \
+
+#define IPC_BEGIN_MESSAGE_MAP(class_name, msg) \
+ { \
+ typedef class_name _IpcMessageHandlerClass; \
+ const IPC::Message& ipc_message__ = msg; \
+ bool msg_is_ok__ = true; \
+ switch (ipc_message__.type()) { \
+
+#define IPC_MESSAGE_FORWARD(msg_class, obj, member_func) \
+ case msg_class::ID: \
+ msg_is_ok__ = msg_class::Dispatch(&ipc_message__, obj, this, &member_func); \
+ break;
+
+#define IPC_MESSAGE_FORWARD_EX(msg_class, obj, sender, member_func) \
+ case msg_class::ID: \
+ msg_is_ok__ = msg_class::Dispatch(&ipc_message__, obj, sender, &member_func); \
+ break;
+
+#define IPC_MESSAGE_HANDLER(msg_class, member_func, sender) \
+ IPC_MESSAGE_FORWARD_EX(msg_class, this, sender, _IpcMessageHandlerClass::member_func)
+
+#define IPC_MESSAGE_HANDLER_EX(msg_class, sender, member_func) \
+ IPC_MESSAGE_FORWARD_EX(msg_class, this, sender, _IpcMessageHandlerClass::member_func)
+
+#define IPC_MESSAGE_FORWARD_DELAY_REPLY(msg_class, obj, member_func) \
+ case msg_class::ID: \
+ msg_is_ok__ = msg_class::DispatchDelayReply(&ipc_message__, obj, &member_func); \
+ break;
+
+#define IPC_MESSAGE_HANDLER_DELAY_REPLY(msg_class, member_func) \
+ IPC_MESSAGE_FORWARD_DELAY_REPLY(msg_class, this, \
+ _IpcMessageHandlerClass::member_func)
+
+#define IPC_MESSAGE_HANDLER_GENERIC(msg_class, code) \
+ case msg_class::ID: \
+ code; \
+ break;
+
+#define IPC_REPLY_HANDLER(func) \
+ case IPC_REPLY_ID: \
+ func(ipc_message__); \
+ break;
+
+
+#define IPC_MESSAGE_UNHANDLED(code) \
+ default: \
+ code; \
+ break;
+
+#define IPC_MESSAGE_UNHANDLED_ERROR() \
+ IPC_MESSAGE_UNHANDLED(NOTREACHED() << \
+ "Invalid message with type = " << \
+ ipc_message__.type())
+
+#define IPC_END_MESSAGE_MAP() \
+ } \
+}
+
+#define IPC_END_MESSAGE_MAP_EX() \
+ } \
+}
+
+// This corresponds to an enum value from IPCMessageStart.
+#define IPC_MESSAGE_CLASS(message) \
+ IPC_MESSAGE_ID_CLASS(message.type())
+
+#endif // IPC_IPC_MESSAGE_MACROS_H_
+
+// Clean up IPC_MESSAGE_START in this unguarded section so that the
+// XXX_messages.h files need not do so themselves. This makes the
+// XXX_messages.h files easier to write.
+#undef IPC_MESSAGE_START
diff --git a/ipc/ipc_message_null_macros.h b/ipc/ipc_message_null_macros.h
new file mode 100644
index 000000000000..7cd02f55569d
--- /dev/null
+++ b/ipc/ipc_message_null_macros.h
@@ -0,0 +1,29 @@
+// 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.
+
+// No include guard, may be included multiple times.
+
+// NULL out all the macros that need NULLing, so that multiple includes of
+// the XXXX_messages_internal.h files will not generate noise.
+#undef IPC_STRUCT_BEGIN
+#undef IPC_STRUCT_MEMBER
+#undef IPC_STRUCT_END
+#undef IPC_STRUCT_TRAITS_BEGIN
+#undef IPC_STRUCT_TRAITS_MEMBER
+#undef IPC_STRUCT_TRAITS_PARENT
+#undef IPC_STRUCT_TRAITS_END
+#undef IPC_ENUM_TRAITS
+#undef IPC_MESSAGE_DECL
+
+#define IPC_STRUCT_BEGIN(struct_name)
+#define IPC_STRUCT_MEMBER(type, name)
+#define IPC_STRUCT_END()
+#define IPC_STRUCT_TRAITS_BEGIN(struct_name)
+#define IPC_STRUCT_TRAITS_MEMBER(name)
+#define IPC_STRUCT_TRAITS_PARENT(type)
+#define IPC_STRUCT_TRAITS_END()
+#define IPC_ENUM_TRAITS(enum_name)
+#define IPC_MESSAGE_DECL(sync, kind, msg_class, \
+ in_cnt, out_cnt, in_list, out_list)
+
diff --git a/ipc/ipc_message_utils.cc b/ipc/ipc_message_utils.cc
new file mode 100644
index 000000000000..2e3f04253fb8
--- /dev/null
+++ b/ipc/ipc_message_utils.cc
@@ -0,0 +1,485 @@
+// 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 "ipc/ipc_message_utils.h"
+
+//#include "base/file_path.h"
+//#include "base/json/json_writer.h"
+//#include "base/memory/scoped_ptr.h"
+//#include "base/nullable_string16.h"
+#include "base/string_number_conversions.h"
+#include "base/time.h"
+//#include "base/utf_string_conversions.h"
+#include "base/values.h"
+#if defined(OS_POSIX)
+//#include "ipc/file_descriptor_set_posix.h"
+#endif
+//#include "ipc/ipc_channel_handle.h"
+
+namespace IPC {
+
+const int kMaxRecursionDepth = 100;
+
+// Value serialization
+
+/*
+static bool ReadValue(const Message* m, void** iter, Value** value,
+ int recursion);
+
+static void WriteValue(Message* m, const Value* value, int recursion) {
+ if (recursion > kMaxRecursionDepth) {
+ LOG(WARNING) << "Max recursion depth hit in WriteValue.";
+ return;
+ }
+
+ m->WriteInt(value->GetType());
+
+ switch (value->GetType()) {
+ case Value::TYPE_NULL:
+ break;
+ case Value::TYPE_BOOLEAN: {
+ bool val;
+ value->GetAsBoolean(&val);
+ WriteParam(m, val);
+ break;
+ }
+ case Value::TYPE_INTEGER: {
+ int val;
+ value->GetAsInteger(&val);
+ WriteParam(m, val);
+ break;
+ }
+ case Value::TYPE_DOUBLE: {
+ double val;
+ value->GetAsDouble(&val);
+ WriteParam(m, val);
+ break;
+ }
+ case Value::TYPE_STRING: {
+ std::string val;
+ value->GetAsString(&val);
+ WriteParam(m, val);
+ break;
+ }
+ case Value::TYPE_BINARY: {
+ const base::BinaryValue* binary =
+ static_cast<const base::BinaryValue*>(value);
+ m->WriteData(binary->GetBuffer(), static_cast<int>(binary->GetSize()));
+ break;
+ }
+ case Value::TYPE_DICTIONARY: {
+ const DictionaryValue* dict = static_cast<const DictionaryValue*>(value);
+
+ WriteParam(m, static_cast<int>(dict->size()));
+
+ for (DictionaryValue::key_iterator it = dict->begin_keys();
+ it != dict->end_keys(); ++it) {
+ Value* subval;
+ if (dict->GetWithoutPathExpansion(*it, &subval)) {
+ WriteParam(m, *it);
+ WriteValue(m, subval, recursion + 1);
+ } else {
+ NOTREACHED() << "DictionaryValue iterators are filthy liars.";
+ }
+ }
+ break;
+ }
+ case Value::TYPE_LIST: {
+ const ListValue* list = static_cast<const ListValue*>(value);
+ WriteParam(m, static_cast<int>(list->GetSize()));
+ for (size_t i = 0; i < list->GetSize(); ++i) {
+ Value* subval;
+ if (list->Get(i, &subval)) {
+ WriteValue(m, subval, recursion + 1);
+ } else {
+ NOTREACHED() << "ListValue::GetSize is a filthy liar.";
+ }
+ }
+ break;
+ }
+ }
+}
+
+// Helper for ReadValue that reads a DictionaryValue into a pre-allocated
+// object.
+static bool ReadDictionaryValue(const Message* m, void** iter,
+ DictionaryValue* value, int recursion) {
+ int size;
+ if (!ReadParam(m, iter, &size))
+ return false;
+
+ for (int i = 0; i < size; ++i) {
+ std::string key;
+ Value* subval;
+ if (!ReadParam(m, iter, &key) ||
+ !ReadValue(m, iter, &subval, recursion + 1))
+ return false;
+ value->Set(key, subval);
+ }
+
+ return true;
+}
+
+// Helper for ReadValue that reads a ReadListValue into a pre-allocated
+// object.
+static bool ReadListValue(const Message* m, void** iter,
+ ListValue* value, int recursion) {
+ int size;
+ if (!ReadParam(m, iter, &size))
+ return false;
+
+ for (int i = 0; i < size; ++i) {
+ Value* subval;
+ if (!ReadValue(m, iter, &subval, recursion + 1))
+ return false;
+ value->Set(i, subval);
+ }
+
+ return true;
+}
+
+static bool ReadValue(const Message* m, void** iter, Value** value,
+ int recursion) {
+ if (recursion > kMaxRecursionDepth) {
+ LOG(WARNING) << "Max recursion depth hit in ReadValue.";
+ return false;
+ }
+
+ int type;
+ if (!ReadParam(m, iter, &type))
+ return false;
+
+ switch (type) {
+ case Value::TYPE_NULL:
+ *value = Value::CreateNullValue();
+ break;
+ case Value::TYPE_BOOLEAN: {
+ bool val;
+ if (!ReadParam(m, iter, &val))
+ return false;
+ *value = Value::CreateBooleanValue(val);
+ break;
+ }
+ case Value::TYPE_INTEGER: {
+ int val;
+ if (!ReadParam(m, iter, &val))
+ return false;
+ *value = Value::CreateIntegerValue(val);
+ break;
+ }
+ case Value::TYPE_DOUBLE: {
+ double val;
+ if (!ReadParam(m, iter, &val))
+ return false;
+ *value = Value::CreateDoubleValue(val);
+ break;
+ }
+ case Value::TYPE_STRING: {
+ std::string val;
+ if (!ReadParam(m, iter, &val))
+ return false;
+ *value = Value::CreateStringValue(val);
+ break;
+ }
+ case Value::TYPE_BINARY: {
+ const char* data;
+ int length;
+ if (!m->ReadData(iter, &data, &length))
+ return false;
+ *value = base::BinaryValue::CreateWithCopiedBuffer(data, length);
+ break;
+ }
+ case Value::TYPE_DICTIONARY: {
+ scoped_ptr<DictionaryValue> val(new DictionaryValue());
+ if (!ReadDictionaryValue(m, iter, val.get(), recursion))
+ return false;
+ *value = val.release();
+ break;
+ }
+ case Value::TYPE_LIST: {
+ scoped_ptr<ListValue> val(new ListValue());
+ if (!ReadListValue(m, iter, val.get(), recursion))
+ return false;
+ *value = val.release();
+ break;
+ }
+ default:
+ return false;
+ }
+
+ return true;
+}
+*/
+
+void ParamTraits<int>::Log(const param_type& p, std::string* l) {
+ //l->append(base::IntToString(p));
+}
+
+void ParamTraits<unsigned int>::Log(const param_type& p, std::string* l) {
+ //l->append(base::UintToString(p));
+}
+
+void ParamTraits<long>::Log(const param_type& p, std::string* l) {
+ //l->append(base::Int64ToString(static_cast<int64>(p)));
+}
+
+void ParamTraits<unsigned long>::Log(const param_type& p, std::string* l) {
+ //l->append(base::Uint64ToString(static_cast<uint64>(p)));
+}
+
+void ParamTraits<long long>::Log(const param_type& p, std::string* l) {
+ //l->append(base::Int64ToString(static_cast<int64>(p)));
+}
+
+void ParamTraits<unsigned long long>::Log(const param_type& p, std::string* l) {
+ //l->append(base::Uint64ToString(p));
+}
+
+
+void ParamTraits<unsigned short>::Write(Message* m, const param_type& p) {
+ m->WriteBytes(&p, sizeof(param_type));
+}
+
+bool ParamTraits<unsigned short>::Read(const Message* m, void** iter,
+ param_type* r) {
+ const char* data;
+ if (!m->ReadBytes(iter, &data, sizeof(param_type)))
+ return false;
+ memcpy(r, data, sizeof(param_type));
+ return true;
+}
+
+/*
+void ParamTraits<unsigned short>::Log(const param_type& p, std::string* l) {
+ l->append(base::UintToString(p));
+}
+
+
+void ParamTraits<base::Time>::Write(Message* m, const param_type& p) {
+ ParamTraits<int64>::Write(m, p.ToInternalValue());
+}
+
+bool ParamTraits<base::Time>::Read(const Message* m, void** iter,
+ param_type* r) {
+ int64 value;
+ if (!ParamTraits<int64>::Read(m, iter, &value))
+ return false;
+ *r = base::Time::FromInternalValue(value);
+ return true;
+}
+
+void ParamTraits<base::Time>::Log(const param_type& p, std::string* l) {
+ ParamTraits<int64>::Log(p.ToInternalValue(), l);
+}
+
+void ParamTraits<base::TimeDelta> ::Write(Message* m, const param_type& p) {
+ ParamTraits<int64> ::Write(m, p.InMicroseconds());
+}
+
+bool ParamTraits<base::TimeDelta> ::Read(const Message* m,
+ void** iter,
+ param_type* r) {
+ int64 value;
+ bool ret = ParamTraits<int64> ::Read(m, iter, &value);
+ if (ret)
+ *r = base::TimeDelta::FromMicroseconds(value);
+
+ return ret;
+}
+
+void ParamTraits<base::TimeDelta> ::Log(const param_type& p, std::string* l) {
+ ParamTraits<int64> ::Log(p.InMicroseconds(), l);
+}
+
+void ParamTraits<DictionaryValue>::Write(Message* m, const param_type& p) {
+ WriteValue(m, &p, 0);
+}
+
+bool ParamTraits<DictionaryValue>::Read(
+ const Message* m, void** iter, param_type* r) {
+ int type;
+ if (!ReadParam(m, iter, &type) || type != Value::TYPE_DICTIONARY)
+ return false;
+
+ return ReadDictionaryValue(m, iter, r, 0);
+}
+
+void ParamTraits<DictionaryValue>::Log(const param_type& p, std::string* l) {
+ std::string json;
+ base::JSONWriter::Write(&p, false, &json);
+ l->append(json);
+}
+
+void ParamTraits<ListValue>::Write(Message* m, const param_type& p) {
+ WriteValue(m, &p, 0);
+}
+
+bool ParamTraits<ListValue>::Read(
+ const Message* m, void** iter, param_type* r) {
+ int type;
+ if (!ReadParam(m, iter, &type) || type != Value::TYPE_LIST)
+ return false;
+
+ return ReadListValue(m, iter, r, 0);
+}
+
+void ParamTraits<ListValue>::Log(const param_type& p, std::string* l) {
+ std::string json;
+ base::JSONWriter::Write(&p, false, &json);
+ l->append(json);
+}
+
+void ParamTraits<std::wstring>::Log(const param_type& p, std::string* l) {
+ l->append(WideToUTF8(p));
+}
+
+void ParamTraits<NullableString16>::Write(Message* m, const param_type& p) {
+ WriteParam(m, p.string());
+ WriteParam(m, p.is_null());
+}
+
+bool ParamTraits<NullableString16>::Read(const Message* m, void** iter,
+ param_type* r) {
+ string16 string;
+ if (!ReadParam(m, iter, &string))
+ return false;
+ bool is_null;
+ if (!ReadParam(m, iter, &is_null))
+ return false;
+ *r = NullableString16(string, is_null);
+ return true;
+}
+
+void ParamTraits<NullableString16>::Log(const param_type& p, std::string* l) {
+ l->append("(");
+ LogParam(p.string(), l);
+ l->append(", ");
+ LogParam(p.is_null(), l);
+ l->append(")");
+}
+
+#if !defined(WCHAR_T_IS_UTF16)
+void ParamTraits<string16>::Log(const param_type& p, std::string* l) {
+ l->append(UTF16ToUTF8(p));
+}
+#endif
+
+*/
+
+/*
+void ParamTraits<FilePath>::Write(Message* m, const param_type& p) {
+ ParamTraits<FilePath::StringType>::Write(m, p.value());
+}
+
+bool ParamTraits<FilePath>::Read(const Message* m, void** iter, param_type* r) {
+ FilePath::StringType value;
+ if (!ParamTraits<FilePath::StringType>::Read(m, iter, &value))
+ return false;
+ *r = FilePath(value);
+ return true;
+}
+
+void ParamTraits<FilePath>::Log(const param_type& p, std::string* l) {
+ ParamTraits<FilePath::StringType>::Log(p.value(), l);
+}
+
+#if defined(OS_POSIX)
+void ParamTraits<base::FileDescriptor>::Write(Message* m, const param_type& p) {
+ const bool valid = p.fd >= 0;
+ WriteParam(m, valid);
+
+ if (valid) {
+ if (!m->WriteFileDescriptor(p))
+ NOTREACHED();
+ }
+}
+
+bool ParamTraits<base::FileDescriptor>::Read(const Message* m, void** iter,
+ param_type* r) {
+ bool valid;
+ if (!ReadParam(m, iter, &valid))
+ return false;
+
+ if (!valid) {
+ r->fd = -1;
+ r->auto_close = false;
+ return true;
+ }
+
+ return m->ReadFileDescriptor(iter, r);
+}
+
+void ParamTraits<base::FileDescriptor>::Log(const param_type& p,
+ std::string* l) {
+ if (p.auto_close) {
+ l->append(StringPrintf("FD(%d auto-close)", p.fd));
+ } else {
+ l->append(StringPrintf("FD(%d)", p.fd));
+ }
+}
+#endif // defined(OS_POSIX)
+
+void ParamTraits<IPC::ChannelHandle>::Write(Message* m, const param_type& p) {
+ WriteParam(m, p.name);
+#if defined(OS_POSIX)
+ WriteParam(m, p.socket);
+#endif
+}
+
+bool ParamTraits<IPC::ChannelHandle>::Read(const Message* m, void** iter,
+ param_type* r) {
+ return ReadParam(m, iter, &r->name)
+#if defined(OS_POSIX)
+ && ReadParam(m, iter, &r->socket)
+#endif
+ ;
+}
+
+void ParamTraits<IPC::ChannelHandle>::Log(const param_type& p,
+ std::string* l) {
+ l->append(StringPrintf("ChannelHandle(%s", p.name.c_str()));
+#if defined(OS_POSIX)
+ ParamTraits<base::FileDescriptor>::Log(p.socket, l);
+#endif
+ l->append(")");
+}
+
+LogData::LogData()
+ : routing_id(0),
+ type(0),
+ sent(0),
+ receive(0),
+ dispatch(0) {
+}
+
+LogData::~LogData() {
+}
+
+void ParamTraits<LogData>::Write(Message* m, const param_type& p) {
+ WriteParam(m, p.channel);
+ WriteParam(m, p.routing_id);
+ WriteParam(m, static_cast<int>(p.type));
+ WriteParam(m, p.flags);
+ WriteParam(m, p.sent);
+ WriteParam(m, p.receive);
+ WriteParam(m, p.dispatch);
+ WriteParam(m, p.params);
+}
+
+bool ParamTraits<LogData>::Read(const Message* m, void** iter, param_type* r) {
+ int type = -1;
+ bool result =
+ ReadParam(m, iter, &r->channel) &&
+ ReadParam(m, iter, &r->routing_id) &&
+ ReadParam(m, iter, &type) &&
+ ReadParam(m, iter, &r->flags) &&
+ ReadParam(m, iter, &r->sent) &&
+ ReadParam(m, iter, &r->receive) &&
+ ReadParam(m, iter, &r->dispatch) &&
+ ReadParam(m, iter, &r->params);
+ r->type = static_cast<uint16>(type);
+ return result;
+}
+*/
+} // namespace IPC
diff --git a/ipc/ipc_message_utils.h b/ipc/ipc_message_utils.h
new file mode 100755
index 000000000000..8c2014f35056
--- /dev/null
+++ b/ipc/ipc_message_utils.h
@@ -0,0 +1,1238 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IPC_IPC_MESSAGE_UTILS_H_
+#define IPC_IPC_MESSAGE_UTILS_H_
+#pragma once
+
+#include <algorithm>
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/compiler_specific.h"
+//#include "base/format_macros.h"
+//#include "base/string16.h"
+//#include "base/stringprintf.h"
+//#include "base/string_util.h"
+#include "base/tuple.h"
+#include "ipc/ipc_param_traits.h"
+#include "ipc/ipc_sync_message.h"
+
+#if defined(COMPILER_GCC)
+// GCC "helpfully" tries to inline template methods in release mode. Except we
+// want the majority of the template junk being expanded once in the
+// implementation file (and only provide the definitions in
+// ipc_message_utils_impl.h in those files) and exported, instead of expanded
+// at every call site. Special note: GCC happily accepts the attribute before
+// the method declaration, but only acts on it if it is after.
+#if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100) >= 40500
+// Starting in gcc 4.5, the noinline no longer implies the concept covered by
+// the introduced noclone attribute, which will create specialized versions of
+// functions/methods when certain types are constant.
+// www.gnu.org/software/gcc/gcc-4.5/changes.html
+#define IPC_MSG_NOINLINE __attribute__((noinline, noclone));
+#else
+#define IPC_MSG_NOINLINE __attribute__((noinline));
+#endif
+#elif defined(COMPILER_MSVC)
+// MSVC++ doesn't do this.
+#define IPC_MSG_NOINLINE
+#else
+#error "Please add the noinline property for your new compiler here."
+#endif
+
+// Used by IPC_BEGIN_MESSAGES so that each message class starts from a unique
+// base. Messages have unique IDs across channels in order for the IPC logging
+// code to figure out the message class from its ID.
+enum IPCMessageStart {
+ AutomationMsgStart = 0,
+ PushServiceMsgStart,
+ CmcStrRegistryManagerStart,
+ LastIPCMsgStart // Must come last.
+};
+
+class FilePath;
+class NullableString16;
+
+namespace base {
+class DictionaryValue;
+class ListValue;
+class Time;
+class TimeDelta;
+struct FileDescriptor;
+}
+
+namespace IPC {
+
+struct ChannelHandle;
+
+//-----------------------------------------------------------------------------
+// An iterator class for reading the fields contained within a Message.
+
+class MessageIterator {
+ public:
+ explicit MessageIterator(const Message& m) : msg_(m), iter_(NULL) {
+ }
+ int NextInt() const {
+ int val = -1;
+ if (!msg_.ReadInt(&iter_, &val))
+ NOTREACHED();
+ return val;
+ }
+/*
+ const std::string NextString() const {
+ std::string val;
+ if (!msg_.ReadString(&iter_, &val))
+ NOTREACHED();
+ return val;
+ }
+ const std::wstring NextWString() const {
+ std::wstring val;
+ if (!msg_.ReadWString(&iter_, &val))
+ NOTREACHED();
+ return val;
+ }
+*/
+ void NextData(const char** data, int* length) const {
+ if (!msg_.ReadData(&iter_, data, length)) {
+ NOTREACHED();
+ }
+ }
+ private:
+ const Message& msg_;
+ mutable void* iter_;
+};
+
+//-----------------------------------------------------------------------------
+// A dummy struct to place first just to allow leading commas for all
+// members in the macro-generated constructor initializer lists.
+struct NoParams {
+};
+
+//-----------------------------------------------------------------------------
+// ParamTraits specializations, etc.
+
+template <class P>
+static inline void WriteParam(Message* m, const P& p) {
+ typedef typename SimilarTypeTraits<P>::Type Type;
+ ParamTraits<Type>::Write(m, static_cast<const Type& >(p));
+}
+
+template <class P>
+static inline bool WARN_UNUSED_RESULT ReadParam(const Message* m, void** iter,
+ P* p) {
+ typedef typename SimilarTypeTraits<P>::Type Type;
+ return ParamTraits<Type>::Read(m, iter, reinterpret_cast<Type* >(p));
+}
+
+
+template <class P>
+static inline void LogParam(const P& p, std::string* l) {
+ typedef typename SimilarTypeTraits<P>::Type Type;
+ ParamTraits<Type>::Log(static_cast<const Type& >(p), l);
+}
+
+
+template <>
+struct ParamTraits<bool> {
+ typedef bool param_type;
+ static void Write(Message* m, const param_type& p) {
+ m->WriteBool(p);
+ }
+ static bool Read(const Message* m, void** iter, param_type* r) {
+ return m->ReadBool(iter, r);
+ }
+ static void Log(const param_type& p, std::string* l) {
+ l->append(p ? "true" : "false");
+ }
+};
+
+template <>
+struct ParamTraits<int> {
+ typedef int param_type;
+ static void Write(Message* m, const param_type& p) {
+ m->WriteInt(p);
+ }
+ static bool Read(const Message* m, void** iter, param_type* r) {
+ return m->ReadInt(iter, r);
+ }
+ IPC_EXPORT static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct ParamTraits<unsigned int> {
+ typedef unsigned int param_type;
+ static void Write(Message* m, const param_type& p) {
+ m->WriteInt(p);
+ }
+ static bool Read(const Message* m, void** iter, param_type* r) {
+ return m->ReadInt(iter, reinterpret_cast<int*>(r));
+ }
+ IPC_EXPORT static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct ParamTraits<long> {
+ typedef long param_type;
+ static void Write(Message* m, const param_type& p) {
+ m->WriteLong(p);
+ }
+ static bool Read(const Message* m, void** iter, param_type* r) {
+ return m->ReadLong(iter, r);
+ }
+ IPC_EXPORT static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct ParamTraits<unsigned long> {
+ typedef unsigned long param_type;
+ static void Write(Message* m, const param_type& p) {
+ m->WriteLong(p);
+ }
+ static bool Read(const Message* m, void** iter, param_type* r) {
+ return m->ReadLong(iter, reinterpret_cast<long*>(r));
+ }
+ IPC_EXPORT static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct ParamTraits<long long> {
+ typedef long long param_type;
+ static void Write(Message* m, const param_type& p) {
+ m->WriteInt64(static_cast<int64>(p));
+ }
+ static bool Read(const Message* m, void** iter, param_type* r) {
+ return m->ReadInt64(iter, reinterpret_cast<int64*>(r));
+ }
+ IPC_EXPORT static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct ParamTraits<unsigned long long> {
+ typedef unsigned long long param_type;
+ static void Write(Message* m, const param_type& p) {
+ m->WriteInt64(p);
+ }
+ static bool Read(const Message* m, void** iter, param_type* r) {
+ return m->ReadInt64(iter, reinterpret_cast<int64*>(r));
+ }
+ IPC_EXPORT static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct IPC_EXPORT ParamTraits<unsigned short> {
+ typedef unsigned short param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+// Note that the IPC layer doesn't sanitize NaNs and +/- INF values. Clients
+// should be sure to check the sanity of these values after receiving them over
+// IPC.
+template <>
+struct ParamTraits<float> {
+ typedef float param_type;
+ static void Write(Message* m, const param_type& p) {
+ m->WriteData(reinterpret_cast<const char*>(&p), sizeof(param_type));
+ }
+ static bool Read(const Message* m, void** iter, param_type* r) {
+ const char *data;
+ int data_size;
+ if (!m->ReadData(iter, &data, &data_size) ||
+ data_size != sizeof(param_type)) {
+ NOTREACHED();
+ return false;
+ }
+ memcpy(r, data, sizeof(param_type));
+ return true;
+ }
+
+ static void Log(const param_type& p, std::string* l) {
+ //l->append(StringPrintf("%e", p));
+ }
+
+};
+
+template <>
+struct ParamTraits<double> {
+ typedef double param_type;
+ static void Write(Message* m, const param_type& p) {
+ m->WriteData(reinterpret_cast<const char*>(&p), sizeof(param_type));
+ }
+ static bool Read(const Message* m, void** iter, param_type* r) {
+ const char *data;
+ int data_size;
+ if (!m->ReadData(iter, &data, &data_size) ||
+ data_size != sizeof(param_type)) {
+ NOTREACHED();
+ return false;
+ }
+ memcpy(r, data, sizeof(param_type));
+ return true;
+ }
+
+ static void Log(const param_type& p, std::string* l) {
+ //l->append(StringPrintf("%e", p));
+ }
+
+};
+
+/*
+template <>
+struct IPC_EXPORT ParamTraits<base::Time> {
+ typedef base::Time param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct IPC_EXPORT ParamTraits<base::TimeDelta> {
+ typedef base::TimeDelta param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+#if defined(OS_WIN)
+template <>
+struct ParamTraits<LOGFONT> {
+ typedef LOGFONT param_type;
+ static void Write(Message* m, const param_type& p) {
+ m->WriteData(reinterpret_cast<const char*>(&p), sizeof(LOGFONT));
+ }
+ static bool Read(const Message* m, void** iter, param_type* r) {
+ const char *data;
+ int data_size = 0;
+ bool result = m->ReadData(iter, &data, &data_size);
+ if (result && data_size == sizeof(LOGFONT)) {
+ memcpy(r, data, sizeof(LOGFONT));
+ } else {
+ result = false;
+ NOTREACHED();
+ }
+
+ return result;
+ }
+ static void Log(const param_type& p, std::string* l) {
+// l->append(StringPrintf("<LOGFONT>"));
+ }
+};
+
+template <>
+struct ParamTraits<MSG> {
+ typedef MSG param_type;
+ static void Write(Message* m, const param_type& p) {
+ m->WriteData(reinterpret_cast<const char*>(&p), sizeof(MSG));
+ }
+ static bool Read(const Message* m, void** iter, param_type* r) {
+ const char *data;
+ int data_size = 0;
+ bool result = m->ReadData(iter, &data, &data_size);
+ if (result && data_size == sizeof(MSG)) {
+ memcpy(r, data, sizeof(MSG));
+ } else {
+ result = false;
+ NOTREACHED();
+ }
+
+ return result;
+ }
+ static void Log(const param_type& p, std::string* l) {
+ l->append("<MSG>");
+ }
+};
+#endif // defined(OS_WIN)
+
+template <>
+struct IPC_EXPORT ParamTraits<base::DictionaryValue> {
+ typedef base::DictionaryValue param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct IPC_EXPORT ParamTraits<base::ListValue> {
+ typedef base::ListValue param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+*/
+template <>
+struct ParamTraits<std::string> {
+ typedef std::string param_type;
+ static void Write(Message* m, const param_type& p) {
+ m->WriteString(p);
+ }
+ static bool Read(const Message* m, void** iter, param_type* r) {
+ return m->ReadString(iter, r);
+ }
+ static void Log(const param_type& p, std::string* l) {
+ l->append(p);
+ }
+};
+
+/*
+template<typename CharType>
+static void LogBytes(const std::vector<CharType>& data, std::string* out) {
+#if defined(OS_WIN)
+ // Windows has a GUI for logging, which can handle arbitrary binary data.
+ for (size_t i = 0; i < data.size(); ++i)
+ out->push_back(data[i]);
+#else
+ // On POSIX, we log to stdout, which we assume can display ASCII.
+ static const size_t kMaxBytesToLog = 100;
+ for (size_t i = 0; i < std::min(data.size(), kMaxBytesToLog); ++i) {
+ if (isprint(data[i]))
+ out->push_back(data[i]);
+ else
+ {
+ // out->append(StringPrintf("[%02X]", static_cast<unsigned char>(data[i])));
+ }
+ }
+ if (data.size() > kMaxBytesToLog) {
+// out->append(
+// StringPrintf(" and %u more bytes",
+// static_cast<unsigned>(data.size() - kMaxBytesToLog)));
+ }
+#endif
+}
+*/
+
+template <>
+struct ParamTraits<std::vector<unsigned char> > {
+ typedef std::vector<unsigned char> param_type;
+ static void Write(Message* m, const param_type& p) {
+ if (p.empty()) {
+ m->WriteData(NULL, 0);
+ } else {
+ m->WriteData(reinterpret_cast<const char*>(&p.front()),
+ static_cast<int>(p.size()));
+ }
+ }
+ static bool Read(const Message* m, void** iter, param_type* r) {
+ const char *data;
+ int data_size = 0;
+ if (!m->ReadData(iter, &data, &data_size) || data_size < 0)
+ return false;
+ r->resize(data_size);
+ if (data_size)
+ memcpy(&r->front(), data, data_size);
+ return true;
+ }
+ static void Log(const param_type& p, std::string* l) {
+ // LogBytes(p, l);
+ }
+};
+
+template <>
+struct ParamTraits<std::vector<char> > {
+ typedef std::vector<char> param_type;
+ static void Write(Message* m, const param_type& p) {
+ if (p.empty()) {
+ m->WriteData(NULL, 0);
+ } else {
+ m->WriteData(&p.front(), static_cast<int>(p.size()));
+ }
+ }
+ static bool Read(const Message* m, void** iter, param_type* r) {
+ const char *data;
+ int data_size = 0;
+ if (!m->ReadData(iter, &data, &data_size) || data_size < 0)
+ return false;
+ r->resize(data_size);
+ if (data_size)
+ memcpy(&r->front(), data, data_size);
+ return true;
+ }
+ static void Log(const param_type& p, std::string* l) {
+ //LogBytes(p, l);
+ }
+};
+
+template <class P>
+struct ParamTraits<std::vector<P> > {
+ typedef std::vector<P> param_type;
+ static void Write(Message* m, const param_type& p) {
+ WriteParam(m, static_cast<int>(p.size()));
+ for (size_t i = 0; i < p.size(); i++)
+ WriteParam(m, p[i]);
+ }
+ static bool Read(const Message* m, void** iter, param_type* r) {
+ int size;
+ // ReadLength() checks for < 0 itself.
+ if (!m->ReadLength(iter, &size))
+ return false;
+ // Resizing beforehand is not safe, see BUG 1006367 for details.
+ if (INT_MAX / sizeof(P) <= static_cast<size_t>(size))
+ return false;
+ r->resize(size);
+ for (int i = 0; i < size; i++) {
+ if (!ReadParam(m, iter, &(*r)[i]))
+ return false;
+ }
+ return true;
+ }
+ static void Log(const param_type& p, std::string* l) {
+// for (size_t i = 0; i < p.size(); ++i) {
+// if (i != 0)
+// l->append(" ");
+// LogParam((p[i]), l);
+// }
+ }
+};
+
+/*
+template <class P>
+struct ParamTraits<std::set<P> > {
+ typedef std::set<P> param_type;
+ static void Write(Message* m, const param_type& p) {
+ WriteParam(m, static_cast<int>(p.size()));
+ typename param_type::const_iterator iter;
+ for (iter = p.begin(); iter != p.end(); ++iter)
+ WriteParam(m, *iter);
+ }
+ static bool Read(const Message* m, void** iter, param_type* r) {
+ int size;
+ if (!m->ReadLength(iter, &size))
+ return false;
+ for (int i = 0; i < size; ++i) {
+ P item;
+ if (!ReadParam(m, iter, &item))
+ return false;
+ r->insert(item);
+ }
+ return true;
+ }
+ static void Log(const param_type& p, std::string* l) {
+ l->append("<std::set>");
+ }
+};
+
+
+template <class K, class V>
+struct ParamTraits<std::map<K, V> > {
+ typedef std::map<K, V> param_type;
+ static void Write(Message* m, const param_type& p) {
+ WriteParam(m, static_cast<int>(p.size()));
+ typename param_type::const_iterator iter;
+ for (iter = p.begin(); iter != p.end(); ++iter) {
+ WriteParam(m, iter->first);
+ WriteParam(m, iter->second);
+ }
+ }
+ static bool Read(const Message* m, void** iter, param_type* r) {
+ int size;
+ if (!ReadParam(m, iter, &size) || size < 0)
+ return false;
+ for (int i = 0; i < size; ++i) {
+ K k;
+ if (!ReadParam(m, iter, &k))
+ return false;
+ V& value = (*r)[k];
+ if (!ReadParam(m, iter, &value))
+ return false;
+ }
+ return true;
+ }
+ static void Log(const param_type& p, std::string* l) {
+ l->append("<std::map>");
+ }
+};
+
+
+template <>
+struct ParamTraits<std::wstring> {
+ typedef std::wstring param_type;
+ static void Write(Message* m, const param_type& p) {
+ m->WriteWString(p);
+ }
+ static bool Read(const Message* m, void** iter, param_type* r) {
+ return m->ReadWString(iter, r);
+ }
+ IPC_EXPORT static void Log(const param_type& p, std::string* l);
+};
+
+template <class A, class B>
+struct ParamTraits<std::pair<A, B> > {
+ typedef std::pair<A, B> param_type;
+ static void Write(Message* m, const param_type& p) {
+ WriteParam(m, p.first);
+ WriteParam(m, p.second);
+ }
+ static bool Read(const Message* m, void** iter, param_type* r) {
+ return ReadParam(m, iter, &r->first) && ReadParam(m, iter, &r->second);
+ }
+ static void Log(const param_type& p, std::string* l) {
+ l->append("(");
+ LogParam(p.first, l);
+ l->append(", ");
+ LogParam(p.second, l);
+ l->append(")");
+ }
+};
+
+template <>
+struct IPC_EXPORT ParamTraits<NullableString16> {
+ typedef NullableString16 param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+// If WCHAR_T_IS_UTF16 is defined, then string16 is a std::wstring so we don't
+// need this trait.
+#if !defined(WCHAR_T_IS_UTF16)
+template <>
+struct ParamTraits<string16> {
+ typedef string16 param_type;
+ static void Write(Message* m, const param_type& p) {
+ m->WriteString16(p);
+ }
+ static bool Read(const Message* m, void** iter, param_type* r) {
+ return m->ReadString16(iter, r);
+ }
+ IPC_EXPORT static void Log(const param_type& p, std::string* l);
+};
+#endif
+
+// and, a few more useful types...
+#if defined(OS_WIN)
+template <>
+struct ParamTraits<HANDLE> {
+ typedef HANDLE param_type;
+ static void Write(Message* m, const param_type& p) {
+ // Note that HWNDs/HANDLE/HCURSOR/HACCEL etc are always 32 bits, even on 64
+ // bit systems.
+ m->WriteUInt32(reinterpret_cast<uint32>(p));
+ }
+ static bool Read(const Message* m, void** iter, param_type* r) {
+ DCHECK_EQ(sizeof(param_type), sizeof(uint32));
+ return m->ReadUInt32(iter, reinterpret_cast<uint32*>(r));
+ }
+ static void Log(const param_type& p, std::string* l) {
+// l->append(StringPrintf("0x%X", p));
+ }
+};
+
+template <>
+struct ParamTraits<HCURSOR> {
+ typedef HCURSOR param_type;
+ static void Write(Message* m, const param_type& p) {
+ m->WriteUInt32(reinterpret_cast<uint32>(p));
+ }
+ static bool Read(const Message* m, void** iter, param_type* r) {
+ DCHECK_EQ(sizeof(param_type), sizeof(uint32));
+ return m->ReadUInt32(iter, reinterpret_cast<uint32*>(r));
+ }
+ static void Log(const param_type& p, std::string* l) {
+// l->append(StringPrintf("0x%X", p));
+ }
+};
+
+template <>
+struct ParamTraits<HACCEL> {
+ typedef HACCEL param_type;
+ static void Write(Message* m, const param_type& p) {
+ m->WriteUInt32(reinterpret_cast<uint32>(p));
+ }
+ static bool Read(const Message* m, void** iter, param_type* r) {
+ DCHECK_EQ(sizeof(param_type), sizeof(uint32));
+ return m->ReadUInt32(iter, reinterpret_cast<uint32*>(r));
+ }
+};
+
+template <>
+struct ParamTraits<POINT> {
+ typedef POINT param_type;
+ static void Write(Message* m, const param_type& p) {
+ m->WriteInt(p.x);
+ m->WriteInt(p.y);
+ }
+ static bool Read(const Message* m, void** iter, param_type* r) {
+ int x, y;
+ if (!m->ReadInt(iter, &x) || !m->ReadInt(iter, &y))
+ return false;
+ r->x = x;
+ r->y = y;
+ return true;
+ }
+ static void Log(const param_type& p, std::string* l) {
+// l->append(StringPrintf("(%d, %d)", p.x, p.y));
+ }
+};
+#endif // defined(OS_WIN)
+
+template <>
+struct IPC_EXPORT ParamTraits<FilePath> {
+ typedef FilePath param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+#if defined(OS_POSIX)
+// FileDescriptors may be serialised over IPC channels on POSIX. On the
+// receiving side, the FileDescriptor is a valid duplicate of the file
+// descriptor which was transmitted: *it is not just a copy of the integer like
+// HANDLEs on Windows*. The only exception is if the file descriptor is < 0. In
+// this case, the receiving end will see a value of -1. *Zero is a valid file
+// descriptor*.
+//
+// The received file descriptor will have the |auto_close| flag set to true. The
+// code which handles the message is responsible for taking ownership of it.
+// File descriptors are OS resources and must be closed when no longer needed.
+//
+// When sending a file descriptor, the file descriptor must be valid at the time
+// of transmission. Since transmission is not synchronous, one should consider
+// dup()ing any file descriptors to be transmitted and setting the |auto_close|
+// flag, which causes the file descriptor to be closed after writing.
+template<>
+struct IPC_EXPORT ParamTraits<base::FileDescriptor> {
+ typedef base::FileDescriptor param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+#endif // defined(OS_POSIX)
+
+// A ChannelHandle is basically a platform-inspecific wrapper around the
+// fact that IPC endpoints are handled specially on POSIX. See above comments
+// on FileDescriptor for more background.
+template<>
+struct IPC_EXPORT ParamTraits<IPC::ChannelHandle> {
+ typedef ChannelHandle param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+#if defined(OS_WIN)
+template <>
+struct ParamTraits<XFORM> {
+ typedef XFORM param_type;
+ static void Write(Message* m, const param_type& p) {
+ m->WriteData(reinterpret_cast<const char*>(&p), sizeof(XFORM));
+ }
+ static bool Read(const Message* m, void** iter, param_type* r) {
+ const char *data;
+ int data_size = 0;
+ bool result = m->ReadData(iter, &data, &data_size);
+ if (result && data_size == sizeof(XFORM)) {
+ memcpy(r, data, sizeof(XFORM));
+ } else {
+ result = false;
+ NOTREACHED();
+ }
+
+ return result;
+ }
+ static void Log(const param_type& p, std::string* l) {
+ l->append("<XFORM>");
+ }
+};
+#endif // defined(OS_WIN)
+
+struct IPC_EXPORT LogData {
+ LogData();
+ ~LogData();
+
+ std::string channel;
+ int32 routing_id;
+ uint32 type; // "User-defined" message type, from ipc_message.h.
+ std::string flags;
+ int64 sent; // Time that the message was sent (i.e. at Send()).
+ int64 receive; // Time before it was dispatched (i.e. before calling
+ // OnMessageReceived).
+ int64 dispatch; // Time after it was dispatched (i.e. after calling
+ // OnMessageReceived).
+ std::string message_name;
+ std::string params;
+};
+
+template <>
+struct IPC_EXPORT ParamTraits<LogData> {
+ typedef LogData param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, void** iter, param_type* r);
+ static void Log(const param_type& p, std::string* l) {
+ // Doesn't make sense to implement this!
+ }
+};
+
+*/
+template <>
+struct ParamTraits<Message> {
+ static void Write(Message* m, const Message& p) {
+ DCHECK(p.size() <= INT_MAX);
+ int message_size = static_cast<int>(p.size());
+ m->WriteInt(message_size);
+ m->WriteData(reinterpret_cast<const char*>(p.data()), message_size);
+ }
+ static bool Read(const Message* m, void** iter, Message* r) {
+ int size;
+ if (!m->ReadInt(iter, &size))
+ return false;
+ const char* data;
+ if (!m->ReadData(iter, &data, &size))
+ return false;
+ *r = Message(data, size);
+ return true;
+ }
+ static void Log(const Message& p, std::string* l) {
+ l->append("<IPC::Message>");
+ }
+};
+
+template <>
+struct ParamTraits<Tuple0> {
+ typedef Tuple0 param_type;
+ static void Write(Message* m, const param_type& p) {
+ }
+ static bool Read(const Message* m, void** iter, param_type* r) {
+ return true;
+ }
+ static void Log(const param_type& p, std::string* l) {
+ }
+};
+
+template <class A>
+struct ParamTraits< Tuple1<A> > {
+ typedef Tuple1<A> param_type;
+ static void Write(Message* m, const param_type& p) {
+ WriteParam(m, p.a);
+ }
+ static bool Read(const Message* m, void** iter, param_type* r) {
+ return ReadParam(m, iter, &r->a);
+ }
+ static void Log(const param_type& p, std::string* l) {
+ LogParam(p.a, l);
+ }
+};
+
+template <class A, class B>
+struct ParamTraits< Tuple2<A, B> > {
+ typedef Tuple2<A, B> param_type;
+ static void Write(Message* m, const param_type& p) {
+ WriteParam(m, p.a);
+ WriteParam(m, p.b);
+ }
+ static bool Read(const Message* m, void** iter, param_type* r) {
+ return (ReadParam(m, iter, &r->a) &&
+ ReadParam(m, iter, &r->b));
+ }
+ static void Log(const param_type& p, std::string* l) {
+ LogParam(p.a, l);
+ l->append(", ");
+ LogParam(p.b, l);
+ }
+};
+
+template <class A, class B, class C>
+struct ParamTraits< Tuple3<A, B, C> > {
+ typedef Tuple3<A, B, C> param_type;
+ static void Write(Message* m, const param_type& p) {
+ WriteParam(m, p.a);
+ WriteParam(m, p.b);
+ WriteParam(m, p.c);
+ }
+ static bool Read(const Message* m, void** iter, param_type* r) {
+ return (ReadParam(m, iter, &r->a) &&
+ ReadParam(m, iter, &r->b) &&
+ ReadParam(m, iter, &r->c));
+ }
+ static void Log(const param_type& p, std::string* l) {
+ LogParam(p.a, l);
+ l->append(", ");
+ LogParam(p.b, l);
+ l->append(", ");
+ LogParam(p.c, l);
+ }
+};
+
+template <class A, class B, class C, class D>
+struct ParamTraits< Tuple4<A, B, C, D> > {
+ typedef Tuple4<A, B, C, D> param_type;
+ static void Write(Message* m, const param_type& p) {
+ WriteParam(m, p.a);
+ WriteParam(m, p.b);
+ WriteParam(m, p.c);
+ WriteParam(m, p.d);
+ }
+ static bool Read(const Message* m, void** iter, param_type* r) {
+ return (ReadParam(m, iter, &r->a) &&
+ ReadParam(m, iter, &r->b) &&
+ ReadParam(m, iter, &r->c) &&
+ ReadParam(m, iter, &r->d));
+ }
+ static void Log(const param_type& p, std::string* l) {
+ LogParam(p.a, l);
+ l->append(", ");
+ LogParam(p.b, l);
+ l->append(", ");
+ LogParam(p.c, l);
+ l->append(", ");
+ LogParam(p.d, l);
+ }
+};
+
+template <class A, class B, class C, class D, class E>
+struct ParamTraits< Tuple5<A, B, C, D, E> > {
+ typedef Tuple5<A, B, C, D, E> param_type;
+ static void Write(Message* m, const param_type& p) {
+ WriteParam(m, p.a);
+ WriteParam(m, p.b);
+ WriteParam(m, p.c);
+ WriteParam(m, p.d);
+ WriteParam(m, p.e);
+ }
+ static bool Read(const Message* m, void** iter, param_type* r) {
+ return (ReadParam(m, iter, &r->a) &&
+ ReadParam(m, iter, &r->b) &&
+ ReadParam(m, iter, &r->c) &&
+ ReadParam(m, iter, &r->d) &&
+ ReadParam(m, iter, &r->e));
+ }
+ static void Log(const param_type& p, std::string* l) {
+ LogParam(p.a, l);
+ l->append(", ");
+ LogParam(p.b, l);
+ l->append(", ");
+ LogParam(p.c, l);
+ l->append(", ");
+ LogParam(p.d, l);
+ l->append(", ");
+ LogParam(p.e, l);
+ }
+};
+
+template <class A, class B, class C, class D, class E, class F>
+struct ParamTraits< Tuple6<A, B, C, D, E, F> > {
+typedef Tuple6<A, B, C, D, E, F> param_type;
+ static void Write(Message* m, const param_type& p) {
+ WriteParam(m, p.a);
+ WriteParam(m, p.b);
+ WriteParam(m, p.c);
+ WriteParam(m, p.d);
+ WriteParam(m, p.e);
+ WriteParam(m, p.f);
+ }
+ static bool Read(const Message* m, void** iter, param_type* r) {
+ return (ReadParam(m, iter, &r->a) &&
+ ReadParam(m, iter, &r->b) &&
+ ReadParam(m, iter, &r->c) &&
+ ReadParam(m, iter, &r->d) &&
+ ReadParam(m, iter, &r->e) &&
+ ReadParam(m, iter, &r->f));
+ }
+ static void Log(const param_type& p, std::string* l) {
+ LogParam(p.a, l);
+ l->append(", ");
+ LogParam(p.b, l);
+ l->append(", ");
+ LogParam(p.c, l);
+ l->append(", ");
+ LogParam(p.d, l);
+ l->append(", ");
+ LogParam(p.e, l);
+ l->append(", ");
+ LogParam(p.f, l);
+ }
+};
+
+//-----------------------------------------------------------------------------
+// Generic message subclasses
+
+// Used for asynchronous messages.
+template <class ParamType>
+class __attribute__((visibility("default"))) MessageWithTuple : public Message {
+ public:
+ typedef ParamType Param;
+ typedef typename TupleTypes<ParamType>::ParamTuple RefParam;
+
+ // The constructor and the Read() method's templated implementations are in
+ // ipc_message_utils_impl.h. The subclass constructor and Log() methods call
+ // the templated versions of these and make sure there are instantiations in
+ // those translation units.
+ MessageWithTuple(int32 routing_id, uint32 type, const RefParam& p);
+
+ static bool Read(const Message* msg, Param* p) IPC_MSG_NOINLINE;
+
+ // Generic dispatcher. Should cover most cases.
+ template<class T, class S, class Method>
+ static bool Dispatch(const Message* msg, T* obj, S* sender, Method func) {
+ Param p;
+ if (Read(msg, &p)) {
+ DispatchToMethod(obj, func, p);
+ return true;
+ }
+ return false;
+ }
+
+ // The following dispatchers exist for the case where the callback function
+ // needs the message as well. They assume that "Param" is a type of Tuple
+ // (except the one arg case, as there is no Tuple1).
+ template<class T, class S, typename TA>
+ static bool Dispatch(const Message* msg, T* obj, S* sender,
+ void (T::*func)(const Message&, TA)) {
+ Param p;
+ if (Read(msg, &p)) {
+ (obj->*func)(*msg, p.a);
+ return true;
+ }
+ return false;
+ }
+
+ template<class T, class S, typename TA, typename TB>
+ static bool Dispatch(const Message* msg, T* obj, S* sender,
+ void (T::*func)(const Message&, TA, TB)) {
+ Param p;
+ if (Read(msg, &p)) {
+ (obj->*func)(*msg, p.a, p.b);
+ return true;
+ }
+ return false;
+ }
+
+ template<class T, class S, typename TA, typename TB, typename TC>
+ static bool Dispatch(const Message* msg, T* obj, S* sender,
+ void (T::*func)(const Message&, TA, TB, TC)) {
+ Param p;
+ if (Read(msg, &p)) {
+ (obj->*func)(*msg, p.a, p.b, p.c);
+ return true;
+ }
+ return false;
+ }
+
+ template<class T, class S, typename TA, typename TB, typename TC, typename TD>
+ static bool Dispatch(const Message* msg, T* obj, S* sender,
+ void (T::*func)(const Message&, TA, TB, TC, TD)) {
+ Param p;
+ if (Read(msg, &p)) {
+ (obj->*func)(*msg, p.a, p.b, p.c, p.d);
+ return true;
+ }
+ return false;
+ }
+
+ template<class T, class S, typename TA, typename TB, typename TC, typename TD,
+ typename TE>
+ static bool Dispatch(const Message* msg, T* obj, S* sender,
+ void (T::*func)(const Message&, TA, TB, TC, TD, TE)) {
+ Param p;
+ if (Read(msg, &p)) {
+ (obj->*func)(*msg, p.a, p.b, p.c, p.d, p.e);
+ return true;
+ }
+ return false;
+ }
+
+ // Functions used to do manual unpacking. Only used by the automation code,
+ // these should go away once that code uses SyncChannel.
+ template<typename TA, typename TB>
+ static bool Read(const IPC::Message* msg, TA* a, TB* b) {
+ ParamType params;
+ if (!Read(msg, &params))
+ return false;
+ *a = params.a;
+ *b = params.b;
+ return true;
+ }
+
+ template<typename TA, typename TB, typename TC>
+ static bool Read(const IPC::Message* msg, TA* a, TB* b, TC* c) {
+ ParamType params;
+ if (!Read(msg, &params))
+ return false;
+ *a = params.a;
+ *b = params.b;
+ *c = params.c;
+ return true;
+ }
+
+ template<typename TA, typename TB, typename TC, typename TD>
+ static bool Read(const IPC::Message* msg, TA* a, TB* b, TC* c, TD* d) {
+ ParamType params;
+ if (!Read(msg, &params))
+ return false;
+ *a = params.a;
+ *b = params.b;
+ *c = params.c;
+ *d = params.d;
+ return true;
+ }
+
+ template<typename TA, typename TB, typename TC, typename TD, typename TE>
+ static bool Read(const IPC::Message* msg, TA* a, TB* b, TC* c, TD* d, TE* e) {
+ ParamType params;
+ if (!Read(msg, &params))
+ return false;
+ *a = params.a;
+ *b = params.b;
+ *c = params.c;
+ *d = params.d;
+ *e = params.e;
+ return true;
+ }
+};
+
+// defined in ipc_logging.cc
+IPC_EXPORT void GenerateLogData(const std::string& channel,
+ const Message& message,
+ LogData* data);
+
+
+#if defined(IPC_MESSAGE_LOG_ENABLED)
+inline void AddOutputParamsToLog(const Message* msg, std::string* l) {
+ const std::string& output_params = msg->output_params();
+ if (!l->empty() && !output_params.empty())
+ l->append(", ");
+
+ l->append(output_params);
+}
+
+template <class ReplyParamType>
+inline void LogReplyParamsToMessage(const ReplyParamType& reply_params,
+ const Message* msg) {
+ if (msg->received_time() != 0) {
+ std::string output_params;
+ LogParam(reply_params, &output_params);
+ msg->set_output_params(output_params);
+ }
+}
+
+inline void ConnectMessageAndReply(const Message* msg, Message* reply) {
+ if (msg->sent_time()) {
+ // Don't log the sync message after dispatch, as we don't have the
+ // output parameters at that point. Instead, save its data and log it
+ // with the outgoing reply message when it's sent.
+ LogData* data = new LogData;
+ GenerateLogData("", *msg, data);
+ msg->set_dont_log();
+ reply->set_sync_log_data(data);
+ }
+}
+#else
+inline void AddOutputParamsToLog(const Message* msg, std::string* l) {}
+
+template <class ReplyParamType>
+inline void LogReplyParamsToMessage(const ReplyParamType& reply_params,
+ const Message* msg) {}
+
+inline void ConnectMessageAndReply(const Message* msg, Message* reply) {}
+#endif
+
+// This class assumes that its template argument is a RefTuple (a Tuple with
+// reference elements). This would go into ipc_message_utils_impl.h, but it is
+// also used by chrome_frame.
+template <class RefTuple>
+class ParamDeserializer : public MessageReplyDeserializer {
+ public:
+ explicit ParamDeserializer(const RefTuple& out) : out_(out) { }
+
+ bool SerializeOutputParameters(const IPC::Message& msg, void* iter) {
+ return ReadParam(&msg, &iter, &out_);
+ }
+
+ RefTuple out_;
+};
+
+// Used for synchronous messages.
+template <class SendParamType, class ReplyParamType>
+class __attribute__((visibility("default"))) MessageWithReply : public SyncMessage {
+ public:
+ typedef SendParamType SendParam;
+ typedef typename TupleTypes<SendParam>::ParamTuple RefSendParam;
+ typedef ReplyParamType ReplyParam;
+
+ MessageWithReply(int32 routing_id, uint32 type,
+ const RefSendParam& send, const ReplyParam& reply);
+ static bool ReadSendParam(const Message* msg, SendParam* p) IPC_MSG_NOINLINE;
+ static bool ReadReplyParam(
+ const Message* msg,
+ typename TupleTypes<ReplyParam>::ValueTuple* p) IPC_MSG_NOINLINE;
+
+ template<class T, class S, class Method>
+ static bool Dispatch(const Message* msg, T* obj, S* sender, Method func) {
+ SendParam send_params;
+ Message* reply = GenerateReply(msg);
+ bool error;
+ if (ReadSendParam(msg, &send_params)) {
+ typename TupleTypes<ReplyParam>::ValueTuple reply_params;
+ DispatchToMethod(obj, func, send_params, &reply_params);
+ WriteParam(reply, reply_params);
+ error = false;
+ LogReplyParamsToMessage(reply_params, msg);
+ } else {
+ NOTREACHED() << "Error deserializing message " << msg->type();
+ reply->set_reply_error();
+ error = true;
+ }
+
+ sender->Send(reply);
+ return !error;
+ }
+
+ template<class T, class Method>
+ static bool DispatchDelayReply(const Message* msg, T* obj, Method func) {
+ SendParam send_params;
+ Message* reply = GenerateReply(msg);
+ bool error;
+ if (ReadSendParam(msg, &send_params)) {
+ Tuple1<Message&> t = MakeRefTuple(*reply);
+ ConnectMessageAndReply(msg, reply);
+ DispatchToMethod(obj, func, send_params, &t);
+ error = false;
+ } else {
+ NOTREACHED() << "Error deserializing message " << msg->type();
+ reply->set_reply_error();
+ obj->Send(reply);
+ error = true;
+ }
+ return !error;
+ }
+
+ template<typename TA>
+ static void WriteReplyParams(Message* reply, TA a) {
+ ReplyParam p(a);
+ WriteParam(reply, p);
+ }
+
+ template<typename TA, typename TB>
+ static void WriteReplyParams(Message* reply, TA a, TB b) {
+ ReplyParam p(a, b);
+ WriteParam(reply, p);
+ }
+
+ template<typename TA, typename TB, typename TC>
+ static void WriteReplyParams(Message* reply, TA a, TB b, TC c) {
+ ReplyParam p(a, b, c);
+ WriteParam(reply, p);
+ }
+
+ template<typename TA, typename TB, typename TC, typename TD>
+ static void WriteReplyParams(Message* reply, TA a, TB b, TC c, TD d) {
+ ReplyParam p(a, b, c, d);
+ WriteParam(reply, p);
+ }
+
+ template<typename TA, typename TB, typename TC, typename TD, typename TE>
+ static void WriteReplyParams(Message* reply, TA a, TB b, TC c, TD d, TE e) {
+ ReplyParam p(a, b, c, d, e);
+ WriteParam(reply, p);
+ }
+};
+
+//-----------------------------------------------------------------------------
+
+} // namespace IPC
+
+#endif // IPC_IPC_MESSAGE_UTILS_H_
diff --git a/ipc/ipc_message_utils_impl.h b/ipc/ipc_message_utils_impl.h
new file mode 100644
index 000000000000..7e512a62c28b
--- /dev/null
+++ b/ipc/ipc_message_utils_impl.h
@@ -0,0 +1,61 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// This file contains templates forward declared (but not defined) in
+// ipc_message_utils.h so that they are only instantiated in certain files,
+// notably a few IPC unit tests.
+
+#ifndef IPC_IPC_MESSAGE_UTILS_IMPL_H_
+#define IPC_IPC_MESSAGE_UTILS_IMPL_H_
+
+namespace IPC {
+
+template <class ParamType>
+MessageWithTuple<ParamType>::MessageWithTuple(
+ int32 routing_id, uint32 type, const RefParam& p)
+ : Message(routing_id, type, PRIORITY_NORMAL) {
+ WriteParam(this, p);
+}
+
+template <class ParamType>
+bool MessageWithTuple<ParamType>::Read(const Message* msg, Param* p) {
+ void* iter = NULL;
+ if (ReadParam(msg, &iter, p))
+ return true;
+ NOTREACHED() << "Error deserializing message " << msg->type();
+ return false;
+}
+
+// We can't migrate the template for Log() to MessageWithTuple, because each
+// subclass needs to have Log() to call Read(), which instantiates the above
+// template.
+
+template <class SendParamType, class ReplyParamType>
+MessageWithReply<SendParamType, ReplyParamType>::MessageWithReply(
+ int32 routing_id, uint32 type,
+ const RefSendParam& send,
+ const ReplyParam& reply)
+ : SyncMessage(routing_id, type, PRIORITY_NORMAL,
+ new ParamDeserializer<ReplyParam>(reply))
+{
+ WriteParam(this, send);
+}
+
+template <class SendParamType, class ReplyParamType>
+bool MessageWithReply<SendParamType, ReplyParamType>::ReadSendParam(
+ const Message* msg, SendParam* p) {
+ void* iter = SyncMessage::GetDataIterator(msg);
+ return ReadParam(msg, &iter, p);
+}
+
+template <class SendParamType, class ReplyParamType>
+bool MessageWithReply<SendParamType, ReplyParamType>::ReadReplyParam(
+ const Message* msg, typename TupleTypes<ReplyParam>::ValueTuple* p) {
+ void* iter = SyncMessage::GetDataIterator(msg);
+ return ReadParam(msg, &iter, p);
+}
+
+} // namespace IPC
+
+#endif // IPC_IPC_MESSAGE_UTILS_IMPL_H_
diff --git a/ipc/ipc_param_traits.h b/ipc/ipc_param_traits.h
new file mode 100644
index 000000000000..e90be18a1b21
--- /dev/null
+++ b/ipc/ipc_param_traits.h
@@ -0,0 +1,24 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IPC_IPC_PARAM_TRAITS_H_
+#define IPC_IPC_PARAM_TRAITS_H_
+#pragma once
+
+// Our IPC system uses the following partially specialized header to define how
+// a data type is read, written and logged in the IPC system.
+
+namespace IPC {
+
+template <class P> struct ParamTraits {
+};
+
+template <class P>
+struct SimilarTypeTraits {
+ typedef P Type;
+};
+
+} // namespace IPC
+
+#endif // IPC_IPC_PARAM_TRAITS_H_
diff --git a/ipc/ipc_platform_file.cc b/ipc/ipc_platform_file.cc
new file mode 100644
index 000000000000..2b15cebfb885
--- /dev/null
+++ b/ipc/ipc_platform_file.cc
@@ -0,0 +1,43 @@
+// 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 "ipc/ipc_platform_file.h"
+
+namespace IPC {
+
+PlatformFileForTransit GetFileHandleForProcess(base::PlatformFile handle,
+ base::ProcessHandle process,
+ bool close_source_handle) {
+ IPC::PlatformFileForTransit out_handle;
+#if defined(OS_WIN)
+ DWORD options = DUPLICATE_SAME_ACCESS;
+ if (close_source_handle)
+ options |= DUPLICATE_CLOSE_SOURCE;
+ if (!::DuplicateHandle(::GetCurrentProcess(),
+ handle,
+ process,
+ &out_handle,
+ 0,
+ FALSE,
+ options)) {
+ out_handle = IPC::InvalidPlatformFileForTransit();
+ }
+#elif defined(OS_POSIX)
+ // If asked to close the source, we can simply re-use the source fd instead of
+ // dup()ing and close()ing.
+ // When we're not closing the source, we need to duplicate the handle and take
+ // ownership of that. The reason is that this function is often used to
+ // generate IPC messages, and the handle must remain valid until it's sent to
+ // the other process from the I/O thread. Without the dup, calling code might
+ // close the source handle before the message is sent, creating a race
+ // condition.
+ int fd = close_source_handle ? handle : ::dup(handle);
+ out_handle = base::FileDescriptor(fd, true);
+#else
+ #error Not implemented.
+#endif
+ return out_handle;
+}
+
+} // namespace IPC
diff --git a/ipc/ipc_platform_file.h b/ipc/ipc_platform_file.h
new file mode 100644
index 000000000000..daaf21cb14b2
--- /dev/null
+++ b/ipc/ipc_platform_file.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IPC_IPC_PLATFORM_FILE_H_
+#define IPC_IPC_PLATFORM_FILE_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "base/platform_file.h"
+#include "base/process.h"
+#include "ipc/ipc_export.h"
+
+#if defined(OS_POSIX)
+#include "base/file_descriptor_posix.h"
+#endif
+
+namespace IPC {
+
+#if defined(OS_WIN)
+typedef base::PlatformFile PlatformFileForTransit;
+#elif defined(OS_POSIX)
+typedef base::FileDescriptor PlatformFileForTransit;
+#endif
+
+inline PlatformFileForTransit InvalidPlatformFileForTransit() {
+#if defined(OS_WIN)
+ return base::kInvalidPlatformFileValue;
+#elif defined(OS_POSIX)
+ return base::FileDescriptor();
+#endif
+}
+
+inline base::PlatformFile PlatformFileForTransitToPlatformFile(
+ const PlatformFileForTransit& transit) {
+#if defined(OS_WIN)
+ return transit;
+#elif defined(OS_POSIX)
+ return transit.fd;
+#endif
+}
+
+// Returns a file handle equivalent to |file| that can be used in |process|.
+IPC_EXPORT PlatformFileForTransit GetFileHandleForProcess(
+ base::PlatformFile file,
+ base::ProcessHandle process,
+ bool close_source_handle);
+
+} // namespace IPC
+
+#endif // IPC_IPC_PLATFORM_FILE_H_
diff --git a/ipc/ipc_switches.cc b/ipc/ipc_switches.cc
new file mode 100644
index 000000000000..bcb12256e545
--- /dev/null
+++ b/ipc/ipc_switches.cc
@@ -0,0 +1,24 @@
+// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ipc/ipc_switches.h"
+
+#include "base/base_switches.h"
+
+namespace switches {
+
+// Can't find the switch you are looking for? try looking in
+// base/base_switches.cc instead.
+
+// The value of this switch tells the child process which
+// IPC channel the browser expects to use to communicate with it.
+const char kProcessChannelID[] = "channel";
+
+// Will add kDebugOnStart to every child processes. If a value is passed, it
+// will be used as a filter to determine if the child process should have the
+// kDebugOnStart flag passed on or not.
+const char kDebugChildren[] = "debug-children";
+
+} // namespace switches
+
diff --git a/ipc/ipc_switches.h b/ipc/ipc_switches.h
new file mode 100644
index 000000000000..7c7a833028df
--- /dev/null
+++ b/ipc/ipc_switches.h
@@ -0,0 +1,20 @@
+// 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.
+
+// Defines all the command-line switches used by the IPC infrastructure.
+
+#ifndef IPC_IPC_SWITCHES_H_
+#define IPC_IPC_SWITCHES_H_
+#pragma once
+
+#include "ipc/ipc_export.h"
+
+namespace switches {
+
+IPC_EXPORT extern const char kProcessChannelID[];
+IPC_EXPORT extern const char kDebugChildren[];
+
+} // namespace switches
+
+#endif // IPC_IPC_SWITCHES_H_
diff --git a/ipc/ipc_sync_channel.cc b/ipc/ipc_sync_channel.cc
new file mode 100644
index 000000000000..c135ef38eb3f
--- /dev/null
+++ b/ipc/ipc_sync_channel.cc
@@ -0,0 +1,513 @@
+// 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 "ipc/ipc_sync_channel.h"
+
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/threading/thread_local.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/synchronization/waitable_event_watcher.h"
+#include "ipc/ipc_sync_message.h"
+
+using base::TimeDelta;
+using base::TimeTicks;
+using base::WaitableEvent;
+
+namespace IPC {
+// When we're blocked in a Send(), we need to process incoming synchronous
+// messages right away because it could be blocking our reply (either
+// directly from the same object we're calling, or indirectly through one or
+// more other channels). That means that in SyncContext's OnMessageReceived,
+// we need to process sync message right away if we're blocked. However a
+// simple check isn't sufficient, because the listener thread can be in the
+// process of calling Send.
+// To work around this, when SyncChannel filters a sync message, it sets
+// an event that the listener thread waits on during its Send() call. This
+// allows us to dispatch incoming sync messages when blocked. The race
+// condition is handled because if Send is in the process of being called, it
+// will check the event. In case the listener thread isn't sending a message,
+// we queue a task on the listener thread to dispatch the received messages.
+// The messages are stored in this queue object that's shared among all
+// SyncChannel objects on the same thread (since one object can receive a
+// sync message while another one is blocked).
+
+class SyncChannel::ReceivedSyncMsgQueue :
+ public base::RefCountedThreadSafe<ReceivedSyncMsgQueue> {
+ public:
+ // Returns the ReceivedSyncMsgQueue instance for this thread, creating one
+ // if necessary. Call RemoveContext on the same thread when done.
+ static ReceivedSyncMsgQueue* AddContext() {
+ // We want one ReceivedSyncMsgQueue per listener thread (i.e. since multiple
+ // SyncChannel objects can block the same thread).
+ ReceivedSyncMsgQueue* rv = lazy_tls_ptr_.Pointer()->Get();
+ if (!rv) {
+ rv = new ReceivedSyncMsgQueue();
+ ReceivedSyncMsgQueue::lazy_tls_ptr_.Pointer()->Set(rv);
+ }
+ rv->listener_count_++;
+ return rv;
+ }
+
+ // Called on IPC thread when a synchronous message or reply arrives.
+ void QueueMessage(const Message& msg, SyncChannel::SyncContext* context) {
+ bool was_task_pending;
+ {
+ base::AutoLock auto_lock(message_lock_);
+
+ was_task_pending = task_pending_;
+ task_pending_ = true;
+
+ // We set the event in case the listener thread is blocked (or is about
+ // to). In case it's not, the PostTask dispatches the messages.
+ message_queue_.push_back(QueuedMessage(new Message(msg), context));
+ }
+
+ dispatch_event_.Signal();
+ if (!was_task_pending) {
+ listener_message_loop_->PostTask(FROM_HERE, NewRunnableMethod(
+ this,
+ &ReceivedSyncMsgQueue::DispatchMessagesTask,
+ scoped_refptr<SyncContext>(context)));
+ }
+ }
+
+ void QueueReply(const Message &msg, SyncChannel::SyncContext* context) {
+ received_replies_.push_back(QueuedMessage(new Message(msg), context));
+ }
+
+ // Called on the listener's thread to process any queues synchronous
+ // messages.
+ void DispatchMessagesTask(SyncContext* context) {
+ {
+ base::AutoLock auto_lock(message_lock_);
+ task_pending_ = false;
+ }
+ context->DispatchMessages();
+ }
+
+ void DispatchMessages(SyncContext* dispatching_context) {
+ SyncMessageQueue delayed_queue;
+ while (true) {
+ Message* message;
+ scoped_refptr<SyncChannel::SyncContext> context;
+ {
+ base::AutoLock auto_lock(message_lock_);
+ if (message_queue_.empty()) {
+ message_queue_ = delayed_queue;
+ break;
+ }
+
+ message = message_queue_.front().message;
+ context = message_queue_.front().context;
+ message_queue_.pop_front();
+ }
+ if (context->restrict_dispatch() && context != dispatching_context) {
+ delayed_queue.push_back(QueuedMessage(message, context));
+ } else {
+ context->OnDispatchMessage(*message);
+ delete message;
+ }
+ }
+ }
+
+ // SyncChannel calls this in its destructor.
+ void RemoveContext(SyncContext* context) {
+ base::AutoLock auto_lock(message_lock_);
+
+ SyncMessageQueue::iterator iter = message_queue_.begin();
+ while (iter != message_queue_.end()) {
+ if (iter->context == context) {
+ delete iter->message;
+ iter = message_queue_.erase(iter);
+ } else {
+ iter++;
+ }
+ }
+
+ if (--listener_count_ == 0) {
+ DCHECK(lazy_tls_ptr_.Pointer()->Get());
+ lazy_tls_ptr_.Pointer()->Set(NULL);
+ }
+ }
+
+ WaitableEvent* dispatch_event() { return &dispatch_event_; }
+ base::MessageLoopProxy* listener_message_loop() {
+ return listener_message_loop_;
+ }
+
+ // Holds a pointer to the per-thread ReceivedSyncMsgQueue object.
+ static base::LazyInstance<base::ThreadLocalPointer<ReceivedSyncMsgQueue> >
+ lazy_tls_ptr_;
+
+ // Called on the ipc thread to check if we can unblock any current Send()
+ // calls based on a queued reply.
+ void DispatchReplies() {
+ for (size_t i = 0; i < received_replies_.size(); ++i) {
+ Message* message = received_replies_[i].message;
+ if (received_replies_[i].context->TryToUnblockListener(message)) {
+ delete message;
+ received_replies_.erase(received_replies_.begin() + i);
+ return;
+ }
+ }
+ }
+
+ base::WaitableEventWatcher* top_send_done_watcher() {
+ return top_send_done_watcher_;
+ }
+
+ void set_top_send_done_watcher(base::WaitableEventWatcher* watcher) {
+ top_send_done_watcher_ = watcher;
+ }
+
+ private:
+ friend class base::RefCountedThreadSafe<ReceivedSyncMsgQueue>;
+
+ // See the comment in SyncChannel::SyncChannel for why this event is created
+ // as manual reset.
+ ReceivedSyncMsgQueue() :
+ dispatch_event_(true, false),
+ listener_message_loop_(base::MessageLoopProxy::current()),
+ task_pending_(false),
+ listener_count_(0),
+ top_send_done_watcher_(NULL) {
+ }
+
+ ~ReceivedSyncMsgQueue() {}
+
+ // Holds information about a queued synchronous message or reply.
+ struct QueuedMessage {
+ QueuedMessage(Message* m, SyncContext* c) : message(m), context(c) { }
+ Message* message;
+ scoped_refptr<SyncChannel::SyncContext> context;
+ };
+
+ typedef std::deque<QueuedMessage> SyncMessageQueue;
+ SyncMessageQueue message_queue_;
+
+ std::vector<QueuedMessage> received_replies_;
+
+ // Set when we got a synchronous message that we must respond to as the
+ // sender needs its reply before it can reply to our original synchronous
+ // message.
+ WaitableEvent dispatch_event_;
+ scoped_refptr<base::MessageLoopProxy> listener_message_loop_;
+ base::Lock message_lock_;
+ bool task_pending_;
+ int listener_count_;
+
+ // The current send done event watcher for this thread. Used to maintain
+ // a local global stack of send done watchers to ensure that nested sync
+ // message loops complete correctly.
+ base::WaitableEventWatcher* top_send_done_watcher_;
+};
+
+base::LazyInstance<base::ThreadLocalPointer<SyncChannel::ReceivedSyncMsgQueue> >
+ SyncChannel::ReceivedSyncMsgQueue::lazy_tls_ptr_(base::LINKER_INITIALIZED);
+
+SyncChannel::SyncContext::SyncContext(
+ Channel::Listener* listener,
+ base::MessageLoopProxy* ipc_thread,
+ WaitableEvent* shutdown_event)
+ : ChannelProxy::Context(listener, ipc_thread),
+ received_sync_msgs_(ReceivedSyncMsgQueue::AddContext()),
+ shutdown_event_(shutdown_event),
+ restrict_dispatch_(false) {
+}
+
+SyncChannel::SyncContext::~SyncContext() {
+ while (!deserializers_.empty())
+ Pop();
+}
+
+// Adds information about an outgoing sync message to the context so that
+// we know how to deserialize the reply. Returns a handle that's set when
+// the reply has arrived.
+void SyncChannel::SyncContext::Push(SyncMessage* sync_msg) {
+ // Create the tracking information for this message. This object is stored
+ // by value since all members are pointers that are cheap to copy. These
+ // pointers are cleaned up in the Pop() function.
+ //
+ // The event is created as manual reset because in between Signal and
+ // OnObjectSignalled, another Send can happen which would stop the watcher
+ // from being called. The event would get watched later, when the nested
+ // Send completes, so the event will need to remain set.
+ PendingSyncMsg pending(SyncMessage::GetMessageId(*sync_msg),
+ sync_msg->GetReplyDeserializer(),
+ new WaitableEvent(true, false));
+ base::AutoLock auto_lock(deserializers_lock_);
+ deserializers_.push_back(pending);
+}
+
+bool SyncChannel::SyncContext::Pop() {
+ bool result;
+ {
+ base::AutoLock auto_lock(deserializers_lock_);
+ PendingSyncMsg msg = deserializers_.back();
+ delete msg.deserializer;
+ delete msg.done_event;
+ msg.done_event = NULL;
+ deserializers_.pop_back();
+ result = msg.send_result;
+ }
+
+ // We got a reply to a synchronous Send() call that's blocking the listener
+ // thread. However, further down the call stack there could be another
+ // blocking Send() call, whose reply we received after we made this last
+ // Send() call. So check if we have any queued replies available that
+ // can now unblock the listener thread.
+ ipc_message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
+ received_sync_msgs_.get(), &ReceivedSyncMsgQueue::DispatchReplies));
+
+ return result;
+}
+
+WaitableEvent* SyncChannel::SyncContext::GetSendDoneEvent() {
+ base::AutoLock auto_lock(deserializers_lock_);
+ return deserializers_.back().done_event;
+}
+
+WaitableEvent* SyncChannel::SyncContext::GetDispatchEvent() {
+ return received_sync_msgs_->dispatch_event();
+}
+
+void SyncChannel::SyncContext::DispatchMessages() {
+ received_sync_msgs_->DispatchMessages(this);
+}
+
+bool SyncChannel::SyncContext::TryToUnblockListener(const Message* msg) {
+ base::AutoLock auto_lock(deserializers_lock_);
+ if (deserializers_.empty() ||
+ !SyncMessage::IsMessageReplyTo(*msg, deserializers_.back().id)) {
+ return false;
+ }
+
+ if (!msg->is_reply_error()) {
+ deserializers_.back().send_result = deserializers_.back().deserializer->
+ SerializeOutputParameters(*msg);
+ }
+ deserializers_.back().done_event->Signal();
+
+ return true;
+}
+
+void SyncChannel::SyncContext::Clear() {
+ CancelPendingSends();
+ received_sync_msgs_->RemoveContext(this);
+ Context::Clear();
+}
+
+bool SyncChannel::SyncContext::OnMessageReceived(const Message& msg) {
+ // Give the filters a chance at processing this message.
+ if (TryFilters(msg))
+ return true;
+
+ if (TryToUnblockListener(&msg))
+ return true;
+
+ if (msg.should_unblock()) {
+ received_sync_msgs_->QueueMessage(msg, this);
+ return true;
+ }
+
+ if (msg.is_reply()) {
+ received_sync_msgs_->QueueReply(msg, this);
+ return true;
+ }
+
+ return Context::OnMessageReceivedNoFilter(msg);
+}
+
+void SyncChannel::SyncContext::OnChannelError() {
+ CancelPendingSends();
+ shutdown_watcher_.StopWatching();
+ Context::OnChannelError();
+}
+
+void SyncChannel::SyncContext::OnChannelOpened() {
+ shutdown_watcher_.StartWatching(shutdown_event_, this);
+ Context::OnChannelOpened();
+}
+
+void SyncChannel::SyncContext::OnChannelClosed() {
+ CancelPendingSends();
+ shutdown_watcher_.StopWatching();
+ Context::OnChannelClosed();
+}
+
+void SyncChannel::SyncContext::OnSendTimeout(int message_id) {
+ base::AutoLock auto_lock(deserializers_lock_);
+ PendingSyncMessageQueue::iterator iter;
+ for (iter = deserializers_.begin(); iter != deserializers_.end(); iter++) {
+ if (iter->id == message_id) {
+ iter->done_event->Signal();
+ break;
+ }
+ }
+}
+
+void SyncChannel::SyncContext::CancelPendingSends() {
+ base::AutoLock auto_lock(deserializers_lock_);
+ PendingSyncMessageQueue::iterator iter;
+ for (iter = deserializers_.begin(); iter != deserializers_.end(); iter++)
+ iter->done_event->Signal();
+}
+
+void SyncChannel::SyncContext::OnWaitableEventSignaled(WaitableEvent* event) {
+ if (event == shutdown_event_) {
+ // Process shut down before we can get a reply to a synchronous message.
+ // Cancel pending Send calls, which will end up setting the send done event.
+ CancelPendingSends();
+ } else {
+ // We got the reply, timed out or the process shutdown.
+ DCHECK_EQ(GetSendDoneEvent(), event);
+ MessageLoop::current()->QuitNow();
+ }
+}
+
+
+SyncChannel::SyncChannel(
+ const IPC::ChannelHandle& channel_handle,
+ Channel::Mode mode,
+ Channel::Listener* listener,
+ base::MessageLoopProxy* ipc_message_loop,
+ bool create_pipe_now,
+ WaitableEvent* shutdown_event)
+ : ChannelProxy(
+ channel_handle, mode, ipc_message_loop,
+ new SyncContext(listener, ipc_message_loop, shutdown_event),
+ create_pipe_now),
+ sync_messages_with_no_timeout_allowed_(true) {
+ // Ideally we only want to watch this object when running a nested message
+ // loop. However, we don't know when it exits if there's another nested
+ // message loop running under it or not, so we wouldn't know whether to
+ // stop or keep watching. So we always watch it, and create the event as
+ // manual reset since the object watcher might otherwise reset the event
+ // when we're doing a WaitMany.
+ dispatch_watcher_.StartWatching(sync_context()->GetDispatchEvent(), this);
+}
+
+SyncChannel::~SyncChannel() {
+}
+
+void SyncChannel::SetRestrictDispatchToSameChannel(bool value) {
+ sync_context()->set_restrict_dispatch(value);
+}
+
+bool SyncChannel::Send(Message* message) {
+ return SendWithTimeout(message, base::kNoTimeout);
+}
+
+bool SyncChannel::SendWithTimeout(Message* message, int timeout_ms) {
+ if (!message->is_sync()) {
+ ChannelProxy::Send(message);
+ return true;
+ }
+
+ // *this* might get deleted in WaitForReply.
+ scoped_refptr<SyncContext> context(sync_context());
+ if (context->shutdown_event()->IsSignaled()) {
+ delete message;
+ return false;
+ }
+
+ DCHECK(sync_messages_with_no_timeout_allowed_ ||
+ timeout_ms != base::kNoTimeout);
+ SyncMessage* sync_msg = static_cast<SyncMessage*>(message);
+ context->Push(sync_msg);
+ int message_id = SyncMessage::GetMessageId(*sync_msg);
+ WaitableEvent* pump_messages_event = sync_msg->pump_messages_event();
+
+ ChannelProxy::Send(message);
+
+ if (timeout_ms != base::kNoTimeout) {
+ // We use the sync message id so that when a message times out, we don't
+ // confuse it with another send that is either above/below this Send in
+ // the call stack.
+ context->ipc_message_loop()->PostDelayedTask(FROM_HERE,
+ NewRunnableMethod(context.get(),
+ &SyncContext::OnSendTimeout, message_id), timeout_ms);
+ }
+
+ // Wait for reply, or for any other incoming synchronous messages.
+ // *this* might get deleted, so only call static functions at this point.
+ WaitForReply(context, pump_messages_event);
+
+ return context->Pop();
+}
+
+void SyncChannel::WaitForReply(
+ SyncContext* context, WaitableEvent* pump_messages_event) {
+ context->DispatchMessages();
+ while (true) {
+ WaitableEvent* objects[] = {
+ context->GetDispatchEvent(),
+ context->GetSendDoneEvent(),
+ pump_messages_event
+ };
+
+ unsigned count = pump_messages_event ? 3: 2;
+ size_t result = WaitableEvent::WaitMany(objects, count);
+ if (result == 0 /* dispatch event */) {
+ // We're waiting for a reply, but we received a blocking synchronous
+ // call. We must process it or otherwise a deadlock might occur.
+ context->GetDispatchEvent()->Reset();
+ context->DispatchMessages();
+ continue;
+ }
+
+ if (result == 2 /* pump_messages_event */)
+ WaitForReplyWithNestedMessageLoop(context); // Run a nested message loop.
+
+ break;
+ }
+}
+
+void SyncChannel::WaitForReplyWithNestedMessageLoop(SyncContext* context) {
+ base::WaitableEventWatcher send_done_watcher;
+
+ ReceivedSyncMsgQueue* sync_msg_queue = context->received_sync_msgs();
+ DCHECK(sync_msg_queue != NULL);
+
+ base::WaitableEventWatcher* old_send_done_event_watcher =
+ sync_msg_queue->top_send_done_watcher();
+
+ base::WaitableEventWatcher::Delegate* old_delegate = NULL;
+ base::WaitableEvent* old_event = NULL;
+
+ // Maintain a local global stack of send done delegates to ensure that
+ // nested sync calls complete in the correct sequence, i.e. the
+ // outermost call completes first, etc.
+ if (old_send_done_event_watcher) {
+ old_delegate = old_send_done_event_watcher->delegate();
+ old_event = old_send_done_event_watcher->GetWatchedEvent();
+ old_send_done_event_watcher->StopWatching();
+ }
+
+ sync_msg_queue->set_top_send_done_watcher(&send_done_watcher);
+
+ send_done_watcher.StartWatching(context->GetSendDoneEvent(), context);
+ bool old_state = MessageLoop::current()->NestableTasksAllowed();
+
+ MessageLoop::current()->SetNestableTasksAllowed(true);
+ MessageLoop::current()->Run();
+ MessageLoop::current()->SetNestableTasksAllowed(old_state);
+
+ sync_msg_queue->set_top_send_done_watcher(old_send_done_event_watcher);
+ if (old_send_done_event_watcher && old_event) {
+ old_send_done_event_watcher->StartWatching(old_event, old_delegate);
+ }
+}
+
+void SyncChannel::OnWaitableEventSignaled(WaitableEvent* event) {
+ DCHECK(event == sync_context()->GetDispatchEvent());
+ // The call to DispatchMessages might delete this object, so reregister
+ // the object watcher first.
+ event->Reset();
+ dispatch_watcher_.StartWatching(event, this);
+ sync_context()->DispatchMessages();
+}
+
+} // namespace IPC
diff --git a/ipc/ipc_sync_channel.h b/ipc/ipc_sync_channel.h
new file mode 100644
index 000000000000..29844da5629a
--- /dev/null
+++ b/ipc/ipc_sync_channel.h
@@ -0,0 +1,200 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IPC_IPC_SYNC_SENDER_H__
+#define IPC_IPC_SYNC_SENDER_H__
+#pragma once
+
+#include <string>
+#include <deque>
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event_watcher.h"
+#include "ipc/ipc_channel_handle.h"
+#include "ipc/ipc_channel_proxy.h"
+#include "ipc/ipc_sync_message.h"
+
+namespace base {
+class WaitableEvent;
+};
+
+namespace IPC {
+
+class SyncMessage;
+class MessageReplyDeserializer;
+
+// This is similar to ChannelProxy, with the added feature of supporting sending
+// synchronous messages.
+//
+// Overview of how the sync channel works
+// --------------------------------------
+// When the sending thread sends a synchronous message, we create a bunch
+// of tracking info (created in SendWithTimeout, stored in the PendingSyncMsg
+// structure) associated with the message that we identify by the unique
+// "MessageId" on the SyncMessage. Among the things we save is the
+// "Deserializer" which is provided by the sync message. This object is in
+// charge of reading the parameters from the reply message and putting them in
+// the output variables provided by its caller.
+//
+// The info gets stashed in a queue since we could have a nested stack of sync
+// messages (each side could send sync messages in response to sync messages,
+// so it works like calling a function). The message is sent to the I/O thread
+// for dispatch and the original thread blocks waiting for the reply.
+//
+// SyncContext maintains the queue in a threadsafe way and listens for replies
+// on the I/O thread. When a reply comes in that matches one of the messages
+// it's looking for (using the unique message ID), it will execute the
+// deserializer stashed from before, and unblock the original thread.
+//
+//
+// Significant complexity results from the fact that messages are still coming
+// in while the original thread is blocked. Normal async messages are queued
+// and dispatched after the blocking call is complete. Sync messages must
+// be dispatched in a reentrant manner to avoid deadlock.
+//
+//
+// Note that care must be taken that the lifetime of the ipc_thread argument
+// is more than this object. If the message loop goes away while this object
+// is running and it's used to send a message, then it will use the invalid
+// message loop pointer to proxy it to the ipc thread.
+class IPC_EXPORT SyncChannel : public ChannelProxy,
+ public base::WaitableEventWatcher::Delegate {
+ public:
+ SyncChannel(const IPC::ChannelHandle& channel_handle,
+ Channel::Mode mode,
+ Channel::Listener* listener,
+ base::MessageLoopProxy* ipc_message_loop,
+ bool create_pipe_now,
+ base::WaitableEvent* shutdown_event);
+ virtual ~SyncChannel();
+
+ virtual bool Send(Message* message);
+ virtual bool SendWithTimeout(Message* message, int timeout_ms);
+
+ // Whether we allow sending messages with no time-out.
+ void set_sync_messages_with_no_timeout_allowed(bool value) {
+ sync_messages_with_no_timeout_allowed_ = value;
+ }
+
+ // Sets this channel to only dispatch its incoming unblocking messages when it
+ // is itself blocked on sending a sync message, not when other channels are.
+ //
+ // Normally, any unblocking message coming from any channel can be dispatched
+ // when any (possibly other) channel is blocked on sending a message. This is
+ // needed in some cases to unblock certain loops (e.g. necessary when some
+ // processes share a window hierarchy), but may cause re-entrancy issues in
+ // some cases where such loops are not possible. This flags allows the tagging
+ // of some particular channels to not re-enter in such cases.
+ void SetRestrictDispatchToSameChannel(bool value);
+
+ protected:
+ class ReceivedSyncMsgQueue;
+ friend class ReceivedSyncMsgQueue;
+
+ // SyncContext holds the per object data for SyncChannel, so that SyncChannel
+ // can be deleted while it's being used in a different thread. See
+ // ChannelProxy::Context for more information.
+ class SyncContext : public Context,
+ public base::WaitableEventWatcher::Delegate {
+ public:
+ SyncContext(Channel::Listener* listener,
+ base::MessageLoopProxy* ipc_thread,
+ base::WaitableEvent* shutdown_event);
+
+ // Adds information about an outgoing sync message to the context so that
+ // we know how to deserialize the reply.
+ void Push(SyncMessage* sync_msg);
+
+ // Cleanly remove the top deserializer (and throw it away). Returns the
+ // result of the Send call for that message.
+ bool Pop();
+
+ // Returns an event that's set when the send is complete, timed out or the
+ // process shut down.
+ base::WaitableEvent* GetSendDoneEvent();
+
+ // Returns an event that's set when an incoming message that's not the reply
+ // needs to get dispatched (by calling SyncContext::DispatchMessages).
+ base::WaitableEvent* GetDispatchEvent();
+
+ void DispatchMessages();
+
+ // Checks if the given message is blocking the listener thread because of a
+ // synchronous send. If it is, the thread is unblocked and true is
+ // returned. Otherwise the function returns false.
+ bool TryToUnblockListener(const Message* msg);
+
+ // Called on the IPC thread when a sync send that runs a nested message loop
+ // times out.
+ void OnSendTimeout(int message_id);
+
+ base::WaitableEvent* shutdown_event() { return shutdown_event_; }
+
+ ReceivedSyncMsgQueue* received_sync_msgs() {
+ return received_sync_msgs_;
+ }
+
+ void set_restrict_dispatch(bool value) { restrict_dispatch_ = value; }
+ bool restrict_dispatch() const { return restrict_dispatch_; }
+
+ private:
+ virtual ~SyncContext();
+ // ChannelProxy methods that we override.
+
+ // Called on the listener thread.
+ virtual void Clear();
+
+ // Called on the IPC thread.
+ virtual bool OnMessageReceived(const Message& msg);
+ virtual void OnChannelError();
+ virtual void OnChannelOpened();
+ virtual void OnChannelClosed();
+
+ // Cancels all pending Send calls.
+ void CancelPendingSends();
+
+ // WaitableEventWatcher::Delegate implementation.
+ virtual void OnWaitableEventSignaled(base::WaitableEvent* arg);
+
+ typedef std::deque<PendingSyncMsg> PendingSyncMessageQueue;
+ PendingSyncMessageQueue deserializers_;
+ base::Lock deserializers_lock_;
+
+ scoped_refptr<ReceivedSyncMsgQueue> received_sync_msgs_;
+
+ base::WaitableEvent* shutdown_event_;
+ base::WaitableEventWatcher shutdown_watcher_;
+ bool restrict_dispatch_;
+ };
+
+ private:
+ // WaitableEventWatcher::Delegate implementation.
+ virtual void OnWaitableEventSignaled(base::WaitableEvent* arg);
+
+ SyncContext* sync_context() {
+ return reinterpret_cast<SyncContext*>(context());
+ }
+
+ // Both these functions wait for a reply, timeout or process shutdown. The
+ // latter one also runs a nested message loop in the meantime.
+ static void WaitForReply(
+ SyncContext* context, base::WaitableEvent* pump_messages_event);
+
+ // Runs a nested message loop until a reply arrives, times out, or the process
+ // shuts down.
+ static void WaitForReplyWithNestedMessageLoop(SyncContext* context);
+
+ bool sync_messages_with_no_timeout_allowed_;
+
+ // Used to signal events between the IPC and listener threads.
+ base::WaitableEventWatcher dispatch_watcher_;
+
+ DISALLOW_COPY_AND_ASSIGN(SyncChannel);
+};
+
+} // namespace IPC
+
+#endif // IPC_IPC_SYNC_SENDER_H__
diff --git a/ipc/ipc_sync_message.cc b/ipc/ipc_sync_message.cc
new file mode 100644
index 000000000000..3a36bf327160
--- /dev/null
+++ b/ipc/ipc_sync_message.cc
@@ -0,0 +1,130 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+#include <stack>
+
+#include "base/atomic_sequence_num.h"
+//#include "base/logging.h"
+#include "log.h"
+#include "base/synchronization/waitable_event.h"
+#include "ipc/ipc_sync_message.h"
+
+namespace IPC {
+
+#define kSyncMessageHeaderSize 4
+
+static base::AtomicSequenceNumber g_next_id(base::LINKER_INITIALIZED);
+
+ static base::WaitableEvent* dummy_event = NULL; //new base::WaitableEvent(true, true);
+
+SyncMessage::SyncMessage(
+ int32 routing_id,
+ uint32 type,
+ PriorityValue priority,
+ MessageReplyDeserializer* deserializer)
+ : Message(routing_id, type, priority),
+ deserializer_(deserializer),
+ pump_messages_event_(NULL)
+ {
+ set_sync();
+ set_unblock(true);
+
+
+ // Add synchronous message data before the message payload.
+ SyncHeader header;
+ header.message_id = g_next_id.GetNext();
+ WriteSyncHeader(this, header);
+}
+
+MessageReplyDeserializer* SyncMessage::GetReplyDeserializer() {
+ MessageReplyDeserializer* rv = deserializer_;
+ DCHECK(rv);
+ deserializer_ = NULL;
+ return rv;
+}
+
+void SyncMessage::EnableMessagePumping() {
+ DCHECK(!pump_messages_event_);
+ set_pump_messages_event(dummy_event);
+}
+
+bool SyncMessage::IsMessageReplyTo(const Message& msg, int request_id) {
+ if (!msg.is_reply())
+ return false;
+
+ return GetMessageId(msg) == request_id;
+}
+
+void* SyncMessage::GetDataIterator(const Message* msg) {
+ void* iter = const_cast<char*>(msg->payload());
+ UpdateIter(&iter, kSyncMessageHeaderSize);
+ return iter;
+}
+
+int SyncMessage::GetMessageId(const Message& msg) {
+ if (!msg.is_sync() && !msg.is_reply())
+ return 0;
+
+ SyncHeader header;
+ if (!ReadSyncHeader(msg, &header))
+ return 0;
+
+ return header.message_id;
+}
+
+Message* SyncMessage::GenerateReply(const Message* msg) {
+ DCHECK(msg->is_sync()) << "is_sync(" << msg->is_sync() <<")"<<std::endl;
+
+ Message* reply = new Message(msg->routing_id(), IPC_REPLY_ID,
+ msg->priority());
+ reply->set_reply();
+
+ SyncHeader header;
+
+ // use the same message id, but this time reply bit is set
+ header.message_id = GetMessageId(*msg);
+ WriteSyncHeader(reply, header);
+
+ return reply;
+}
+
+bool SyncMessage::ReadSyncHeader(const Message& msg, SyncHeader* header) {
+ DCHECK(msg.is_sync() || msg.is_reply());
+
+ void* iter = NULL;
+ bool result = msg.ReadInt(&iter, &header->message_id);
+ if (!result) {
+ NOTREACHED();
+ return false;
+ }
+
+ return true;
+}
+
+bool SyncMessage::WriteSyncHeader(Message* msg, const SyncHeader& header) {
+ DCHECK(msg->is_sync() || msg->is_reply());
+ DCHECK(msg->payload_size() == 0);
+ bool result = msg->WriteInt(header.message_id);
+ if (!result) {
+ NOTREACHED();
+ return false;
+ }
+
+ // Note: if you add anything here, you need to update kSyncMessageHeaderSize.
+ DCHECK(kSyncMessageHeaderSize == msg->payload_size());
+
+ return true;
+}
+
+
+bool MessageReplyDeserializer::SerializeOutputParameters(const Message& msg) {
+ return SerializeOutputParameters(msg, SyncMessage::GetDataIterator(&msg));
+}
+
+} // namespace IPC
diff --git a/ipc/ipc_sync_message.h b/ipc/ipc_sync_message.h
new file mode 100644
index 000000000000..2c6ed8b7c483
--- /dev/null
+++ b/ipc/ipc_sync_message.h
@@ -0,0 +1,109 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IPC_IPC_SYNC_MESSAGE_H_
+#define IPC_IPC_SYNC_MESSAGE_H_
+#pragma once
+
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
+#include <string>
+#include "base/basictypes.h"
+#include "ipc/ipc_message.h"
+
+namespace base {
+class WaitableEvent;
+}
+
+namespace IPC {
+
+class MessageReplyDeserializer;
+
+class IPC_EXPORT SyncMessage : public Message {
+ public:
+ SyncMessage(int32 routing_id, uint32 type, PriorityValue priority,
+ MessageReplyDeserializer* deserializer);
+
+ // Call this to get a deserializer for the output parameters.
+ // Note that this can only be called once, and the caller is responsible
+ // for deleting the deserializer when they're done.
+ MessageReplyDeserializer* GetReplyDeserializer();
+
+ // If this message can cause the receiver to block while waiting for user
+ // input (i.e. by calling MessageBox), then the caller needs to pump window
+ // messages and dispatch asynchronous messages while waiting for the reply.
+ // If this event is passed in, then window messages will start being pumped
+ // when it's set. Note that this behavior will continue even if the event is
+ // later reset. The event must be valid until after the Send call returns.
+ void set_pump_messages_event(base::WaitableEvent* event) {
+ pump_messages_event_ = event;
+ if (event) {
+ header()->flags |= PUMPING_MSGS_BIT;
+ } else {
+ header()->flags &= ~PUMPING_MSGS_BIT;
+ }
+ }
+
+ // Call this if you always want to pump messages. You can call this method
+ // or set_pump_messages_event but not both.
+ void EnableMessagePumping();
+
+ base::WaitableEvent* pump_messages_event() const {
+ return pump_messages_event_;
+ }
+
+ // Returns true if the message is a reply to the given request id.
+ static bool IsMessageReplyTo(const Message& msg, int request_id);
+
+ // Given a reply message, returns an iterator to the beginning of the data
+ // (i.e. skips over the synchronous specific data).
+ static void* GetDataIterator(const Message* msg);
+
+ // Given a synchronous message (or its reply), returns its id.
+ static int GetMessageId(const Message& msg);
+
+ // Generates a reply message to the given message.
+ static Message* GenerateReply(const Message* msg);
+
+ private:
+ struct SyncHeader {
+ // unique ID (unique per sender)
+ int message_id;
+ };
+
+ static bool ReadSyncHeader(const Message& msg, SyncHeader* header);
+ static bool WriteSyncHeader(Message* msg, const SyncHeader& header);
+
+ MessageReplyDeserializer* deserializer_;
+ base::WaitableEvent* pump_messages_event_;
+};
+
+// Used to deserialize parameters from a reply to a synchronous message
+class IPC_EXPORT MessageReplyDeserializer {
+ public:
+ virtual ~MessageReplyDeserializer() {}
+ bool SerializeOutputParameters(const Message& msg);
+ private:
+ // Derived classes need to implement this, using the given iterator (which
+ // is skipped past the header for synchronous messages).
+ virtual bool SerializeOutputParameters(const Message& msg, void* iter) = 0;
+};
+
+// When sending a synchronous message, this structure contains an object
+// that knows how to deserialize the response.
+struct PendingSyncMsg {
+ PendingSyncMsg(int id,
+ MessageReplyDeserializer* d,
+ base::WaitableEvent* e)
+ : id(id), deserializer(d), done_event(e), send_result(false) { }
+ int id;
+ MessageReplyDeserializer* deserializer;
+ base::WaitableEvent* done_event;
+ bool send_result;
+};
+
+} // namespace IPC
+
+#endif // IPC_IPC_SYNC_MESSAGE_H_
diff --git a/ipc/ipc_sync_message_filter.cc b/ipc/ipc_sync_message_filter.cc
new file mode 100644
index 000000000000..cffbaa674aed
--- /dev/null
+++ b/ipc/ipc_sync_message_filter.cc
@@ -0,0 +1,127 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ipc/ipc_sync_message_filter.h"
+
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "base/synchronization/waitable_event.h"
+#include "ipc/ipc_sync_message.h"
+
+namespace IPC {
+
+SyncMessageFilter::SyncMessageFilter(base::WaitableEvent* shutdown_event)
+ : channel_(NULL),
+ listener_loop_(MessageLoop::current()),
+ io_loop_(NULL),
+ shutdown_event_(shutdown_event) {
+}
+
+SyncMessageFilter::~SyncMessageFilter() {
+}
+
+bool SyncMessageFilter::Send(Message* message) {
+ {
+ base::AutoLock auto_lock(lock_);
+ if (!io_loop_) {
+ delete message;
+ return false;
+ }
+ }
+
+ if (!message->is_sync()) {
+ io_loop_->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &SyncMessageFilter::SendOnIOThread, message));
+ return true;
+ }
+
+ base::WaitableEvent done_event(true, false);
+ PendingSyncMsg pending_message(
+ SyncMessage::GetMessageId(*message),
+ reinterpret_cast<SyncMessage*>(message)->GetReplyDeserializer(),
+ &done_event);
+
+ {
+ base::AutoLock auto_lock(lock_);
+ // Can't use this class on the main thread or else it can lead to deadlocks.
+ // Also by definition, can't use this on IO thread since we're blocking it.
+ DCHECK(MessageLoop::current() != listener_loop_);
+ DCHECK(MessageLoop::current() != io_loop_);
+ pending_sync_messages_.insert(&pending_message);
+ }
+
+ io_loop_->PostTask(
+ FROM_HERE,
+ NewRunnableMethod(this, &SyncMessageFilter::SendOnIOThread, message));
+
+ base::WaitableEvent* events[2] = { shutdown_event_, &done_event };
+ base::WaitableEvent::WaitMany(events, 2);
+
+ {
+ base::AutoLock auto_lock(lock_);
+ delete pending_message.deserializer;
+ pending_sync_messages_.erase(&pending_message);
+ }
+
+ return pending_message.send_result;
+}
+
+void SyncMessageFilter::SendOnIOThread(Message* message) {
+ if (channel_) {
+ channel_->Send(message);
+ return;
+ }
+
+ if (message->is_sync()) {
+ // We don't know which thread sent it, but it doesn't matter, just signal
+ // them all.
+ SignalAllEvents();
+ }
+
+ delete message;
+}
+
+void SyncMessageFilter::SignalAllEvents() {
+ base::AutoLock auto_lock(lock_);
+ for (PendingSyncMessages::iterator iter = pending_sync_messages_.begin();
+ iter != pending_sync_messages_.end(); ++iter) {
+ (*iter)->done_event->Signal();
+ }
+}
+
+void SyncMessageFilter::OnFilterAdded(Channel* channel) {
+ channel_ = channel;
+ base::AutoLock auto_lock(lock_);
+ io_loop_ = MessageLoop::current();
+}
+
+void SyncMessageFilter::OnChannelError() {
+ channel_ = NULL;
+ SignalAllEvents();
+}
+
+void SyncMessageFilter::OnChannelClosing() {
+ channel_ = NULL;
+ SignalAllEvents();
+}
+
+bool SyncMessageFilter::OnMessageReceived(const Message& message) {
+ base::AutoLock auto_lock(lock_);
+ for (PendingSyncMessages::iterator iter = pending_sync_messages_.begin();
+ iter != pending_sync_messages_.end(); ++iter) {
+ if (SyncMessage::IsMessageReplyTo(message, (*iter)->id)) {
+ if (!message.is_reply_error()) {
+ (*iter)->send_result =
+ (*iter)->deserializer->SerializeOutputParameters(message);
+ }
+ (*iter)->done_event->Signal();
+ return true;
+ }
+ }
+
+ return false;
+}
+
+} // namespace IPC
diff --git a/ipc/ipc_sync_message_filter.h b/ipc/ipc_sync_message_filter.h
new file mode 100644
index 000000000000..0dc471adacd3
--- /dev/null
+++ b/ipc/ipc_sync_message_filter.h
@@ -0,0 +1,70 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IPC_IPC_SYNC_MESSAGE_FILTER_H_
+#define IPC_IPC_SYNC_MESSAGE_FILTER_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/synchronization/lock.h"
+#include "ipc/ipc_channel_proxy.h"
+#include "ipc/ipc_sync_message.h"
+#include <set>
+
+namespace base {
+class WaitableEvent;
+}
+
+class MessageLoop;
+
+namespace IPC {
+
+class MessageReplyDeserializer;
+
+// This MessageFilter allows sending synchronous IPC messages from a thread
+// other than the listener thread associated with the SyncChannel. It does not
+// support fancy features that SyncChannel does, such as handling recursion or
+// receiving messages while waiting for a response. Note that this object can
+// be used to send simultaneous synchronous messages from different threads.
+class IPC_EXPORT SyncMessageFilter : public ChannelProxy::MessageFilter,
+ public Message::Sender {
+ public:
+ explicit SyncMessageFilter(base::WaitableEvent* shutdown_event);
+ virtual ~SyncMessageFilter();
+
+ // Message::Sender implementation.
+ virtual bool Send(Message* message);
+
+ // ChannelProxy::MessageFilter implementation.
+ virtual void OnFilterAdded(Channel* channel);
+ virtual void OnChannelError();
+ virtual void OnChannelClosing();
+ virtual bool OnMessageReceived(const Message& message);
+
+ private:
+ void SendOnIOThread(Message* message);
+ // Signal all the pending sends as done, used in an error condition.
+ void SignalAllEvents();
+
+ // The channel to which this filter was added.
+ Channel* channel_;
+
+ MessageLoop* listener_loop_; // The process's main thread.
+ MessageLoop* io_loop_; // The message loop where the Channel lives.
+
+ typedef std::set<PendingSyncMsg*> PendingSyncMessages;
+ PendingSyncMessages pending_sync_messages_;
+
+ // Locks data members above.
+ base::Lock lock_;
+
+ base::WaitableEvent* shutdown_event_;
+
+ DISALLOW_COPY_AND_ASSIGN(SyncMessageFilter);
+};
+
+} // namespace IPC
+
+#endif // IPC_IPC_SYNC_MESSAGE_FILTER_H_
diff --git a/ipc/param_traits_log_macros.h b/ipc/param_traits_log_macros.h
new file mode 100644
index 000000000000..8259a0d0a0bd
--- /dev/null
+++ b/ipc/param_traits_log_macros.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IPC_PARAM_TRAITS_LOG_MACROS_H_
+#define IPC_PARAM_TRAITS_LOG_MACROS_H_
+#pragma once
+
+#include <string>
+
+// Null out all the macros that need nulling.
+#include "ipc/ipc_message_null_macros.h"
+
+// STRUCT declarations cause corresponding STRUCT_TRAITS declarations to occur.
+#undef IPC_STRUCT_BEGIN
+#undef IPC_STRUCT_MEMBER
+#undef IPC_STRUCT_END
+#define IPC_STRUCT_BEGIN(struct_name) IPC_STRUCT_TRAITS_BEGIN(struct_name)
+#define IPC_STRUCT_MEMBER(type, name) IPC_STRUCT_TRAITS_MEMBER(name)
+#define IPC_STRUCT_END() IPC_STRUCT_TRAITS_END()
+
+// Set up so next include will generate log methods.
+#undef IPC_STRUCT_TRAITS_BEGIN
+#undef IPC_STRUCT_TRAITS_MEMBER
+#undef IPC_STRUCT_TRAITS_PARENT
+#undef IPC_STRUCT_TRAITS_END
+#define IPC_STRUCT_TRAITS_BEGIN(struct_name) \
+ void ParamTraits<struct_name>::Log(const param_type& p, std::string* l) { \
+ bool needs_comma = false; \
+ l->append("(");
+#define IPC_STRUCT_TRAITS_MEMBER(name) \
+ if (needs_comma) \
+ l->append(", "); \
+ LogParam(p.name, l); \
+ needs_comma = true;
+#define IPC_STRUCT_TRAITS_PARENT(type) \
+ if (needs_comma) \
+ l->append(", "); \
+ ParamTraits<type>::Log(p, l); \
+ needs_comma = true;
+#define IPC_STRUCT_TRAITS_END() \
+ l->append(")"); \
+ }
+
+#undef IPC_ENUM_TRAITS
+#define IPC_ENUM_TRAITS(enum_name) \
+ void ParamTraits<enum_name>::Log(const param_type& p, std::string* l) { \
+ LogParam(static_cast<int>(p), l); \
+ }
+
+#endif // IPC_PARAM_TRAITS_LOG_MACROS_H_
+
diff --git a/ipc/param_traits_macros.h b/ipc/param_traits_macros.h
new file mode 100644
index 000000000000..df57adfb32e0
--- /dev/null
+++ b/ipc/param_traits_macros.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IPC_PARAM_TRAITS_MACROS_H_
+#define IPC_PARAM_TRAITS_MACROS_H_
+
+#include <string>
+
+// Traits generation for structs.
+#define IPC_STRUCT_TRAITS_BEGIN(struct_name) \
+ namespace IPC { \
+ template <> \
+ struct ParamTraits<struct_name> { \
+ typedef struct_name param_type; \
+ static void Write(Message* m, const param_type& p); \
+ static bool Read(const Message* m, void** iter, param_type* p); \
+ static void Log(const param_type& p, std::string* l); \
+ }; \
+ }
+
+#define IPC_STRUCT_TRAITS_MEMBER(name)
+#define IPC_STRUCT_TRAITS_PARENT(type)
+#define IPC_STRUCT_TRAITS_END()
+
+// Traits generation for enums.
+#define IPC_ENUM_TRAITS(enum_name) \
+ namespace IPC { \
+ template <> \
+ struct ParamTraits<enum_name> { \
+ typedef enum_name param_type; \
+ static void Write(Message* m, const param_type& p); \
+ static bool Read(const Message* m, void** iter, param_type* p); \
+ static void Log(const param_type& p, std::string* l); \
+ }; \
+ }
+
+#endif // IPC_PARAM_TRAITS_MACROS_H_
+
diff --git a/ipc/param_traits_read_macros.h b/ipc/param_traits_read_macros.h
new file mode 100644
index 000000000000..f0b88bc7ebe3
--- /dev/null
+++ b/ipc/param_traits_read_macros.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IPC_PARAM_TRAITS_READ_MACROS_H_
+#define IPC_PARAM_TRAITS_READ_MACROS_H_
+#pragma once
+
+// Null out all the macros that need nulling.
+#include "ipc/ipc_message_null_macros.h"
+
+// STRUCT declarations cause corresponding STRUCT_TRAITS declarations to occur.
+#undef IPC_STRUCT_BEGIN
+#undef IPC_STRUCT_MEMBER
+#undef IPC_STRUCT_END
+#define IPC_STRUCT_BEGIN(struct_name) IPC_STRUCT_TRAITS_BEGIN(struct_name)
+#define IPC_STRUCT_MEMBER(type, name) IPC_STRUCT_TRAITS_MEMBER(name)
+#define IPC_STRUCT_END() IPC_STRUCT_TRAITS_END()
+
+// Set up so next include will generate read methods.
+#undef IPC_STRUCT_TRAITS_BEGIN
+#undef IPC_STRUCT_TRAITS_MEMBER
+#undef IPC_STRUCT_TRAITS_PARENT
+#undef IPC_STRUCT_TRAITS_END
+#define IPC_STRUCT_TRAITS_BEGIN(struct_name) \
+ bool ParamTraits<struct_name>:: \
+ Read(const Message* m, void** iter, param_type* p) { \
+ return
+#define IPC_STRUCT_TRAITS_MEMBER(name) ReadParam(m, iter, &p->name) &&
+#define IPC_STRUCT_TRAITS_PARENT(type) ParamTraits<type>::Read(m, iter, p) &&
+#define IPC_STRUCT_TRAITS_END() 1; }
+
+#undef IPC_ENUM_TRAITS
+#define IPC_ENUM_TRAITS(enum_name) \
+ bool ParamTraits<enum_name>:: \
+ Read(const Message* m, void** iter, param_type* p) { \
+ int type; \
+ if (!m->ReadInt(iter, &type)) \
+ return false; \
+ *p = static_cast<param_type>(type); \
+ return true; \
+ }
+
+#endif // IPC_PARAM_TRAITS_READ_MACROS_H_
+
diff --git a/ipc/param_traits_write_macros.h b/ipc/param_traits_write_macros.h
new file mode 100644
index 000000000000..844c3855eb72
--- /dev/null
+++ b/ipc/param_traits_write_macros.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IPC_PARAM_TRAITS_WRITE_MACROS_H_
+#define IPC_PARAM_TRAITS_WRITE_MACROS_H_
+#pragma once
+
+// Null out all the macros that need nulling.
+#include "ipc/ipc_message_null_macros.h"
+
+// STRUCT declarations cause corresponding STRUCT_TRAITS declarations to occur.
+#undef IPC_STRUCT_BEGIN
+#undef IPC_STRUCT_MEMBER
+#undef IPC_STRUCT_END
+#define IPC_STRUCT_BEGIN(struct_name) IPC_STRUCT_TRAITS_BEGIN(struct_name)
+#define IPC_STRUCT_MEMBER(type, name) IPC_STRUCT_TRAITS_MEMBER(name)
+#define IPC_STRUCT_END() IPC_STRUCT_TRAITS_END()
+
+// Set up so next include will generate write methods.
+#undef IPC_STRUCT_TRAITS_BEGIN
+#undef IPC_STRUCT_TRAITS_MEMBER
+#undef IPC_STRUCT_TRAITS_PARENT
+#undef IPC_STRUCT_TRAITS_END
+#define IPC_STRUCT_TRAITS_BEGIN(struct_name) \
+ void ParamTraits<struct_name>::Write(Message* m, const param_type& p) {
+#define IPC_STRUCT_TRAITS_MEMBER(name) WriteParam(m, p.name);
+#define IPC_STRUCT_TRAITS_PARENT(type) ParamTraits<type>::Write(m, p);
+#define IPC_STRUCT_TRAITS_END() }
+
+#undef IPC_ENUM_TRAITS
+#define IPC_ENUM_TRAITS(enum_name) \
+ void ParamTraits<enum_name>::Write(Message* m, const param_type& p) { \
+ m->WriteInt(static_cast<int>(p)); \
+ }
+
+#endif // IPC_PARAM_TRAITS_WRITE_MACROS_H_
+
diff --git a/ipc/struct_constructor_macros.h b/ipc/struct_constructor_macros.h
new file mode 100644
index 000000000000..67bfcfb6e2ae
--- /dev/null
+++ b/ipc/struct_constructor_macros.h
@@ -0,0 +1,20 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IPC_STRUCT_CONSTRUCTOR_MACROS_H_
+#define IPC_STRUCT_CONSTRUCTOR_MACROS_H_
+
+// Null out all the macros that need nulling.
+#include "ipc/ipc_message_null_macros.h"
+
+// Set up so next include will generate constructors.
+#undef IPC_STRUCT_BEGIN
+#undef IPC_STRUCT_MEMBER
+#undef IPC_STRUCT_END
+#define IPC_STRUCT_BEGIN(struct_name) struct_name::struct_name() : NoParams()
+#define IPC_STRUCT_MEMBER(type, name) , name()
+#define IPC_STRUCT_END() {}
+
+#endif // IPC_STRUCT_CONSTRUCTOR_MACROS_H_
+
diff --git a/ipc/struct_destructor_macros.h b/ipc/struct_destructor_macros.h
new file mode 100644
index 000000000000..bf3dc953bcb6
--- /dev/null
+++ b/ipc/struct_destructor_macros.h
@@ -0,0 +1,16 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IPC_STRUCT_DESTRUCTOR_MACROS_H_
+#define IPC_STRUCT_DESTRUCTOR_MACROS_H_
+
+// Null out all the macros that need nulling.
+#include "ipc/ipc_message_null_macros.h"
+
+// Set up so next include will generate destructors.
+#undef IPC_STRUCT_BEGIN
+#define IPC_STRUCT_BEGIN(struct_name) struct_name::~struct_name() {}
+
+#endif // IPC_STRUCT_DESTRUCTOR_MACROS_H_
+
diff --git a/ipc/sync_socket_unittest.cc b/ipc/sync_socket_unittest.cc
new file mode 100644
index 000000000000..1a4ae13d89cd
--- /dev/null
+++ b/ipc/sync_socket_unittest.cc
@@ -0,0 +1,250 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/sync_socket.h"
+
+#include <stdio.h>
+#include <string>
+#include <sstream>
+
+#include "base/message_loop.h"
+#include "base/process_util.h"
+#include "build/build_config.h"
+#include "ipc/ipc_channel.h"
+#include "ipc/ipc_channel_proxy.h"
+#include "ipc/ipc_message_macros.h"
+#include "ipc/ipc_message_utils.h"
+#include "ipc/ipc_message_utils_impl.h"
+#include "ipc/ipc_tests.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
+
+#if defined(OS_POSIX)
+#include "base/file_descriptor_posix.h"
+#endif
+
+enum IPCMessageIds {
+ UNUSED_IPC_TYPE,
+ SERVER_FIRST_IPC_TYPE, // SetHandle message sent to server.
+ SERVER_SECOND_IPC_TYPE, // Shutdown message sent to server.
+ CLIENT_FIRST_IPC_TYPE // Response message sent to client.
+};
+
+namespace {
+const char kHelloString[] = "Hello, SyncSocket Client";
+const size_t kHelloStringLength = arraysize(kHelloString);
+} // namespace
+
+// Message class to pass a base::SyncSocket::Handle to another process.
+// This is not as easy as it sounds, because of the differences in transferring
+// Windows HANDLEs versus posix file descriptors.
+#if defined(OS_WIN)
+class MsgClassSetHandle
+ : public IPC::MessageWithTuple< Tuple1<base::SyncSocket::Handle> > {
+ public:
+ enum { ID = SERVER_FIRST_IPC_TYPE };
+ explicit MsgClassSetHandle(const base::SyncSocket::Handle arg1)
+ : IPC::MessageWithTuple< Tuple1<base::SyncSocket::Handle> >(
+ MSG_ROUTING_CONTROL, ID, MakeRefTuple(arg1)) {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MsgClassSetHandle);
+};
+#elif defined(OS_POSIX)
+class MsgClassSetHandle
+ : public IPC::MessageWithTuple< Tuple1<base::FileDescriptor> > {
+ public:
+ enum { ID = SERVER_FIRST_IPC_TYPE };
+ explicit MsgClassSetHandle(const base::FileDescriptor& arg1)
+ : IPC::MessageWithTuple< Tuple1<base::FileDescriptor> >(
+ MSG_ROUTING_CONTROL, ID, MakeRefTuple(arg1)) {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MsgClassSetHandle);
+};
+#else
+# error "What platform?"
+#endif // defined(OS_WIN)
+
+// Message class to pass a response to the server.
+class MsgClassResponse
+ : public IPC::MessageWithTuple< Tuple1<std::string> > {
+ public:
+ enum { ID = CLIENT_FIRST_IPC_TYPE };
+ explicit MsgClassResponse(const std::string& arg1)
+ : IPC::MessageWithTuple< Tuple1<std::string> >(
+ MSG_ROUTING_CONTROL, ID, MakeRefTuple(arg1)) {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MsgClassResponse);
+};
+
+// Message class to tell the server to shut down.
+class MsgClassShutdown
+ : public IPC::MessageWithTuple< Tuple0 > {
+ public:
+ enum { ID = SERVER_SECOND_IPC_TYPE };
+ MsgClassShutdown()
+ : IPC::MessageWithTuple< Tuple0 >(
+ MSG_ROUTING_CONTROL, ID, MakeTuple()) {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MsgClassShutdown);
+};
+
+// The SyncSocket server listener class processes two sorts of
+// messages from the client.
+class SyncSocketServerListener : public IPC::Channel::Listener {
+ public:
+ SyncSocketServerListener() : chan_(NULL) {
+ }
+
+ void Init(IPC::Channel* chan) {
+ chan_ = chan;
+ }
+
+ virtual bool OnMessageReceived(const IPC::Message& msg) {
+ if (msg.routing_id() == MSG_ROUTING_CONTROL) {
+ IPC_BEGIN_MESSAGE_MAP(SyncSocketServerListener, msg)
+ IPC_MESSAGE_HANDLER(MsgClassSetHandle, OnMsgClassSetHandle)
+ IPC_MESSAGE_HANDLER(MsgClassShutdown, OnMsgClassShutdown)
+ IPC_END_MESSAGE_MAP()
+ }
+ return true;
+ }
+
+ private:
+ // This sort of message is sent first, causing the transfer of
+ // the handle for the SyncSocket. This message sends a buffer
+ // on the SyncSocket and then sends a response to the client.
+#if defined(OS_WIN)
+ void OnMsgClassSetHandle(const base::SyncSocket::Handle handle) {
+ SetHandle(handle);
+ }
+#elif defined(OS_POSIX)
+ void OnMsgClassSetHandle(const base::FileDescriptor& fd_struct) {
+ SetHandle(fd_struct.fd);
+ }
+#else
+# error "What platform?"
+#endif // defined(OS_WIN)
+
+ void SetHandle(base::SyncSocket::Handle handle) {
+ base::SyncSocket sync_socket(handle);
+ EXPECT_EQ(sync_socket.Send(static_cast<const void*>(kHelloString),
+ kHelloStringLength), kHelloStringLength);
+ IPC::Message* msg = new MsgClassResponse(kHelloString);
+ EXPECT_TRUE(chan_->Send(msg));
+ }
+
+ // When the client responds, it sends back a shutdown message,
+ // which causes the message loop to exit.
+ void OnMsgClassShutdown() {
+ MessageLoop::current()->Quit();
+ }
+
+ IPC::Channel* chan_;
+
+ DISALLOW_COPY_AND_ASSIGN(SyncSocketServerListener);
+};
+
+// Runs the fuzzing server child mode. Returns when the preset number
+// of messages have been received.
+MULTIPROCESS_TEST_MAIN(RunSyncSocketServer) {
+ MessageLoopForIO main_message_loop;
+ SyncSocketServerListener listener;
+ IPC::Channel chan(kSyncSocketChannel, IPC::Channel::MODE_CLIENT, &listener);
+ EXPECT_TRUE(chan.Connect());
+ listener.Init(&chan);
+ MessageLoop::current()->Run();
+ return 0;
+}
+
+// The SyncSocket client listener only processes one sort of message,
+// a response from the server.
+class SyncSocketClientListener : public IPC::Channel::Listener {
+ public:
+ SyncSocketClientListener() {
+ }
+
+ void Init(base::SyncSocket* socket, IPC::Channel* chan) {
+ socket_ = socket;
+ chan_ = chan;
+ }
+
+ virtual bool OnMessageReceived(const IPC::Message& msg) {
+ if (msg.routing_id() == MSG_ROUTING_CONTROL) {
+ IPC_BEGIN_MESSAGE_MAP(SyncSocketClientListener, msg)
+ IPC_MESSAGE_HANDLER(MsgClassResponse, OnMsgClassResponse)
+ IPC_END_MESSAGE_MAP()
+ }
+ return true;
+ }
+
+ private:
+ // When a response is received from the server, it sends the same
+ // string as was written on the SyncSocket. These are compared
+ // and a shutdown message is sent back to the server.
+ void OnMsgClassResponse(const std::string& str) {
+ // We rely on the order of sync_socket.Send() and chan_->Send() in
+ // the SyncSocketServerListener object.
+ EXPECT_EQ(kHelloStringLength, socket_->Peek());
+ char buf[kHelloStringLength];
+ socket_->Receive(static_cast<void*>(buf), kHelloStringLength);
+ EXPECT_EQ(strcmp(str.c_str(), buf), 0);
+ // After receiving from the socket there should be no bytes left.
+ EXPECT_EQ(0U, socket_->Peek());
+ IPC::Message* msg = new MsgClassShutdown();
+ EXPECT_TRUE(chan_->Send(msg));
+ MessageLoop::current()->Quit();
+ }
+
+ base::SyncSocket* socket_;
+ IPC::Channel* chan_;
+
+ DISALLOW_COPY_AND_ASSIGN(SyncSocketClientListener);
+};
+
+class SyncSocketTest : public IPCChannelTest {
+};
+
+TEST_F(SyncSocketTest, SanityTest) {
+ SyncSocketClientListener listener;
+ IPC::Channel chan(kSyncSocketChannel, IPC::Channel::MODE_SERVER,
+ &listener);
+ base::ProcessHandle server_process = SpawnChild(SYNC_SOCKET_SERVER, &chan);
+ ASSERT_TRUE(server_process);
+ // Create a pair of SyncSockets.
+ base::SyncSocket* pair[2];
+ base::SyncSocket::CreatePair(pair);
+ // Immediately after creation there should be no pending bytes.
+ EXPECT_EQ(0U, pair[0]->Peek());
+ EXPECT_EQ(0U, pair[1]->Peek());
+ base::SyncSocket::Handle target_handle;
+ // Connect the channel and listener.
+ ASSERT_TRUE(chan.Connect());
+ listener.Init(pair[0], &chan);
+#if defined(OS_WIN)
+ // On windows we need to duplicate the handle into the server process.
+ BOOL retval = DuplicateHandle(GetCurrentProcess(), pair[1]->handle(),
+ server_process, &target_handle,
+ 0, FALSE, DUPLICATE_SAME_ACCESS);
+ EXPECT_TRUE(retval);
+ // Set up a message to pass the handle to the server.
+ IPC::Message* msg = new MsgClassSetHandle(target_handle);
+#else
+ target_handle = pair[1]->handle();
+ // Set up a message to pass the handle to the server.
+ base::FileDescriptor filedesc(target_handle, false);
+ IPC::Message* msg = new MsgClassSetHandle(filedesc);
+#endif // defined(OS_WIN)
+ EXPECT_TRUE(chan.Send(msg));
+ // Use the current thread as the I/O thread.
+ MessageLoop::current()->Run();
+ // Shut down.
+ delete pair[0];
+ delete pair[1];
+ EXPECT_TRUE(base::WaitForSingleProcess(server_process, 5000));
+ base::CloseProcessHandle(server_process);
+}
diff --git a/log.h b/log.h
new file mode 100644
index 000000000000..90f87eb33876
--- /dev/null
+++ b/log.h
@@ -0,0 +1,26 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_LOGGING_H_
+#define BASE_LOGGING_H_
+#pragma once
+
+//namespace logging {
+#define DCHECK(x) if (!(x)) std::cout << "Check failed"
+#define CHECK(x) if (!(x)) std::cout << "Check failed"
+#define NOTREACHED() std::cout << "Not reached"
+#define DCHECK_EQ(x, y) if ((x) != (y)) std::cout << "Check failed"
+#define DCHECK_LE(x, y) if ((x) > (y)) std::cout << "Check failed"
+#define DCHECK_GE(x, y) if ((x) < (y)) std::cout << "Check failed"
+#define DCHECK_NE(x, y) if ((x) == (y)) std::cout << "Check failed"
+#define CHECK_NE(x, y) if ((x) == (y)) std::cout << "Check failed"
+//#define MAX(x,y) ((x) > (y) ? (x) : (y))
+
+#ifndef WARN_UNUSED_RESULT
+//#define WARN_UNUSED_RESULT
+#endif
+
+//} // namespace base
+
+#endif // BASE_LOGGING_H_
diff --git a/packaging/chromium.spec b/packaging/chromium.spec
new file mode 100755
index 000000000000..c2d7659b80fe
--- /dev/null
+++ b/packaging/chromium.spec
@@ -0,0 +1,54 @@
+Name: chromium
+Summary: chromium library
+Version: 1.0
+Release: 2
+Group: TO_BE/FILLED_IN
+License: TO BE FILLED IN
+Source0: %{name}-%{version}.tar.gz
+BuildRequires: cmake
+
+%description
+chromium library
+
+%package devel
+Summary: chromium library (devel)
+Group: Development/Libraries
+Requires: %{name} = %{version}-%{release}
+
+%description devel
+chromium library (devel)
+
+%prep
+%setup -q
+
+%build
+MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'`
+%ifarch %{ix86}
+CXXFLAGS="$CXXFLAGS -D_OSP_DEBUG_ -D_OSP_X86_ -D_OSP_EMUL_" cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix} -DFULLVER=%{version} -DMAJORVER=${MAJORVER}
+%else
+CXXFLAGS="$CXXFLAGS -D_OSP_DEBUG_ -D_OSP_ARMEL_" cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix} -DFULLVER=%{version} -DMAJORVER=${MAJORVER}
+%endif
+# Call make instruction with smp support
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+mkdir -p %{buildroot}/usr/share/license
+cp %{_builddir}/%{name}-%{version}/LICENSE %{buildroot}/usr/share/license/%{name}
+
+%make_install
+
+%post -p /sbin/ldconfig
+
+%postun -p /sbin/ldconfig
+
+%files
+%manifest chromium.manifest
+%defattr(-,root,root,-)
+/usr/share/license/%{name}
+%{_libdir}/libchromium.so*
+
+%files devel
+%defattr(-,root,root,-)
+%{_includedir}/chromium/*
+%{_libdir}/pkgconfig/chromium.pc