summaryrefslogtreecommitdiffstats
path: root/ipc/chromium/src/base
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /ipc/chromium/src/base
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ipc/chromium/src/base')
-rw-r--r--ipc/chromium/src/base/at_exit.cc73
-rw-r--r--ipc/chromium/src/base/at_exit.h76
-rw-r--r--ipc/chromium/src/base/basictypes.h262
-rw-r--r--ipc/chromium/src/base/chrome_application_mac.h60
-rw-r--r--ipc/chromium/src/base/chrome_application_mac.mm68
-rw-r--r--ipc/chromium/src/base/command_line.cc389
-rw-r--r--ipc/chromium/src/base/command_line.h188
-rw-r--r--ipc/chromium/src/base/compiler_specific.h79
-rw-r--r--ipc/chromium/src/base/condition_variable.h116
-rw-r--r--ipc/chromium/src/base/condition_variable_posix.cc110
-rw-r--r--ipc/chromium/src/base/condition_variable_win.cc40
-rw-r--r--ipc/chromium/src/base/dir_reader_bsd.h94
-rw-r--r--ipc/chromium/src/base/dir_reader_fallback.h33
-rw-r--r--ipc/chromium/src/base/dir_reader_linux.h95
-rw-r--r--ipc/chromium/src/base/dir_reader_posix.h45
-rw-r--r--ipc/chromium/src/base/eintr_wrapper.h61
-rw-r--r--ipc/chromium/src/base/file_path.cc313
-rw-r--r--ipc/chromium/src/base/file_path.h248
-rw-r--r--ipc/chromium/src/base/histogram.cc638
-rw-r--r--ipc/chromium/src/base/histogram.h432
-rw-r--r--ipc/chromium/src/base/linked_ptr.h185
-rw-r--r--ipc/chromium/src/base/linux_memfd_defs.h69
-rw-r--r--ipc/chromium/src/base/lock.h97
-rw-r--r--ipc/chromium/src/base/lock_impl.h65
-rw-r--r--ipc/chromium/src/base/lock_impl_posix.cc98
-rw-r--r--ipc/chromium/src/base/lock_impl_win.cc23
-rw-r--r--ipc/chromium/src/base/logging.cc87
-rw-r--r--ipc/chromium/src/base/logging.h132
-rw-r--r--ipc/chromium/src/base/mac_util.h17
-rw-r--r--ipc/chromium/src/base/mac_util.mm33
-rw-r--r--ipc/chromium/src/base/message_loop.cc725
-rw-r--r--ipc/chromium/src/base/message_loop.h559
-rw-r--r--ipc/chromium/src/base/message_pump.h140
-rw-r--r--ipc/chromium/src/base/message_pump_android.cc104
-rw-r--r--ipc/chromium/src/base/message_pump_android.h61
-rw-r--r--ipc/chromium/src/base/message_pump_default.cc96
-rw-r--r--ipc/chromium/src/base/message_pump_default.h43
-rw-r--r--ipc/chromium/src/base/message_pump_glib.cc291
-rw-r--r--ipc/chromium/src/base/message_pump_glib.h92
-rw-r--r--ipc/chromium/src/base/message_pump_libevent.cc410
-rw-r--r--ipc/chromium/src/base/message_pump_libevent.h181
-rw-r--r--ipc/chromium/src/base/message_pump_mac.h280
-rw-r--r--ipc/chromium/src/base/message_pump_mac.mm735
-rw-r--r--ipc/chromium/src/base/message_pump_qt.cc177
-rw-r--r--ipc/chromium/src/base/message_pump_qt.h84
-rw-r--r--ipc/chromium/src/base/message_pump_win.cc553
-rw-r--r--ipc/chromium/src/base/message_pump_win.h347
-rw-r--r--ipc/chromium/src/base/object_watcher.cc135
-rw-r--r--ipc/chromium/src/base/object_watcher.h115
-rw-r--r--ipc/chromium/src/base/observer_list.h180
-rw-r--r--ipc/chromium/src/base/pickle.cc525
-rw-r--r--ipc/chromium/src/base/pickle.h284
-rw-r--r--ipc/chromium/src/base/platform_file.h46
-rw-r--r--ipc/chromium/src/base/platform_thread.h88
-rw-r--r--ipc/chromium/src/base/platform_thread_mac.mm75
-rw-r--r--ipc/chromium/src/base/platform_thread_posix.cc151
-rw-r--r--ipc/chromium/src/base/platform_thread_win.cc80
-rw-r--r--ipc/chromium/src/base/port.h64
-rw-r--r--ipc/chromium/src/base/process.h50
-rw-r--r--ipc/chromium/src/base/process_util.h342
-rw-r--r--ipc/chromium/src/base/process_util_linux.cc368
-rw-r--r--ipc/chromium/src/base/process_util_mac.mm167
-rw-r--r--ipc/chromium/src/base/process_util_posix.cc388
-rw-r--r--ipc/chromium/src/base/process_util_win.cc392
-rw-r--r--ipc/chromium/src/base/rand_util.cc30
-rw-r--r--ipc/chromium/src/base/rand_util.h19
-rw-r--r--ipc/chromium/src/base/revocable_store.cc40
-rw-r--r--ipc/chromium/src/base/revocable_store.h75
-rw-r--r--ipc/chromium/src/base/scoped_bstr_win.h138
-rw-r--r--ipc/chromium/src/base/scoped_cftyperef.h68
-rw-r--r--ipc/chromium/src/base/scoped_handle.h52
-rw-r--r--ipc/chromium/src/base/scoped_handle_win.h193
-rw-r--r--ipc/chromium/src/base/scoped_nsautorelease_pool.h55
-rw-r--r--ipc/chromium/src/base/scoped_nsautorelease_pool.mm30
-rw-r--r--ipc/chromium/src/base/scoped_nsobject.h66
-rw-r--r--ipc/chromium/src/base/set_process_title_linux.cc206
-rw-r--r--ipc/chromium/src/base/set_process_title_linux.h12
-rw-r--r--ipc/chromium/src/base/shared_memory.h197
-rw-r--r--ipc/chromium/src/base/shared_memory_posix.cc563
-rw-r--r--ipc/chromium/src/base/shared_memory_win.cc266
-rw-r--r--ipc/chromium/src/base/stack_container.h244
-rw-r--r--ipc/chromium/src/base/stl_util-inl.h435
-rw-r--r--ipc/chromium/src/base/string16.cc74
-rw-r--r--ipc/chromium/src/base/string16.h161
-rw-r--r--ipc/chromium/src/base/string_piece.cc190
-rw-r--r--ipc/chromium/src/base/string_piece.h189
-rw-r--r--ipc/chromium/src/base/string_util.cc719
-rw-r--r--ipc/chromium/src/base/string_util.h229
-rw-r--r--ipc/chromium/src/base/string_util_posix.h44
-rw-r--r--ipc/chromium/src/base/string_util_win.h41
-rw-r--r--ipc/chromium/src/base/sys_string_conversions.h35
-rw-r--r--ipc/chromium/src/base/sys_string_conversions_mac.mm126
-rw-r--r--ipc/chromium/src/base/sys_string_conversions_win.cc68
-rw-r--r--ipc/chromium/src/base/task.h227
-rw-r--r--ipc/chromium/src/base/thread.cc201
-rw-r--r--ipc/chromium/src/base/thread.h176
-rw-r--r--ipc/chromium/src/base/thread_local.h121
-rw-r--r--ipc/chromium/src/base/thread_local_posix.cc38
-rw-r--r--ipc/chromium/src/base/thread_local_storage.h95
-rw-r--r--ipc/chromium/src/base/thread_local_win.cc41
-rw-r--r--ipc/chromium/src/base/time.cc97
-rw-r--r--ipc/chromium/src/base/time.h392
-rw-r--r--ipc/chromium/src/base/time_mac.cc122
-rw-r--r--ipc/chromium/src/base/time_posix.cc200
-rw-r--r--ipc/chromium/src/base/time_win.cc263
-rw-r--r--ipc/chromium/src/base/timer.cc31
-rw-r--r--ipc/chromium/src/base/timer.h261
-rw-r--r--ipc/chromium/src/base/tuple.h838
-rw-r--r--ipc/chromium/src/base/waitable_event.h173
-rw-r--r--ipc/chromium/src/base/waitable_event_posix.cc362
-rw-r--r--ipc/chromium/src/base/waitable_event_win.cc81
-rw-r--r--ipc/chromium/src/base/win_util.cc37
-rw-r--r--ipc/chromium/src/base/win_util.h22
113 files changed, 20897 insertions, 0 deletions
diff --git a/ipc/chromium/src/base/at_exit.cc b/ipc/chromium/src/base/at_exit.cc
new file mode 100644
index 0000000000..057d8b2678
--- /dev/null
+++ b/ipc/chromium/src/base/at_exit.cc
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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 "base/at_exit.h"
+#include "base/logging.h"
+
+namespace base {
+
+// Keep a stack of registered AtExitManagers. We always operate on the most
+// recent, and we should never have more than one outside of testing, when we
+// use the shadow version of the constructor. We don't protect this for
+// thread-safe access, since it will only be modified in testing.
+static AtExitManager* g_top_manager = NULL;
+
+AtExitManager::AtExitManager() : lock_("AtExitManager"), next_manager_(NULL) {
+ DCHECK(!g_top_manager);
+ g_top_manager = this;
+}
+
+AtExitManager::AtExitManager(bool shadow)
+ : lock_("AtExitManager"), next_manager_(g_top_manager) {
+ DCHECK(shadow || !g_top_manager);
+ g_top_manager = this;
+}
+
+AtExitManager::~AtExitManager() {
+ if (!g_top_manager) {
+ NOTREACHED() << "Tried to ~AtExitManager without an AtExitManager";
+ return;
+ }
+ DCHECK(g_top_manager == this);
+
+ ProcessCallbacksNow();
+ g_top_manager = next_manager_;
+}
+
+// static
+void AtExitManager::RegisterCallback(AtExitCallbackType func, void* param) {
+ if (!g_top_manager) {
+ NOTREACHED() << "Tried to RegisterCallback without an AtExitManager";
+ return;
+ }
+
+ DCHECK(func);
+
+ mozilla::MutexAutoLock lock(g_top_manager->lock_);
+ g_top_manager->stack_.push(CallbackAndParam(func, param));
+}
+
+// static
+void AtExitManager::ProcessCallbacksNow() {
+ if (!g_top_manager) {
+ NOTREACHED() << "Tried to ProcessCallbacksNow without an AtExitManager";
+ return;
+ }
+
+ mozilla::MutexAutoLock lock(g_top_manager->lock_);
+
+ while (!g_top_manager->stack_.empty()) {
+ CallbackAndParam callback_and_param = g_top_manager->stack_.top();
+ g_top_manager->stack_.pop();
+
+ callback_and_param.func_(callback_and_param.param_);
+ }
+}
+
+// static
+bool AtExitManager::AlreadyRegistered() { return !!g_top_manager; }
+
+} // namespace base
diff --git a/ipc/chromium/src/base/at_exit.h b/ipc/chromium/src/base/at_exit.h
new file mode 100644
index 0000000000..268d9e0fbe
--- /dev/null
+++ b/ipc/chromium/src/base/at_exit.h
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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_AT_EXIT_H_
+#define BASE_AT_EXIT_H_
+
+#include <stack>
+
+#include "base/basictypes.h"
+
+#include "mozilla/Mutex.h"
+
+namespace base {
+
+// This class provides a facility similar to the CRT atexit(), except that
+// we control when the callbacks are executed. Under Windows for a DLL they
+// happen at a really bad time and under the loader lock. This facility is
+// mostly used by base::Singleton.
+//
+// The usage is simple. Early in the main() or WinMain() scope create an
+// AtExitManager object on the stack:
+// int main(...) {
+// base::AtExitManager exit_manager;
+//
+// }
+// When the exit_manager object goes out of scope, all the registered
+// callbacks and singleton destructors will be called.
+
+class AtExitManager {
+ protected:
+ // This constructor will allow this instance of AtExitManager to be created
+ // even if one already exists. This should only be used for testing!
+ // AtExitManagers are kept on a global stack, and it will be removed during
+ // destruction. This allows you to shadow another AtExitManager.
+ explicit AtExitManager(bool shadow);
+
+ public:
+ typedef void (*AtExitCallbackType)(void*);
+
+ AtExitManager();
+
+ // The dtor calls all the registered callbacks. Do not try to register more
+ // callbacks after this point.
+ ~AtExitManager();
+
+ // Registers the specified function to be called at exit. The prototype of
+ // the callback function is void func().
+ static void RegisterCallback(AtExitCallbackType func, void* param);
+
+ // Calls the functions registered with RegisterCallback in LIFO order. It
+ // is possible to register new callbacks after calling this function.
+ static void ProcessCallbacksNow();
+
+ static bool AlreadyRegistered();
+
+ private:
+ struct CallbackAndParam {
+ CallbackAndParam(AtExitCallbackType func, void* param)
+ : func_(func), param_(param) {}
+ AtExitCallbackType func_;
+ void* param_;
+ };
+
+ mozilla::Mutex lock_;
+ std::stack<CallbackAndParam> stack_ MOZ_GUARDED_BY(lock_);
+ AtExitManager* next_manager_; // Stack of managers to allow shadowing.
+
+ DISALLOW_COPY_AND_ASSIGN(AtExitManager);
+};
+
+} // namespace base
+
+#endif // BASE_AT_EXIT_H_
diff --git a/ipc/chromium/src/base/basictypes.h b/ipc/chromium/src/base/basictypes.h
new file mode 100644
index 0000000000..78dcd8964e
--- /dev/null
+++ b/ipc/chromium/src/base/basictypes.h
@@ -0,0 +1,262 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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_BASICTYPES_H_
+#define BASE_BASICTYPES_H_
+
+#include <limits.h> // So we can set the bounds of our types
+#include <stddef.h> // For size_t
+#include <string.h> // for memcpy
+
+#include "base/port.h" // Types that only need exist on certain systems
+
+#include "mozilla/Assertions.h"
+#include "mozilla/IntegerPrintfMacros.h"
+
+// 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_t is.)
+typedef signed int char32;
+
+const uint8_t kuint8max = ((uint8_t)0xFF);
+const uint16_t kuint16max = ((uint16_t)0xFFFF);
+const uint32_t kuint32max = ((uint32_t)0xFFFFFFFF);
+const uint64_t kuint64max = ((uint64_t)GG_LONGLONG(0xFFFFFFFFFFFFFFFF));
+const int8_t kint8min = ((int8_t)0x80);
+const int8_t kint8max = ((int8_t)0x7F);
+const int16_t kint16min = ((int16_t)0x8000);
+const int16_t kint16max = ((int16_t)0x7FFF);
+const int32_t kint32min = ((int32_t)0x80000000);
+const int32_t kint32max = ((int32_t)0x7FFFFFFF);
+const int64_t kint64min = ((int64_t)GG_LONGLONG(0x8000000000000000));
+const int64_t kint64max = ((int64_t)GG_LONGLONG(0x7FFFFFFFFFFFFFFF));
+
+// Platform- and hardware-dependent printf specifiers
+#if defined(XP_UNIX)
+# define PRId64L "I64d"
+# define PRIu64L "I64u"
+# define PRIx64L "I64x"
+#else
+# define PRId64L L"I64d"
+# define PRIu64L L"I64u"
+# define PRIx64L L"I64x"
+#endif
+
+// A macro to disallow the copy constructor and operator= functions
+// This should be used in the private: declarations for a class
+#undef DISALLOW_COPY_AND_ASSIGN
+#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
+ TypeName(const TypeName&); \
+ void operator=(const TypeName&)
+
+// An older, deprecated, politically incorrect name for the above.
+#undef DISALLOW_EVIL_CONSTRUCTORS
+#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.
+#undef DISALLOW_IMPLICIT_CONSTRUCTORS
+#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 (below) creates an otherwise-unused typedef. This
+// triggers compiler warnings with gcc 4.8 and higher, so mark the typedef
+// as permissibly-unused to disable the warnings.
+#if defined(__GNUC__)
+# define COMPILE_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused))
+#else
+# define COMPILE_ASSERT_UNUSED_ATTRIBUTE /* nothing */
+#endif
+
+// 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.
+
+// Avoid multiple definitions for webrtc
+#if !defined(COMPILE_ASSERT)
+template <bool>
+struct CompileAssert {};
+
+# define COMPILE_ASSERT(expr, msg) \
+ typedef CompileAssert<(bool(expr))> \
+ msg[bool(expr) ? 1 : -1] COMPILE_ASSERT_UNUSED_ATTRIBUTE
+#endif
+
+// 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 outter 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_t 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 };
+
+// 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 };
+} // namespace base
+
+#endif // BASE_BASICTYPES_H_
diff --git a/ipc/chromium/src/base/chrome_application_mac.h b/ipc/chromium/src/base/chrome_application_mac.h
new file mode 100644
index 0000000000..8c5bb197f7
--- /dev/null
+++ b/ipc/chromium/src/base/chrome_application_mac.h
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=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.
+
+#ifndef BASE_CHROME_APPLICATION_MAC_H_
+#define BASE_CHROME_APPLICATION_MAC_H_
+
+#import <AppKit/AppKit.h>
+
+#include "base/basictypes.h"
+#include "base/scoped_nsobject.h"
+
+// Event hooks must implement this protocol.
+@protocol CrApplicationEventHookProtocol
+- (void)hookForEvent:(NSEvent*)theEvent;
+@end
+
+@interface CrApplication : NSApplication {
+ @private
+ BOOL handlingSendEvent_;
+ // Array of objects implementing the CrApplicationEventHookProtocol
+ scoped_nsobject<NSMutableArray> eventHooks_;
+}
+@property(readonly, getter=isHandlingSendEvent, nonatomic)
+ BOOL handlingSendEvent;
+
+// Add or remove an event hook to be called for every sendEvent:
+// that the application receives. These handlers are called before
+// the normal [NSApplication sendEvent:] call is made.
+
+// This is not a good alternative to a nested event loop. It should
+// be used only when normal event logic and notification breaks down
+// (e.g. when clicking outside a canBecomeKey:NO window to "switch
+// context" out of it).
+- (void)addEventHook:(id<CrApplicationEventHookProtocol>)hook;
+- (void)removeEventHook:(id<CrApplicationEventHookProtocol>)hook;
+
++ (NSApplication*)sharedApplication;
+@end
+
+namespace chrome_application_mac {
+
+// Controls the state of |handlingSendEvent_| in the event loop so that it is
+// reset properly.
+class ScopedSendingEvent {
+ public:
+ ScopedSendingEvent();
+ ~ScopedSendingEvent();
+
+ private:
+ CrApplication* app_;
+ BOOL handling_;
+ DISALLOW_COPY_AND_ASSIGN(ScopedSendingEvent);
+};
+
+} // namespace chrome_application_mac
+
+#endif // BASE_CHROME_APPLICATION_MAC_H_
diff --git a/ipc/chromium/src/base/chrome_application_mac.mm b/ipc/chromium/src/base/chrome_application_mac.mm
new file mode 100644
index 0000000000..405a02a0e7
--- /dev/null
+++ b/ipc/chromium/src/base/chrome_application_mac.mm
@@ -0,0 +1,68 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "chrome_application_mac.h"
+
+#include "base/logging.h"
+
+@interface CrApplication ()
+@property(readwrite, getter=isHandlingSendEvent, nonatomic)
+ BOOL handlingSendEvent;
+@end
+
+@implementation CrApplication
+@synthesize handlingSendEvent = handlingSendEvent_;
+
+// Initialize NSApplication using the custom subclass. Check whether NSApp
+// was already initialized using another class, because that would break
+// some things.
++ (NSApplication*)sharedApplication {
+ NSApplication* app = [super sharedApplication];
+ if (![NSApp isKindOfClass:self]) {
+ CHROMIUM_LOG(ERROR) << "NSApp should be of type "
+ << [[self className] UTF8String] << ", not "
+ << [[NSApp className] UTF8String];
+ DCHECK(false) << "NSApp is of wrong type";
+ }
+ return app;
+}
+
+- (id)init {
+ if ((self = [super init])) {
+ eventHooks_.reset([[NSMutableArray alloc] init]);
+ }
+ return self;
+}
+
+- (void)sendEvent:(NSEvent*)event {
+ chrome_application_mac::ScopedSendingEvent sendingEventScoper;
+ for (id<CrApplicationEventHookProtocol> handler in eventHooks_.get()) {
+ [handler hookForEvent:event];
+ }
+ [super sendEvent:event];
+}
+
+- (void)addEventHook:(id<CrApplicationEventHookProtocol>)handler {
+ [eventHooks_ addObject:handler];
+}
+
+- (void)removeEventHook:(id<CrApplicationEventHookProtocol>)handler {
+ [eventHooks_ removeObject:handler];
+}
+
+@end
+
+namespace chrome_application_mac {
+
+ScopedSendingEvent::ScopedSendingEvent()
+ : app_(static_cast<CrApplication*>([CrApplication sharedApplication])),
+ handling_([app_ isHandlingSendEvent]) {
+ [app_ setHandlingSendEvent:YES];
+}
+
+ScopedSendingEvent::~ScopedSendingEvent() {
+ [app_ setHandlingSendEvent:handling_];
+}
+
+} // namespace chrome_application_mac
diff --git a/ipc/chromium/src/base/command_line.cc b/ipc/chromium/src/base/command_line.cc
new file mode 100644
index 0000000000..b3daa6f104
--- /dev/null
+++ b/ipc/chromium/src/base/command_line.cc
@@ -0,0 +1,389 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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 "base/command_line.h"
+
+#if defined(XP_WIN)
+# include <windows.h>
+# include <shellapi.h>
+# include "mozilla/DynamicallyLinkedFunctionPtr.h"
+#endif
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "base/string_piece.h"
+#include "base/string_util.h"
+#include "base/sys_string_conversions.h"
+
+CommandLine* CommandLine::current_process_commandline_ = NULL;
+
+// Since we use a lazy match, make sure that longer versions (like L"--")
+// are listed before shorter versions (like L"-") of similar prefixes.
+#if defined(XP_WIN)
+const wchar_t* const kSwitchPrefixes[] = {L"--", L"-", L"/"};
+const wchar_t kSwitchTerminator[] = L"--";
+const wchar_t kSwitchValueSeparator[] = L"=";
+#else
+// Unixes don't use slash as a switch.
+const char* const kSwitchPrefixes[] = {"--", "-"};
+const char kSwitchTerminator[] = "--";
+const char kSwitchValueSeparator[] = "=";
+#endif
+
+#if defined(XP_WIN)
+// Lowercase a string. This is used to lowercase switch names.
+// Is this what we really want? It seems crazy to me. I've left it in
+// for backwards compatibility on Windows.
+static void Lowercase(std::wstring* parameter) {
+ transform(parameter->begin(), parameter->end(), parameter->begin(), tolower);
+}
+#endif
+
+#if defined(XP_WIN)
+void CommandLine::ParseFromString(const std::wstring& command_line) {
+ TrimWhitespace(command_line, TRIM_ALL, &command_line_string_);
+
+ if (command_line_string_.empty()) return;
+
+ int num_args = 0;
+ wchar_t** args = NULL;
+ // When calling CommandLineToArgvW, use the API set if available.
+ // Doing so will bypass loading shell32.dll on Win8+.
+ mozilla::DynamicallyLinkedFunctionPtr<decltype(&::CommandLineToArgvW)>
+ pCommandLineToArgvW(L"api-ms-win-downlevel-shell32-l1-1-0.dll",
+ "CommandLineToArgvW");
+ if (pCommandLineToArgvW) {
+ args = pCommandLineToArgvW(command_line_string_.c_str(), &num_args);
+ } else {
+ args = CommandLineToArgvW(command_line_string_.c_str(), &num_args);
+ }
+
+ // Populate program_ with the trimmed version of the first arg.
+ TrimWhitespace(args[0], TRIM_ALL, &program_);
+
+ bool parse_switches = true;
+ for (int i = 1; i < num_args; ++i) {
+ std::wstring arg;
+ TrimWhitespace(args[i], TRIM_ALL, &arg);
+
+ if (!parse_switches) {
+ loose_values_.push_back(arg);
+ continue;
+ }
+
+ if (arg == kSwitchTerminator) {
+ parse_switches = false;
+ continue;
+ }
+
+ std::string switch_string;
+ std::wstring switch_value;
+ if (IsSwitch(arg, &switch_string, &switch_value)) {
+ switches_[switch_string] = switch_value;
+ } else {
+ loose_values_.push_back(arg);
+ }
+ }
+
+ if (args) LocalFree(args);
+}
+CommandLine::CommandLine(const std::wstring& program) {
+ if (!program.empty()) {
+ program_ = program;
+ command_line_string_ = L'"' + program + L'"';
+ }
+}
+#else
+CommandLine::CommandLine(int argc, const char* const* argv) {
+ for (int i = 0; i < argc; ++i) argv_.push_back(argv[i]);
+ InitFromArgv();
+}
+CommandLine::CommandLine(const std::vector<std::string>& argv) {
+ argv_ = argv;
+ InitFromArgv();
+}
+
+void CommandLine::InitFromArgv() {
+ bool parse_switches = true;
+ for (size_t i = 1; i < argv_.size(); ++i) {
+ const std::string& arg = argv_[i];
+
+ if (!parse_switches) {
+ loose_values_.push_back(arg);
+ continue;
+ }
+
+ if (arg == kSwitchTerminator) {
+ parse_switches = false;
+ continue;
+ }
+
+ std::string switch_string;
+ std::string switch_value;
+ if (IsSwitch(arg, &switch_string, &switch_value)) {
+ switches_[switch_string] = switch_value;
+ } else {
+ loose_values_.push_back(arg);
+ }
+ }
+}
+
+CommandLine::CommandLine(const std::wstring& program) {
+ argv_.push_back(WideToASCII(program));
+}
+#endif
+
+// static
+bool CommandLine::IsSwitch(const StringType& parameter_string,
+ std::string* switch_string,
+ StringType* switch_value) {
+ switch_string->clear();
+ switch_value->clear();
+
+ for (size_t i = 0; i < arraysize(kSwitchPrefixes); ++i) {
+ StringType prefix(kSwitchPrefixes[i]);
+ if (parameter_string.find(prefix) != 0) continue;
+
+ const size_t switch_start = prefix.length();
+ const size_t equals_position =
+ parameter_string.find(kSwitchValueSeparator, switch_start);
+ StringType switch_native;
+ if (equals_position == StringType::npos) {
+ switch_native = parameter_string.substr(switch_start);
+ } else {
+ switch_native =
+ parameter_string.substr(switch_start, equals_position - switch_start);
+ *switch_value = parameter_string.substr(equals_position + 1);
+ }
+#if defined(XP_WIN)
+ Lowercase(&switch_native);
+ *switch_string = WideToASCII(switch_native);
+#else
+ *switch_string = switch_native;
+#endif
+
+ return true;
+ }
+
+ return false;
+}
+
+// static
+void CommandLine::Init(int argc, const char* const* argv) {
+ DCHECK(current_process_commandline_ == NULL);
+#if defined(XP_WIN)
+ current_process_commandline_ = new CommandLine;
+ current_process_commandline_->ParseFromString(::GetCommandLineW());
+#else
+ current_process_commandline_ = new CommandLine(argc, argv);
+#endif
+}
+
+void CommandLine::Terminate() {
+ DCHECK(current_process_commandline_ != NULL);
+ delete current_process_commandline_;
+ current_process_commandline_ = NULL;
+}
+
+bool CommandLine::HasSwitch(const std::wstring& switch_string) const {
+ std::wstring lowercased_switch(switch_string);
+#if defined(XP_WIN)
+ Lowercase(&lowercased_switch);
+#endif
+ return switches_.find(WideToASCII(lowercased_switch)) != switches_.end();
+}
+
+std::wstring CommandLine::GetSwitchValue(
+ const std::wstring& switch_string) const {
+ std::wstring lowercased_switch(switch_string);
+#if defined(XP_WIN)
+ Lowercase(&lowercased_switch);
+#endif
+
+ std::map<std::string, StringType>::const_iterator result =
+ switches_.find(WideToASCII(lowercased_switch));
+
+ if (result == switches_.end()) {
+ return L"";
+ } else {
+#if defined(XP_WIN)
+ return result->second;
+#else
+ return ASCIIToWide(result->second);
+#endif
+ }
+}
+
+#if defined(XP_WIN)
+std::vector<std::wstring> CommandLine::GetLooseValues() const {
+ return loose_values_;
+}
+std::wstring CommandLine::program() const { return program_; }
+#else
+std::vector<std::wstring> CommandLine::GetLooseValues() const {
+ std::vector<std::wstring> values;
+ for (size_t i = 0; i < loose_values_.size(); ++i)
+ values.push_back(ASCIIToWide(loose_values_[i]));
+ return values;
+}
+std::wstring CommandLine::program() const {
+ DCHECK(argv_.size() > 0);
+ return ASCIIToWide(argv_[0]);
+}
+#endif
+
+// static
+std::wstring CommandLine::PrefixedSwitchString(
+ const std::wstring& switch_string) {
+ return StringPrintf(L"%ls%ls", kSwitchPrefixes[0], switch_string.c_str());
+}
+
+// static
+std::wstring CommandLine::PrefixedSwitchStringWithValue(
+ const std::wstring& switch_string, const std::wstring& value_string) {
+ if (value_string.empty()) {
+ return PrefixedSwitchString(switch_string);
+ }
+
+ return StringPrintf(L"%ls%ls%ls%ls", kSwitchPrefixes[0],
+ switch_string.c_str(), kSwitchValueSeparator,
+ value_string.c_str());
+}
+
+#if defined(XP_WIN)
+void CommandLine::AppendSwitch(const std::wstring& switch_string) {
+ std::wstring prefixed_switch_string = PrefixedSwitchString(switch_string);
+ command_line_string_.append(L" ");
+ command_line_string_.append(prefixed_switch_string);
+ switches_[WideToASCII(switch_string)] = L"";
+}
+
+// Quote a string if necessary, such that CommandLineToArgvW() will
+// always process it as a single argument.
+static std::wstring WindowsStyleQuote(const std::wstring& arg) {
+ // We follow the quoting rules of CommandLineToArgvW.
+ // http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
+ if (arg.find_first_of(L" \\\"\t") == std::wstring::npos) {
+ // No quoting necessary.
+ return arg;
+ }
+
+ std::wstring out;
+ out.push_back(L'"');
+ for (size_t i = 0; i < arg.size(); ++i) {
+ if (arg[i] == '\\') {
+ // Find the extent of this run of backslashes.
+ size_t start = i, end = start + 1;
+ for (; end < arg.size() && arg[end] == '\\'; ++end) /* empty */
+ ;
+ size_t backslash_count = end - start;
+
+ // Backslashes are escapes only if the run is followed by a double quote.
+ // Since we also will end the string with a double quote, we escape for
+ // either a double quote or the end of the string.
+ if (end == arg.size() || arg[end] == '"') {
+ // To quote, we need to output 2x as many backslashes.
+ backslash_count *= 2;
+ }
+ for (size_t j = 0; j < backslash_count; ++j) out.push_back('\\');
+
+ // Advance i to one before the end to balance i++ in loop.
+ i = end - 1;
+ } else if (arg[i] == '"') {
+ out.push_back('\\');
+ out.push_back('"');
+ } else {
+ out.push_back(arg[i]);
+ }
+ }
+ out.push_back('"');
+
+ return out;
+}
+
+void CommandLine::AppendSwitchWithValue(const std::wstring& switch_string,
+ const std::wstring& value_string) {
+ std::wstring quoted_value_string = WindowsStyleQuote(value_string);
+ std::wstring combined_switch_string =
+ PrefixedSwitchStringWithValue(switch_string, quoted_value_string);
+
+ command_line_string_.append(L" ");
+ command_line_string_.append(combined_switch_string);
+
+ switches_[WideToASCII(switch_string)] = value_string;
+}
+
+void CommandLine::AppendLooseValue(const std::wstring& value) {
+ command_line_string_.append(L" ");
+ command_line_string_.append(WindowsStyleQuote(value));
+}
+
+void CommandLine::AppendArguments(const CommandLine& other,
+ bool include_program) {
+ // Verify include_program is used correctly.
+ // Logic could be shorter but this is clearer.
+ DCHECK(include_program ? !other.program().empty() : other.program().empty());
+ command_line_string_ += L" " + other.command_line_string_;
+ std::map<std::string, StringType>::const_iterator i;
+ for (i = other.switches_.begin(); i != other.switches_.end(); ++i)
+ switches_[i->first] = i->second;
+}
+
+void CommandLine::PrependWrapper(const std::wstring& wrapper) {
+ // The wrapper may have embedded arguments (like "gdb --args"). In this case,
+ // we don't pretend to do anything fancy, we just split on spaces.
+ std::vector<std::wstring> wrapper_and_args;
+ SplitString(wrapper, ' ', &wrapper_and_args);
+ program_ = wrapper_and_args[0];
+ command_line_string_ = wrapper + L" " + command_line_string_;
+}
+
+#else
+void CommandLine::AppendSwitch(const std::wstring& switch_string) {
+ std::string ascii_switch = WideToASCII(switch_string);
+ argv_.push_back(kSwitchPrefixes[0] + ascii_switch);
+ switches_[ascii_switch] = "";
+}
+
+void CommandLine::AppendSwitchWithValue(const std::wstring& switch_string,
+ const std::wstring& value_string) {
+ std::string ascii_switch = WideToASCII(switch_string);
+ std::string ascii_value = WideToASCII(value_string);
+
+ argv_.push_back(kSwitchPrefixes[0] + ascii_switch + kSwitchValueSeparator +
+ ascii_value);
+ switches_[ascii_switch] = ascii_value;
+}
+
+void CommandLine::AppendLooseValue(const std::wstring& value) {
+ argv_.push_back(WideToASCII(value));
+}
+
+void CommandLine::AppendArguments(const CommandLine& other,
+ bool include_program) {
+ // Verify include_program is used correctly.
+ // Logic could be shorter but this is clearer.
+ DCHECK(include_program ? !other.program().empty() : other.program().empty());
+
+ size_t first_arg = include_program ? 0 : 1;
+ for (size_t i = first_arg; i < other.argv_.size(); ++i)
+ argv_.push_back(other.argv_[i]);
+ std::map<std::string, StringType>::const_iterator i;
+ for (i = other.switches_.begin(); i != other.switches_.end(); ++i)
+ switches_[i->first] = i->second;
+}
+
+void CommandLine::PrependWrapper(const std::wstring& wrapper_wide) {
+ // The wrapper may have embedded arguments (like "gdb --args"). In this case,
+ // we don't pretend to do anything fancy, we just split on spaces.
+ const std::string wrapper = WideToASCII(wrapper_wide);
+ std::vector<std::string> wrapper_and_args;
+ SplitString(wrapper, ' ', &wrapper_and_args);
+ argv_.insert(argv_.begin(), wrapper_and_args.begin(), wrapper_and_args.end());
+}
+
+#endif
diff --git a/ipc/chromium/src/base/command_line.h b/ipc/chromium/src/base/command_line.h
new file mode 100644
index 0000000000..1aff5eae07
--- /dev/null
+++ b/ipc/chromium/src/base/command_line.h
@@ -0,0 +1,188 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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 class works with command lines: building and parsing.
+// Switches can optionally have a value attached using an equals sign,
+// as in "-switch=value". Arguments that aren't prefixed with a
+// switch prefix are considered "loose parameters". Switch names are
+// case-insensitive. An argument of "--" will terminate switch
+// parsing, causing everything after to be considered as loose
+// parameters.
+
+// There is a singleton read-only CommandLine that represents the command
+// line that the current process was started with. It must be initialized
+// in main() (or whatever the platform's equivalent function is).
+
+#ifndef BASE_COMMAND_LINE_H_
+#define BASE_COMMAND_LINE_H_
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+class InProcessBrowserTest;
+
+class CommandLine {
+ public:
+#if defined(XP_WIN)
+ // Creates a parsed version of the given command-line string.
+ // The program name is assumed to be the first item in the string.
+ void ParseFromString(const std::wstring& command_line);
+#else
+ // Initialize from an argv vector (or directly from main()'s argv).
+ CommandLine(int argc, const char* const* argv);
+ explicit CommandLine(const std::vector<std::string>& argv);
+#endif
+
+ // Construct a new, empty command line.
+ // |program| is the name of the program to run (aka argv[0]).
+ // TODO(port): should be a FilePath.
+ explicit CommandLine(const std::wstring& program);
+
+ // Initialize the current process CommandLine singleton. On Windows,
+ // ignores its arguments (we instead parse GetCommandLineW()
+ // directly) because we don't trust the CRT's parsing of the command
+ // line, but it still must be called to set up the command line.
+ static void Init(int argc, const char* const* argv);
+
+ // Destroys the current process CommandLine singleton. This is necessary if
+ // you want to reset the base library to its initial state (for example in an
+ // outer library that needs to be able to terminate, and be re-initialized).
+ // If Init is called only once, e.g. in main(), calling Terminate() is not
+ // necessary.
+ static void Terminate();
+
+ // Get the singleton CommandLine representing the current process's
+ // command line.
+ static const CommandLine* ForCurrentProcess() {
+ DCHECK(current_process_commandline_);
+ return current_process_commandline_;
+ }
+
+ static bool IsInitialized() { return !!current_process_commandline_; }
+
+ // Returns true if this command line contains the given switch.
+ // (Switch names are case-insensitive.)
+ bool HasSwitch(const std::wstring& switch_string) const;
+
+ // Returns the value associated with the given switch. If the
+ // switch has no value or isn't present, this method returns
+ // the empty string.
+ std::wstring GetSwitchValue(const std::wstring& switch_string) const;
+
+ // Get the remaining arguments to the command.
+ // WARNING: this is incorrect on POSIX; we must do string conversions.
+ std::vector<std::wstring> GetLooseValues() const;
+
+#if defined(XP_WIN)
+ // Returns the original command line string.
+ const std::wstring& command_line_string() const {
+ return command_line_string_;
+ }
+#else
+ // Returns the original command line string as a vector of strings.
+ const std::vector<std::string>& argv() const { return argv_; }
+#endif
+
+ // Returns the program part of the command line string (the first item).
+ std::wstring program() const;
+
+ // Return a copy of the string prefixed with a switch prefix.
+ // Used internally.
+ static std::wstring PrefixedSwitchString(const std::wstring& switch_string);
+
+ // Return a copy of the string prefixed with a switch prefix,
+ // and appended with the given value. Used internally.
+ static std::wstring PrefixedSwitchStringWithValue(
+ const std::wstring& switch_string, const std::wstring& value_string);
+
+ // Appends the given switch string (preceded by a space and a switch
+ // prefix) to the given string.
+ void AppendSwitch(const std::wstring& switch_string);
+
+ // Appends the given switch string (preceded by a space and a switch
+ // prefix) to the given string, with the given value attached.
+ void AppendSwitchWithValue(const std::wstring& switch_string,
+ const std::wstring& value_string);
+
+ // Append a loose value to the command line.
+ void AppendLooseValue(const std::wstring& value);
+
+#if defined(XP_WIN)
+ void AppendLooseValue(const wchar_t* value) {
+ AppendLooseValue(std::wstring(value));
+ }
+#endif
+
+ // Append the arguments from another command line to this one.
+ // If |include_program| is true, include |other|'s program as well.
+ void AppendArguments(const CommandLine& other, bool include_program);
+
+ // On POSIX systems it's common to run processes via a wrapper (like
+ // "valgrind" or "gdb --args").
+ void PrependWrapper(const std::wstring& wrapper);
+
+ private:
+ friend class InProcessBrowserTest;
+
+ CommandLine() {}
+
+ // Used by InProcessBrowserTest.
+ static CommandLine* ForCurrentProcessMutable() {
+ DCHECK(current_process_commandline_);
+ return current_process_commandline_;
+ }
+
+ // The singleton CommandLine instance representing the current process's
+ // command line.
+ static CommandLine* current_process_commandline_;
+
+ // We store a platform-native version of the command line, used when building
+ // up a new command line to be executed. This ifdef delimits that code.
+
+#if defined(XP_WIN)
+ // The quoted, space-separated command-line string.
+ std::wstring command_line_string_;
+
+ // The name of the program.
+ std::wstring program_;
+
+ // The type of native command line arguments.
+ typedef std::wstring StringType;
+
+#else
+ // The argv array, with the program name in argv_[0].
+ std::vector<std::string> argv_;
+
+ // The type of native command line arguments.
+ typedef std::string StringType;
+
+ // Shared by the two POSIX constructor forms. Initalize from argv_.
+ void InitFromArgv();
+#endif
+
+ // Returns true and fills in |switch_string| and |switch_value|
+ // if |parameter_string| represents a switch.
+ static bool IsSwitch(const StringType& parameter_string,
+ std::string* switch_string, StringType* switch_value);
+
+ // Parsed-out values.
+ std::map<std::string, StringType> switches_;
+
+ // Non-switch command-line arguments.
+ std::vector<StringType> loose_values_;
+
+ // We allow copy constructors, because a common pattern is to grab a
+ // copy of the current process's command line and then add some
+ // flags to it. E.g.:
+ // CommandLine cl(*CommandLine::ForCurrentProcess());
+ // cl.AppendSwitch(...);
+};
+
+#endif // BASE_COMMAND_LINE_H_
diff --git a/ipc/chromium/src/base/compiler_specific.h b/ipc/chromium/src/base/compiler_specific.h
new file mode 100644
index 0000000000..9cf749d9f1
--- /dev/null
+++ b/ipc/chromium/src/base/compiler_specific.h
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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_COMPILER_SPECIFIC_H_
+#define BASE_COMPILER_SPECIFIC_H_
+
+#if defined(_MSC_VER)
+
+// 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()
+
+#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
+
+#endif // _MSC_VER
+
+// 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/macros.h.
+#undef WARN_UNUSED_RESULT
+#if defined(__GNUC__) || defined(__clang__)
+# define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
+#else
+# define WARN_UNUSED_RESULT
+#endif
+
+#endif // BASE_COMPILER_SPECIFIC_H_
diff --git a/ipc/chromium/src/base/condition_variable.h b/ipc/chromium/src/base/condition_variable.h
new file mode 100644
index 0000000000..0b82824ce6
--- /dev/null
+++ b/ipc/chromium/src/base/condition_variable.h
@@ -0,0 +1,116 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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.
+
+// ConditionVariable wraps pthreads condition variable synchronization or, on
+// Windows, simulates it. This functionality is very helpful for having
+// several threads wait for an event, as is common with a managed thread pool.
+// The meaning of such an event in the (worker) thread pool scenario is that
+// additional tasks are now available for processing. It is used in Chrome in
+// the DNS prefetching system to notify worker threads that a queue now has
+// items (tasks) which need to be tended to. A related use would have a pool
+// manager waiting on a ConditionVariable, waiting for a thread in the pool to
+// announce (signal) that there is now more room in a (bounded size)
+// communications queue for the manager to deposit tasks, or, as a second
+// example, that the queue of tasks is completely empty and all workers are
+// waiting.
+//
+// USAGE NOTE 1: spurious signal events are possible with this and
+// most implementations of condition variables. As a result, be
+// *sure* to retest your condition before proceeding. The following
+// is a good example of doing this correctly:
+//
+// while (!work_to_be_done()) Wait(...);
+//
+// In contrast do NOT do the following:
+//
+// if (!work_to_be_done()) Wait(...); // Don't do this.
+//
+// Especially avoid the above if you are relying on some other thread only
+// issuing a signal up *if* there is work-to-do. There can/will
+// be spurious signals. Recheck state on waiting thread before
+// assuming the signal was intentional. Caveat caller ;-).
+//
+// USAGE NOTE 2: Broadcast() frees up all waiting threads at once,
+// which leads to contention for the locks they all held when they
+// called Wait(). This results in POOR performance. A much better
+// approach to getting a lot of threads out of Wait() is to have each
+// thread (upon exiting Wait()) call Signal() to free up another
+// Wait'ing thread. Look at condition_variable_unittest.cc for
+// both examples.
+//
+// Broadcast() can be used nicely during teardown, as it gets the job
+// done, and leaves no sleeping threads... and performance is less
+// critical at that point.
+//
+// The semantics of Broadcast() are carefully crafted so that *all*
+// threads that were waiting when the request was made will indeed
+// get signaled. Some implementations mess up, and don't signal them
+// all, while others allow the wait to be effectively turned off (for
+// a while while waiting threads come around). This implementation
+// appears correct, as it will not "lose" any signals, and will guarantee
+// that all threads get signaled by Broadcast().
+//
+// This implementation offers support for "performance" in its selection of
+// which thread to revive. Performance, in direct contrast with "fairness,"
+// assures that the thread that most recently began to Wait() is selected by
+// Signal to revive. Fairness would (if publicly supported) assure that the
+// thread that has Wait()ed the longest is selected. The default policy
+// may improve performance, as the selected thread may have a greater chance of
+// having some of its stack data in various CPU caches.
+//
+// For a discussion of the many very subtle implementation details, see the FAQ
+// at the end of condition_variable_win.cc.
+
+#ifndef BASE_CONDITION_VARIABLE_H_
+#define BASE_CONDITION_VARIABLE_H_
+
+#include "base/basictypes.h"
+#include "base/lock.h"
+
+#if defined(XP_UNIX)
+# include <pthread.h>
+#endif
+
+#if defined(XP_WIN)
+# include <windows.h>
+#endif
+
+namespace base {
+class TimeDelta;
+}
+
+class ConditionVariable {
+ public:
+ // Construct a cv for use with ONLY one user lock.
+ explicit ConditionVariable(Lock* user_lock);
+
+ ~ConditionVariable();
+
+ // Wait() releases the caller's critical section atomically as it starts to
+ // sleep, and the reacquires it when it is signaled. The wait functions are
+ // susceptible to spurious wakeups. (See usage note 1 for more details.)
+ void Wait();
+ void TimedWait(const base::TimeDelta& max_time);
+
+ // Broadcast() revives all waiting threads. (See usage note 2 for more
+ // details.)
+ void Broadcast();
+ // Signal() revives one waiting thread.
+ void Signal();
+
+ private:
+#if defined(XP_WIN)
+ CONDITION_VARIABLE cv_;
+ SRWLOCK* const srwlock_;
+#else
+ pthread_cond_t condition_;
+ pthread_mutex_t* user_mutex_;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(ConditionVariable);
+};
+
+#endif // BASE_CONDITION_VARIABLE_H_
diff --git a/ipc/chromium/src/base/condition_variable_posix.cc b/ipc/chromium/src/base/condition_variable_posix.cc
new file mode 100644
index 0000000000..be01d3af95
--- /dev/null
+++ b/ipc/chromium/src/base/condition_variable_posix.cc
@@ -0,0 +1,110 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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/condition_variable.h"
+
+#include <errno.h>
+#include <stdint.h>
+#include <sys/time.h>
+
+#include "base/lock.h"
+#include "base/logging.h"
+#include "base/time.h"
+
+ConditionVariable::ConditionVariable(Lock* user_lock)
+ : user_mutex_(user_lock->lock_.native_handle()) {
+ int rv = 0;
+ // http://crbug.com/293736
+ // On older Android platform versions, monotonic clock based absolute
+ // deadlines are supported through the non-standard
+ // pthread_cond_timedwait_monotonic_np. Newer platform versions have
+ // pthread_condattr_setclock.
+ // Mac can use relative time deadlines.
+#if !defined(XP_DARWIN) && \
+ !(defined(ANDROID) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC))
+ pthread_condattr_t attrs;
+ rv = pthread_condattr_init(&attrs);
+ DCHECK_EQ(0, rv);
+ pthread_condattr_setclock(&attrs, CLOCK_MONOTONIC);
+ rv = pthread_cond_init(&condition_, &attrs);
+ pthread_condattr_destroy(&attrs);
+#else
+ rv = pthread_cond_init(&condition_, NULL);
+#endif
+ DCHECK_EQ(0, rv);
+}
+
+ConditionVariable::~ConditionVariable() {
+#if defined(XP_DARWIN)
+ // This hack is necessary to avoid a fatal pthreads subsystem bug in the
+ // Darwin kernel. http://crbug.com/517681.
+ {
+ Lock lock;
+ AutoLock l(lock);
+ struct timespec ts;
+ ts.tv_sec = 0;
+ ts.tv_nsec = 1;
+ pthread_cond_timedwait_relative_np(&condition_, lock.lock_.native_handle(),
+ &ts);
+ }
+#endif
+
+ int rv = pthread_cond_destroy(&condition_);
+ DCHECK_EQ(0, rv);
+}
+
+void ConditionVariable::Wait() {
+ int rv = pthread_cond_wait(&condition_, user_mutex_);
+ DCHECK_EQ(0, rv);
+}
+
+void ConditionVariable::TimedWait(const base::TimeDelta& max_time) {
+ int64_t usecs = max_time.InMicroseconds();
+ struct timespec relative_time;
+ relative_time.tv_sec = usecs / base::Time::kMicrosecondsPerSecond;
+ relative_time.tv_nsec = (usecs % base::Time::kMicrosecondsPerSecond) *
+ base::Time::kNanosecondsPerMicrosecond;
+
+#if defined(XP_DARWIN)
+ int rv = pthread_cond_timedwait_relative_np(&condition_, user_mutex_,
+ &relative_time);
+#else
+ // The timeout argument to pthread_cond_timedwait is in absolute time.
+ struct timespec absolute_time;
+ struct timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ absolute_time.tv_sec = now.tv_sec;
+ absolute_time.tv_nsec = now.tv_nsec;
+
+ absolute_time.tv_sec += relative_time.tv_sec;
+ absolute_time.tv_nsec += relative_time.tv_nsec;
+ absolute_time.tv_sec +=
+ absolute_time.tv_nsec / base::Time::kNanosecondsPerSecond;
+ absolute_time.tv_nsec %= base::Time::kNanosecondsPerSecond;
+ DCHECK_GE(absolute_time.tv_sec, now.tv_sec); // Overflow paranoia
+
+# if defined(ANDROID) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC)
+ int rv = pthread_cond_timedwait_monotonic_np(&condition_, user_mutex_,
+ &absolute_time);
+# else
+ int rv = pthread_cond_timedwait(&condition_, user_mutex_, &absolute_time);
+# endif // ANDROID && HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC
+#endif // XP_DARWIN
+
+ // On failure, we only expect the CV to timeout. Any other error value means
+ // that we've unexpectedly woken up.
+ DCHECK(rv == 0 || rv == ETIMEDOUT);
+}
+
+void ConditionVariable::Broadcast() {
+ int rv = pthread_cond_broadcast(&condition_);
+ DCHECK_EQ(0, rv);
+}
+
+void ConditionVariable::Signal() {
+ int rv = pthread_cond_signal(&condition_);
+ DCHECK_EQ(0, rv);
+}
diff --git a/ipc/chromium/src/base/condition_variable_win.cc b/ipc/chromium/src/base/condition_variable_win.cc
new file mode 100644
index 0000000000..35d79ba2ec
--- /dev/null
+++ b/ipc/chromium/src/base/condition_variable_win.cc
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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/condition_variable.h"
+
+#include "base/lock.h"
+#include "base/logging.h"
+#include "base/time.h"
+
+ConditionVariable::ConditionVariable(Lock* user_lock)
+ : srwlock_(user_lock->lock_.native_handle()) {
+ DCHECK(user_lock);
+ InitializeConditionVariable(&cv_);
+}
+
+ConditionVariable::~ConditionVariable() = default;
+
+void ConditionVariable::Wait() {
+ TimedWait(base::TimeDelta::FromMilliseconds(INFINITE));
+}
+
+void ConditionVariable::TimedWait(const base::TimeDelta& max_time) {
+ DWORD timeout = static_cast<DWORD>(max_time.InMilliseconds());
+
+ if (!SleepConditionVariableSRW(&cv_, srwlock_, timeout, 0)) {
+ // On failure, we only expect the CV to timeout. Any other error value means
+ // that we've unexpectedly woken up.
+ // Note that WAIT_TIMEOUT != ERROR_TIMEOUT. WAIT_TIMEOUT is used with the
+ // WaitFor* family of functions as a direct return value. ERROR_TIMEOUT is
+ // used with GetLastError().
+ DCHECK_EQ(static_cast<DWORD>(ERROR_TIMEOUT), GetLastError());
+ }
+}
+
+void ConditionVariable::Broadcast() { WakeAllConditionVariable(&cv_); }
+
+void ConditionVariable::Signal() { WakeConditionVariable(&cv_); }
diff --git a/ipc/chromium/src/base/dir_reader_bsd.h b/ipc/chromium/src/base/dir_reader_bsd.h
new file mode 100644
index 0000000000..851f46a006
--- /dev/null
+++ b/ipc/chromium/src/base/dir_reader_bsd.h
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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.
+
+// derived from dir_reader_linux.h
+
+#ifndef BASE_DIR_READER_BSD_H_
+#define BASE_DIR_READER_BSD_H_
+#pragma once
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "base/eintr_wrapper.h"
+
+// See the comments in dir_reader_posix.h about this.
+
+namespace base {
+
+class DirReaderBSD {
+ public:
+ explicit DirReaderBSD(const char* directory_path)
+#ifdef O_DIRECTORY
+ : fd_(open(directory_path, O_RDONLY | O_DIRECTORY)),
+#else
+ : fd_(open(directory_path, O_RDONLY)),
+#endif
+ offset_(0),
+ size_(0) {
+ memset(buf_, 0, sizeof(buf_));
+ }
+
+ ~DirReaderBSD() {
+ if (fd_ >= 0) {
+ if (IGNORE_EINTR(close(fd_)))
+ DLOG(ERROR) << "Failed to close directory handle";
+ }
+ }
+
+ bool IsValid() const { return fd_ >= 0; }
+
+ // Move to the next entry returning false if the iteration is complete.
+ bool Next() {
+ if (size_) {
+ struct dirent* dirent = reinterpret_cast<struct dirent*>(&buf_[offset_]);
+#ifdef __DragonFly__
+ offset_ += _DIRENT_DIRSIZ(dirent);
+#else
+ offset_ += dirent->d_reclen;
+#endif
+ }
+
+ if (offset_ != size_) return true;
+
+ const int r = getdents(fd_, buf_, sizeof(buf_));
+ if (r == 0) return false;
+ if (r == -1) {
+ DLOG(ERROR) << "getdents returned an error: " << errno;
+ return false;
+ }
+ size_ = r;
+ offset_ = 0;
+ return true;
+ }
+
+ const char* name() const {
+ if (!size_) return NULL;
+
+ const struct dirent* dirent =
+ reinterpret_cast<const struct dirent*>(&buf_[offset_]);
+ return dirent->d_name;
+ }
+
+ int fd() const { return fd_; }
+
+ static bool IsFallback() { return false; }
+
+ private:
+ const int fd_;
+ char buf_[512];
+ size_t offset_, size_;
+
+ DISALLOW_COPY_AND_ASSIGN(DirReaderBSD);
+};
+
+} // namespace base
+
+#endif // BASE_DIR_READER_BSD_H_
diff --git a/ipc/chromium/src/base/dir_reader_fallback.h b/ipc/chromium/src/base/dir_reader_fallback.h
new file mode 100644
index 0000000000..5fbf658d49
--- /dev/null
+++ b/ipc/chromium/src/base/dir_reader_fallback.h
@@ -0,0 +1,33 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_DIR_READER_FALLBACK_H_
+#define BASE_DIR_READER_FALLBACK_H_
+#pragma once
+
+namespace base {
+
+class DirReaderFallback {
+ public:
+ // Open a directory. If |IsValid| is true, then |Next| can be called to start
+ // the iteration at the beginning of the directory.
+ explicit DirReaderFallback(const char* directory_path) {}
+ // After construction, IsValid returns true iff the directory was
+ // successfully opened.
+ bool IsValid() const { return false; }
+ // Move to the next entry returning false if the iteration is complete.
+ bool Next() { return false; }
+ // Return the name of the current directory entry.
+ const char* name() { return 0; }
+ // Return the file descriptor which is being used.
+ int fd() const { return -1; }
+ // Returns true if this is a no-op fallback class (for testing).
+ static bool IsFallback() { return true; }
+};
+
+} // namespace base
+
+#endif // BASE_DIR_READER_FALLBACK_H_
diff --git a/ipc/chromium/src/base/dir_reader_linux.h b/ipc/chromium/src/base/dir_reader_linux.h
new file mode 100644
index 0000000000..a70ff3bb64
--- /dev/null
+++ b/ipc/chromium/src/base/dir_reader_linux.h
@@ -0,0 +1,95 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_DIR_READER_LINUX_H_
+#define BASE_DIR_READER_LINUX_H_
+#pragma once
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#include "base/logging.h"
+#include "base/eintr_wrapper.h"
+
+// See the comments in dir_reader_posix.h about this.
+
+namespace base {
+
+struct linux_dirent {
+ uint64_t d_ino;
+ int64_t d_off;
+ unsigned short d_reclen;
+ unsigned char d_type;
+ char d_name[0];
+};
+
+class DirReaderLinux {
+ public:
+ explicit DirReaderLinux(const char* directory_path)
+ : fd_(open(directory_path, O_RDONLY | O_DIRECTORY)),
+ offset_(0),
+ size_(0) {
+ memset(buf_, 0, sizeof(buf_));
+ }
+
+ ~DirReaderLinux() {
+ if (fd_ >= 0) {
+ if (IGNORE_EINTR(close(fd_)))
+ DLOG(ERROR) << "Failed to close directory handle";
+ }
+ }
+
+ bool IsValid() const { return fd_ >= 0; }
+
+ // Move to the next entry returning false if the iteration is complete.
+ bool Next() {
+ if (size_) {
+ linux_dirent* dirent = reinterpret_cast<linux_dirent*>(&buf_[offset_]);
+ offset_ += dirent->d_reclen;
+ }
+
+ if (offset_ != size_) return true;
+
+ const int r = syscall(__NR_getdents64, fd_, buf_, sizeof(buf_));
+ if (r == 0) return false;
+ if (r == -1) {
+ DLOG(ERROR) << "getdents64 returned an error: " << errno;
+ return false;
+ }
+ size_ = r;
+ offset_ = 0;
+ return true;
+ }
+
+ const char* name() const {
+ if (!size_) return NULL;
+
+ const linux_dirent* dirent =
+ reinterpret_cast<const linux_dirent*>(&buf_[offset_]);
+ return dirent->d_name;
+ }
+
+ int fd() const { return fd_; }
+
+ static bool IsFallback() { return false; }
+
+ private:
+ const int fd_;
+ union {
+ linux_dirent dirent_;
+ unsigned char buf_[512];
+ };
+ size_t offset_, size_;
+
+ DISALLOW_COPY_AND_ASSIGN(DirReaderLinux);
+};
+
+} // namespace base
+
+#endif // BASE_DIR_READER_LINUX_H_
diff --git a/ipc/chromium/src/base/dir_reader_posix.h b/ipc/chromium/src/base/dir_reader_posix.h
new file mode 100644
index 0000000000..2a2aae1140
--- /dev/null
+++ b/ipc/chromium/src/base/dir_reader_posix.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_DIR_READER_POSIX_H_
+#define BASE_DIR_READER_POSIX_H_
+#pragma once
+
+// This header provides a class, DirReaderPosix, which allows one to open and
+// read from directories without allocating memory. For the interface, see
+// the generic fallback in dir_reader_fallback.h.
+
+// Mac note: OS X has getdirentries, but it only works if we restrict Chrome to
+// 32-bit inodes. There is a getdirentries64 syscall in 10.6, but it's not
+// wrapped and the direct syscall interface is unstable. Using an unstable API
+// seems worse than falling back to enumerating all file descriptors so we will
+// probably never implement this on the Mac.
+
+#if defined(XP_LINUX)
+# include "base/dir_reader_linux.h"
+#elif (defined(__DragonFly__) || defined(XP_FREEBSD) || defined(XP_NETBSD) || \
+ defined(XP_OPENBSD)) && \
+ !defined(__GLIBC__)
+# include "base/dir_reader_bsd.h"
+#else
+# include "base/dir_reader_fallback.h"
+#endif
+
+namespace base {
+
+#if defined(XP_LINUX)
+typedef DirReaderLinux DirReaderPosix;
+#elif (defined(__DragonFly__) || defined(XP_FREEBSD) || defined(XP_NETBSD) || \
+ defined(XP_OPENBSD)) && \
+ !defined(__GLIBC__)
+typedef DirReaderBSD DirReaderPosix;
+#else
+typedef DirReaderFallback DirReaderPosix;
+#endif
+
+} // namespace base
+
+#endif // BASE_DIR_READER_POSIX_H_
diff --git a/ipc/chromium/src/base/eintr_wrapper.h b/ipc/chromium/src/base/eintr_wrapper.h
new file mode 100644
index 0000000000..8592efa8ce
--- /dev/null
+++ b/ipc/chromium/src/base/eintr_wrapper.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This provides a wrapper around system calls which may be interrupted by a
+// signal and return EINTR. See man 7 signal.
+//
+// On Windows, this wrapper macro does nothing because there are no
+// signals.
+//
+// Don't wrap close calls in HANDLE_EINTR. Use IGNORE_EINTR if the return
+// value of close is significant. See http://crbug.com/269623.
+
+#ifndef BASE_EINTR_WRAPPER_H_
+#define BASE_EINTR_WRAPPER_H_
+
+#if defined(XP_UNIX)
+
+# include <errno.h>
+
+# define HANDLE_EINTR(x) \
+ ({ \
+ decltype(x) eintr_wrapper_result; \
+ do { \
+ eintr_wrapper_result = (x); \
+ } while (eintr_wrapper_result == -1 && errno == EINTR); \
+ eintr_wrapper_result; \
+ })
+
+# define IGNORE_EINTR(x) \
+ ({ \
+ decltype(x) eintr_wrapper_result; \
+ do { \
+ eintr_wrapper_result = (x); \
+ if (eintr_wrapper_result == -1 && errno == EINTR) { \
+ eintr_wrapper_result = 0; \
+ } \
+ } while (0); \
+ eintr_wrapper_result; \
+ })
+
+# define HANDLE_RV_EINTR(x) \
+ ({ \
+ decltype(x) eintr_wrapper_result; \
+ do { \
+ eintr_wrapper_result = (x); \
+ } while (eintr_wrapper_result == EINTR); \
+ eintr_wrapper_result; \
+ })
+
+#else
+
+# define HANDLE_EINTR(x) (x)
+# define IGNORE_EINTR(x) (x)
+# define HANDLE_RV_EINTR(x) (x)
+
+#endif // XP_UNIX
+
+#endif // !BASE_EINTR_WRAPPER_H_
diff --git a/ipc/chromium/src/base/file_path.cc b/ipc/chromium/src/base/file_path.cc
new file mode 100644
index 0000000000..6796ad45d0
--- /dev/null
+++ b/ipc/chromium/src/base/file_path.cc
@@ -0,0 +1,313 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <fstream>
+
+#include "base/file_path.h"
+#include "base/logging.h"
+
+// These includes are just for the *Hack functions, and should be removed
+// when those functions are removed.
+#include "base/string_piece.h"
+#include "base/string_util.h"
+#include "base/sys_string_conversions.h"
+
+#if defined(FILE_PATH_USES_WIN_SEPARATORS)
+const FilePath::CharType FilePath::kSeparators[] = FILE_PATH_LITERAL("\\/");
+#else // FILE_PATH_USES_WIN_SEPARATORS
+const FilePath::CharType FilePath::kSeparators[] = FILE_PATH_LITERAL("/");
+#endif // FILE_PATH_USES_WIN_SEPARATORS
+
+const FilePath::CharType FilePath::kCurrentDirectory[] = FILE_PATH_LITERAL(".");
+const FilePath::CharType FilePath::kParentDirectory[] = FILE_PATH_LITERAL("..");
+
+const FilePath::CharType FilePath::kExtensionSeparator = FILE_PATH_LITERAL('.');
+
+namespace {
+
+// If this FilePath contains a drive letter specification, returns the
+// position of the last character of the drive letter specification,
+// otherwise returns npos. This can only be true on Windows, when a pathname
+// begins with a letter followed by a colon. On other platforms, this always
+// returns npos.
+FilePath::StringType::size_type FindDriveLetter(
+ const FilePath::StringType& path) {
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+ // This is dependent on an ASCII-based character set, but that's a
+ // reasonable assumption. iswalpha can be too inclusive here.
+ if (path.length() >= 2 && path[1] == L':' &&
+ ((path[0] >= L'A' && path[0] <= L'Z') ||
+ (path[0] >= L'a' && path[0] <= L'z'))) {
+ return 1;
+ }
+#endif // FILE_PATH_USES_DRIVE_LETTERS
+ return FilePath::StringType::npos;
+}
+
+bool IsPathAbsolute(const FilePath::StringType& path) {
+#if defined(FILE_PATH_USES_DRIVE_LETTERS)
+ FilePath::StringType::size_type letter = FindDriveLetter(path);
+ if (letter != FilePath::StringType::npos) {
+ // Look for a separator right after the drive specification.
+ return path.length() > letter + 1 &&
+ FilePath::IsSeparator(path[letter + 1]);
+ }
+ // Look for a pair of leading separators.
+ return path.length() > 1 && FilePath::IsSeparator(path[0]) &&
+ FilePath::IsSeparator(path[1]);
+#else // FILE_PATH_USES_DRIVE_LETTERS
+ // Look for a separator in the first position.
+ return path.length() > 0 && FilePath::IsSeparator(path[0]);
+#endif // FILE_PATH_USES_DRIVE_LETTERS
+}
+
+} // namespace
+
+bool FilePath::IsSeparator(CharType character) {
+ for (size_t i = 0; i < arraysize(kSeparators) - 1; ++i) {
+ if (character == kSeparators[i]) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// libgen's dirname and basename aren't guaranteed to be thread-safe and aren't
+// guaranteed to not modify their input strings, and in fact are implemented
+// differently in this regard on different platforms. Don't use them, but
+// adhere to their behavior.
+FilePath FilePath::DirName() const {
+ FilePath new_path(path_);
+ new_path.StripTrailingSeparatorsInternal();
+
+ // The drive letter, if any, always needs to remain in the output. If there
+ // is no drive letter, as will always be the case on platforms which do not
+ // support drive letters, letter will be npos, or -1, so the comparisons and
+ // resizes below using letter will still be valid.
+ StringType::size_type letter = FindDriveLetter(new_path.path_);
+
+ StringType::size_type last_separator = new_path.path_.find_last_of(
+ kSeparators, StringType::npos, arraysize(kSeparators) - 1);
+ if (last_separator == StringType::npos) {
+ // path_ is in the current directory.
+ new_path.path_.resize(letter + 1);
+ } else if (last_separator == letter + 1) {
+ // path_ is in the root directory.
+ new_path.path_.resize(letter + 2);
+ } else if (last_separator == letter + 2 &&
+ IsSeparator(new_path.path_[letter + 1])) {
+ // path_ is in "//" (possibly with a drive letter); leave the double
+ // separator intact indicating alternate root.
+ new_path.path_.resize(letter + 3);
+ } else if (last_separator != 0) {
+ // path_ is somewhere else, trim the basename.
+ new_path.path_.resize(last_separator);
+ }
+
+ new_path.StripTrailingSeparatorsInternal();
+ if (!new_path.path_.length()) new_path.path_ = kCurrentDirectory;
+
+ return new_path;
+}
+
+FilePath FilePath::BaseName() const {
+ FilePath new_path(path_);
+ new_path.StripTrailingSeparatorsInternal();
+
+ // The drive letter, if any, is always stripped.
+ StringType::size_type letter = FindDriveLetter(new_path.path_);
+ if (letter != StringType::npos) {
+ new_path.path_.erase(0, letter + 1);
+ }
+
+ // Keep everything after the final separator, but if the pathname is only
+ // one character and it's a separator, leave it alone.
+ StringType::size_type last_separator = new_path.path_.find_last_of(
+ kSeparators, StringType::npos, arraysize(kSeparators) - 1);
+ if (last_separator != StringType::npos &&
+ last_separator < new_path.path_.length() - 1) {
+ new_path.path_.erase(0, last_separator + 1);
+ }
+
+ return new_path;
+}
+
+FilePath::StringType FilePath::Extension() const {
+ // BaseName() calls StripTrailingSeparators, so cases like /foo.baz/// work.
+ StringType base = BaseName().value();
+
+ // Special case "." and ".."
+ if (base == kCurrentDirectory || base == kParentDirectory)
+ return StringType();
+
+ const StringType::size_type last_dot = base.rfind(kExtensionSeparator);
+ if (last_dot == StringType::npos) return StringType();
+ return StringType(base, last_dot);
+}
+
+FilePath FilePath::RemoveExtension() const {
+ StringType ext = Extension();
+ // It's important to check Extension() since that verifies that the
+ // kExtensionSeparator actually appeared in the last path component.
+ if (ext.empty()) return FilePath(path_);
+ // Since Extension() verified that the extension is in fact in the last path
+ // component, this substr will effectively strip trailing separators.
+ const StringType::size_type last_dot = path_.rfind(kExtensionSeparator);
+ return FilePath(path_.substr(0, last_dot));
+}
+
+FilePath FilePath::InsertBeforeExtension(const StringType& suffix) const {
+ if (suffix.empty()) return FilePath(path_);
+
+ if (path_.empty()) return FilePath();
+
+ StringType base = BaseName().value();
+ if (base.empty()) return FilePath();
+ if (*(base.end() - 1) == kExtensionSeparator) {
+ // Special case "." and ".."
+ if (base == kCurrentDirectory || base == kParentDirectory) {
+ return FilePath();
+ }
+ }
+
+ StringType ext = Extension();
+ StringType ret = RemoveExtension().value();
+ ret.append(suffix);
+ ret.append(ext);
+ return FilePath(ret);
+}
+
+FilePath FilePath::ReplaceExtension(const StringType& extension) const {
+ if (path_.empty()) return FilePath();
+
+ StringType base = BaseName().value();
+ if (base.empty()) return FilePath();
+ if (*(base.end() - 1) == kExtensionSeparator) {
+ // Special case "." and ".."
+ if (base == kCurrentDirectory || base == kParentDirectory) {
+ return FilePath();
+ }
+ }
+
+ FilePath no_ext = RemoveExtension();
+ // If the new extension is "" or ".", then just remove the current extension.
+ if (extension.empty() || extension == StringType(1, kExtensionSeparator))
+ return no_ext;
+
+ StringType str = no_ext.value();
+ if (extension[0] != kExtensionSeparator) str.append(1, kExtensionSeparator);
+ str.append(extension);
+ return FilePath(str);
+}
+
+FilePath FilePath::Append(const StringType& component) const {
+ DCHECK(!IsPathAbsolute(component));
+ if (path_.compare(kCurrentDirectory) == 0) {
+ // Append normally doesn't do any normalization, but as a special case,
+ // when appending to kCurrentDirectory, just return a new path for the
+ // component argument. Appending component to kCurrentDirectory would
+ // serve no purpose other than needlessly lengthening the path, and
+ // it's likely in practice to wind up with FilePath objects containing
+ // only kCurrentDirectory when calling DirName on a single relative path
+ // component.
+ return FilePath(component);
+ }
+
+ FilePath new_path(path_);
+ new_path.StripTrailingSeparatorsInternal();
+
+ // Don't append a separator if the path is empty (indicating the current
+ // directory) or if the path component is empty (indicating nothing to
+ // append).
+ if (component.length() > 0 && new_path.path_.length() > 0) {
+ // Don't append a separator if the path still ends with a trailing
+ // separator after stripping (indicating the root directory).
+ if (!IsSeparator(new_path.path_[new_path.path_.length() - 1])) {
+ // Don't append a separator if the path is just a drive letter.
+ if (FindDriveLetter(new_path.path_) + 1 != new_path.path_.length()) {
+ new_path.path_.append(1, kSeparators[0]);
+ }
+ }
+ }
+
+ new_path.path_.append(component);
+ return new_path;
+}
+
+FilePath FilePath::Append(const FilePath& component) const {
+ return Append(component.value());
+}
+
+FilePath FilePath::AppendASCII(const std::string& component) const {
+ DCHECK(IsStringASCII(component));
+#if defined(XP_WIN)
+ return Append(ASCIIToWide(component));
+#else
+ return Append(component);
+#endif
+}
+
+bool FilePath::IsAbsolute() const { return IsPathAbsolute(path_); }
+
+#if defined(XP_UNIX)
+// See file_path.h for a discussion of the encoding of paths on POSIX
+// platforms. These *Hack() functions are not quite correct, but they're
+// only temporary while we fix the remainder of the code.
+// Remember to remove the #includes at the top when you remove these.
+
+// static
+FilePath FilePath::FromWStringHack(const std::wstring& wstring) {
+ return FilePath(base::SysWideToNativeMB(wstring));
+}
+std::wstring FilePath::ToWStringHack() const {
+ return base::SysNativeMBToWide(path_);
+}
+#else
+// static
+FilePath FilePath::FromWStringHack(const std::wstring& wstring) {
+ return FilePath(wstring);
+}
+std::wstring FilePath::ToWStringHack() const { return path_; }
+#endif
+
+void FilePath::OpenInputStream(std::ifstream& stream) const {
+ stream.open(
+#ifndef __MINGW32__
+ path_.c_str(),
+#else
+ base::SysWideToNativeMB(path_).c_str(),
+#endif
+ std::ios::in | std::ios::binary);
+}
+
+FilePath FilePath::StripTrailingSeparators() const {
+ FilePath new_path(path_);
+ new_path.StripTrailingSeparatorsInternal();
+
+ return new_path;
+}
+
+void FilePath::StripTrailingSeparatorsInternal() {
+ // If there is no drive letter, start will be 1, which will prevent stripping
+ // the leading separator if there is only one separator. If there is a drive
+ // letter, start will be set appropriately to prevent stripping the first
+ // separator following the drive letter, if a separator immediately follows
+ // the drive letter.
+ StringType::size_type start = FindDriveLetter(path_) + 2;
+
+ StringType::size_type last_stripped = StringType::npos;
+ for (StringType::size_type pos = path_.length();
+ pos > start && IsSeparator(path_[pos - 1]); --pos) {
+ // If the string only has two separators and they're at the beginning,
+ // don't strip them, unless the string began with more than two separators.
+ if (pos != start + 1 || last_stripped == start + 2 ||
+ !IsSeparator(path_[start - 1])) {
+ path_.resize(pos - 1);
+ last_stripped = pos;
+ }
+ }
+}
diff --git a/ipc/chromium/src/base/file_path.h b/ipc/chromium/src/base/file_path.h
new file mode 100644
index 0000000000..3551fba6a9
--- /dev/null
+++ b/ipc/chromium/src/base/file_path.h
@@ -0,0 +1,248 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// FilePath is a container for pathnames stored in a platform's native string
+// type, providing containers for manipulation in according with the
+// platform's conventions for pathnames. It supports the following path
+// types:
+//
+// POSIX Windows
+// --------------- ----------------------------------
+// Fundamental type char[] wchar_t[]
+// Encoding unspecified* UTF-16
+// Separator / \, tolerant of /
+// Drive letters no case-insensitive A-Z followed by :
+// Alternate root // (surprise!) \\, for UNC paths
+//
+// * The encoding need not be specified on POSIX systems, although some
+// POSIX-compliant systems do specify an encoding. Mac OS X uses UTF-8.
+// Linux does not specify an encoding, but in practice, the locale's
+// character set may be used.
+//
+// FilePath objects are intended to be used anywhere paths are. An
+// application may pass FilePath objects around internally, masking the
+// underlying differences between systems, only differing in implementation
+// where interfacing directly with the system. For example, a single
+// OpenFile(const FilePath &) function may be made available, allowing all
+// callers to operate without regard to the underlying implementation. On
+// POSIX-like platforms, OpenFile might wrap fopen, and on Windows, it might
+// wrap _wfopen_s, perhaps both by calling file_path.value().c_str(). This
+// allows each platform to pass pathnames around without requiring conversions
+// between encodings, which has an impact on performance, but more imporantly,
+// has an impact on correctness on platforms that do not have well-defined
+// encodings for pathnames.
+//
+// Several methods are available to perform common operations on a FilePath
+// object, such as determining the parent directory (DirName), isolating the
+// final path component (BaseName), and appending a relative pathname string
+// to an existing FilePath object (Append). These methods are highly
+// recommended over attempting to split and concatenate strings directly.
+// These methods are based purely on string manipulation and knowledge of
+// platform-specific pathname conventions, and do not consult the filesystem
+// at all, making them safe to use without fear of blocking on I/O operations.
+// These methods do not function as mutators but instead return distinct
+// instances of FilePath objects, and are therefore safe to use on const
+// objects. The objects themselves are safe to share between threads.
+//
+// To aid in initialization of FilePath objects from string literals, a
+// FILE_PATH_LITERAL macro is provided, which accounts for the difference
+// between char[]-based pathnames on POSIX systems and wchar_t[]-based
+// pathnames on Windows.
+//
+// Because a FilePath object should not be instantiated at the global scope,
+// instead, use a FilePath::CharType[] and initialize it with
+// FILE_PATH_LITERAL. At runtime, a FilePath object can be created from the
+// character array. Example:
+//
+// | const FilePath::CharType kLogFileName[] = FILE_PATH_LITERAL("log.txt");
+// |
+// | void Function() {
+// | FilePath log_file_path(kLogFileName);
+// | [...]
+// | }
+
+#ifndef BASE_FILE_PATH_H_
+#define BASE_FILE_PATH_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+
+// Windows-style drive letter support and pathname separator characters can be
+// enabled and disabled independently, to aid testing. These #defines are
+// here so that the same setting can be used in both the implementation and
+// in the unit test.
+#if defined(XP_WIN)
+# define FILE_PATH_USES_DRIVE_LETTERS
+# define FILE_PATH_USES_WIN_SEPARATORS
+#endif // XP_WIN
+
+// An abstraction to isolate users from the differences between native
+// pathnames on different platforms.
+class FilePath {
+ public:
+#if defined(XP_UNIX)
+ // On most platforms, native pathnames are char arrays, and the encoding
+ // may or may not be specified. On Mac OS X, native pathnames are encoded
+ // in UTF-8.
+ typedef std::string StringType;
+#else
+ // On Windows, for Unicode-aware applications, native pathnames are wchar_t
+ // arrays encoded in UTF-16.
+ typedef std::wstring StringType;
+#endif
+
+ typedef StringType::value_type CharType;
+
+ // Null-terminated array of separators used to separate components in
+ // hierarchical paths. Each character in this array is a valid separator,
+ // but kSeparators[0] is treated as the canonical separator and will be used
+ // when composing pathnames.
+ static const CharType kSeparators[];
+
+ // A special path component meaning "this directory."
+ static const CharType kCurrentDirectory[];
+
+ // A special path component meaning "the parent directory."
+ static const CharType kParentDirectory[];
+
+ // The character used to identify a file extension.
+ static const CharType kExtensionSeparator;
+
+ FilePath() {}
+ FilePath(const FilePath& that) : path_(that.path_) {}
+ explicit FilePath(const StringType& path) : path_(path) {}
+
+#if defined(XP_WIN)
+ explicit FilePath(const wchar_t* path) : path_(path) {}
+#endif
+
+ FilePath& operator=(const FilePath& that) {
+ path_ = that.path_;
+ return *this;
+ }
+
+ bool operator==(const FilePath& that) const { return path_ == that.path_; }
+
+ bool operator!=(const FilePath& that) const { return path_ != that.path_; }
+
+ // Required for some STL containers and operations
+ bool operator<(const FilePath& that) const { return path_ < that.path_; }
+
+ const StringType& value() const { return path_; }
+
+ bool empty() const { return path_.empty(); }
+
+ // Returns true if |character| is in kSeparators.
+ static bool IsSeparator(CharType character);
+
+ // Returns a FilePath corresponding to the directory containing the path
+ // named by this object, stripping away the file component. If this object
+ // only contains one component, returns a FilePath identifying
+ // kCurrentDirectory. If this object already refers to the root directory,
+ // returns a FilePath identifying the root directory.
+ FilePath DirName() const;
+
+ // Returns a FilePath corresponding to the last path component of this
+ // object, either a file or a directory. If this object already refers to
+ // the root directory, returns a FilePath identifying the root directory;
+ // this is the only situation in which BaseName will return an absolute path.
+ FilePath BaseName() const;
+
+ // Returns ".jpg" for path "C:\pics\jojo.jpg", or an empty string if
+ // the file has no extension. If non-empty, Extension() will always start
+ // with precisely one ".". The following code should always work regardless
+ // of the value of path.
+ // new_path = path.RemoveExtension().value().append(path.Extension());
+ // ASSERT(new_path == path.value());
+ // NOTE: this is different from the original file_util implementation which
+ // returned the extension without a leading "." ("jpg" instead of ".jpg")
+ StringType Extension() const;
+
+ // Returns "C:\pics\jojo" for path "C:\pics\jojo.jpg"
+ // NOTE: this is slightly different from the similar file_util implementation
+ // which returned simply 'jojo'.
+ FilePath RemoveExtension() const;
+
+ // Inserts |suffix| after the file name portion of |path| but before the
+ // extension. Returns "" if BaseName() == "." or "..".
+ // Examples:
+ // path == "C:\pics\jojo.jpg" suffix == " (1)", returns "C:\pics\jojo (1).jpg"
+ // path == "jojo.jpg" suffix == " (1)", returns "jojo (1).jpg"
+ // path == "C:\pics\jojo" suffix == " (1)", returns "C:\pics\jojo (1)"
+ // path == "C:\pics.old\jojo" suffix == " (1)", returns "C:\pics.old\jojo (1)"
+ FilePath InsertBeforeExtension(const StringType& suffix) const;
+
+ // Replaces the extension of |file_name| with |extension|. If |file_name|
+ // does not have an extension, them |extension| is added. If |extension| is
+ // empty, then the extension is removed from |file_name|.
+ // Returns "" if BaseName() == "." or "..".
+ FilePath ReplaceExtension(const StringType& extension) const;
+
+ // Returns a FilePath by appending a separator and the supplied path
+ // component to this object's path. Append takes care to avoid adding
+ // excessive separators if this object's path already ends with a separator.
+ // If this object's path is kCurrentDirectory, a new FilePath corresponding
+ // only to |component| is returned. |component| must be a relative path;
+ // it is an error to pass an absolute path.
+ FilePath Append(const StringType& component) const WARN_UNUSED_RESULT;
+ FilePath Append(const FilePath& component) const WARN_UNUSED_RESULT;
+
+ // Although Windows StringType is std::wstring, since the encoding it uses for
+ // paths is well defined, it can handle ASCII path components as well.
+ // Mac uses UTF8, and since ASCII is a subset of that, it works there as well.
+ // On Linux, although it can use any 8-bit encoding for paths, we assume that
+ // ASCII is a valid subset, regardless of the encoding, since many operating
+ // system paths will always be ASCII.
+ FilePath AppendASCII(const std::string& component) const WARN_UNUSED_RESULT;
+
+ // Returns true if this FilePath contains an absolute path. On Windows, an
+ // absolute path begins with either a drive letter specification followed by
+ // a separator character, or with two separator characters. On POSIX
+ // platforms, an absolute path begins with a separator character.
+ bool IsAbsolute() const;
+
+ // Returns a copy of this FilePath that does not end with a trailing
+ // separator.
+ FilePath StripTrailingSeparators() const;
+
+ // Calls open on given ifstream instance
+ void OpenInputStream(std::ifstream& stream) const;
+
+ // Older Chromium code assumes that paths are always wstrings.
+ // This function converts a wstring to a FilePath, and is useful to smooth
+ // porting that old code to the FilePath API.
+ // It has "Hack" in its name so people feel bad about using it.
+ // TODO(port): remove these functions.
+ static FilePath FromWStringHack(const std::wstring& wstring);
+
+ // Older Chromium code assumes that paths are always wstrings.
+ // This function produces a wstring from a FilePath, and is useful to smooth
+ // porting that old code to the FilePath API.
+ // It has "Hack" in its name so people feel bad about using it.
+ // TODO(port): remove these functions.
+ std::wstring ToWStringHack() const;
+
+ private:
+ // Remove trailing separators from this object. If the path is absolute, it
+ // will never be stripped any more than to refer to the absolute root
+ // directory, so "////" will become "/", not "". A leading pair of
+ // separators is never stripped, to support alternate roots. This is used to
+ // support UNC paths on Windows.
+ void StripTrailingSeparatorsInternal();
+
+ StringType path_;
+};
+
+// Macros for string literal initialization of FilePath::CharType[].
+#if defined(XP_UNIX)
+# define FILE_PATH_LITERAL(x) x
+#else
+# define FILE_PATH_LITERAL(x) L##x
+#endif
+
+#endif // BASE_FILE_PATH_H_
diff --git a/ipc/chromium/src/base/histogram.cc b/ipc/chromium/src/base/histogram.cc
new file mode 100644
index 0000000000..1ddb788b41
--- /dev/null
+++ b/ipc/chromium/src/base/histogram.cc
@@ -0,0 +1,638 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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.
+
+// Histogram is an object that aggregates statistics, and can summarize them in
+// various forms, including ASCII graphical, HTML, and numerically (as a
+// vector of numbers corresponding to each of the aggregating buckets).
+// See header file for details and examples.
+
+#include "base/histogram.h"
+
+#include <math.h>
+
+#include <algorithm>
+#include <string>
+
+#include "base/logging.h"
+#include "base/pickle.h"
+#include "base/string_util.h"
+#include "base/logging.h"
+
+namespace base {
+
+#define CHECK_GT DCHECK_GT
+#define CHECK_LT DCHECK_LT
+
+// Static table of checksums for all possible 8 bit bytes.
+const uint32_t Histogram::kCrcTable[256] = {
+ 0x0, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x76dc419L,
+ 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0xedb8832L, 0x79dcb8a4L,
+ 0xe0d5e91eL, 0x97d2d988L, 0x9b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+ 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+ 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+ 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+ 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+ 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+ 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+ 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+ 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+ 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+ 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+ 0x1db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x6b6b51fL,
+ 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0xf00f934L, 0x9609a88eL,
+ 0xe10e9818L, 0x7f6a0dbbL, 0x86d3d2dL, 0x91646c97L, 0xe6635c01L,
+ 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+ 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+ 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+ 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+ 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+ 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+ 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+ 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+ 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+ 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+ 0x3b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x4db2615L,
+ 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0xd6d6a3eL, 0x7a6a5aa8L,
+ 0xe40ecf0bL, 0x9309ff9dL, 0xa00ae27L, 0x7d079eb1L, 0xf00f9344L,
+ 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+ 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+ 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+ 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+ 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+ 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+ 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+ 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+ 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+ 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+ 0x26d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x5005713L,
+ 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0xcb61b38L, 0x92d28e9bL,
+ 0xe5d5be0dL, 0x7cdcefb7L, 0xbdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+ 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+ 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+ 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+ 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+ 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+ 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+ 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+ 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+ 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+ 0x2d02ef8dL,
+};
+
+typedef Histogram::Count Count;
+
+// static
+const size_t Histogram::kBucketCount_MAX = 16384u;
+
+Histogram* Histogram::FactoryGet(Sample minimum, Sample maximum,
+ size_t bucket_count, Flags flags,
+ const int* buckets) {
+ DCHECK(buckets);
+ Histogram* histogram(NULL);
+
+ // Defensive code.
+ if (minimum < 1) minimum = 1;
+ if (maximum > kSampleType_MAX - 1) maximum = kSampleType_MAX - 1;
+
+ histogram = new Histogram(minimum, maximum, bucket_count);
+ histogram->InitializeBucketRangeFromData(buckets);
+ histogram->SetFlags(flags);
+
+ DCHECK_EQ(HISTOGRAM, histogram->histogram_type());
+ DCHECK(histogram->HasConstructorArguments(minimum, maximum, bucket_count));
+ return histogram;
+}
+
+void Histogram::Add(int value) {
+ if (value > kSampleType_MAX - 1) value = kSampleType_MAX - 1;
+ if (value < 0) value = 0;
+ size_t index = BucketIndex(value);
+ DCHECK_GE(value, ranges(index));
+ DCHECK_LT(value, ranges(index + 1));
+ Accumulate(value, 1, index);
+}
+
+void Histogram::Subtract(int value) {
+ if (value > kSampleType_MAX - 1) value = kSampleType_MAX - 1;
+ if (value < 0) value = 0;
+ size_t index = BucketIndex(value);
+ DCHECK_GE(value, ranges(index));
+ DCHECK_LT(value, ranges(index + 1));
+ Accumulate(value, -1, index);
+}
+
+void Histogram::AddBoolean(bool value) { DCHECK(false); }
+
+void Histogram::AddSampleSet(const SampleSet& sample) { sample_.Add(sample); }
+
+void Histogram::Clear() { sample_.Clear(); }
+
+void Histogram::SetRangeDescriptions(const DescriptionPair descriptions[]) {
+ DCHECK(false);
+}
+
+//------------------------------------------------------------------------------
+// Methods for the validating a sample and a related histogram.
+//------------------------------------------------------------------------------
+
+Histogram::Inconsistencies Histogram::FindCorruption(
+ const SampleSet& snapshot) const {
+ int inconsistencies = NO_INCONSISTENCIES;
+ Sample previous_range = -1; // Bottom range is always 0.
+ int64_t count = 0;
+ for (size_t index = 0; index < bucket_count(); ++index) {
+ count += snapshot.counts(index);
+ int new_range = ranges(index);
+ if (previous_range >= new_range) inconsistencies |= BUCKET_ORDER_ERROR;
+ previous_range = new_range;
+ }
+
+ if (!HasValidRangeChecksum()) inconsistencies |= RANGE_CHECKSUM_ERROR;
+
+ int64_t delta64 = snapshot.redundant_count() - count;
+ if (delta64 != 0) {
+ int delta = static_cast<int>(delta64);
+ if (delta != delta64) delta = INT_MAX; // Flag all giant errors as INT_MAX.
+ // Since snapshots of histograms are taken asynchronously relative to
+ // sampling (and snapped from different threads), it is pretty likely that
+ // we'll catch a redundant count that doesn't match the sample count. We
+ // allow for a certain amount of slop before flagging this as an
+ // inconsistency. Even with an inconsistency, we'll snapshot it again (for
+ // UMA in about a half hour, so we'll eventually get the data, if it was
+ // not the result of a corruption. If histograms show that 1 is "too tight"
+ // then we may try to use 2 or 3 for this slop value.
+ const int kCommonRaceBasedCountMismatch = 1;
+ if (delta > 0) {
+ if (delta > kCommonRaceBasedCountMismatch)
+ inconsistencies |= COUNT_HIGH_ERROR;
+ } else {
+ DCHECK_GT(0, delta);
+ if (-delta > kCommonRaceBasedCountMismatch)
+ inconsistencies |= COUNT_LOW_ERROR;
+ }
+ }
+ return static_cast<Inconsistencies>(inconsistencies);
+}
+
+Histogram::ClassType Histogram::histogram_type() const { return HISTOGRAM; }
+
+Histogram::Sample Histogram::ranges(size_t i) const { return ranges_[i]; }
+
+size_t Histogram::bucket_count() const { return bucket_count_; }
+
+Histogram::SampleSet Histogram::SnapshotSample() const {
+ return sample_.Clone();
+}
+
+bool Histogram::HasConstructorArguments(Sample minimum, Sample maximum,
+ size_t bucket_count) {
+ return ((minimum == declared_min_) && (maximum == declared_max_) &&
+ (bucket_count == bucket_count_));
+}
+
+bool Histogram::HasConstructorTimeDeltaArguments(TimeDelta minimum,
+ TimeDelta maximum,
+ size_t bucket_count) {
+ return ((minimum.InMilliseconds() == declared_min_) &&
+ (maximum.InMilliseconds() == declared_max_) &&
+ (bucket_count == bucket_count_));
+}
+
+bool Histogram::HasValidRangeChecksum() const {
+ return CalculateRangeChecksum() == range_checksum_;
+}
+
+size_t Histogram::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) {
+ size_t n = 0;
+ n += aMallocSizeOf(this);
+ n += sample_.SizeOfExcludingThis(aMallocSizeOf);
+ return n;
+}
+
+size_t Histogram::SampleSet::SizeOfExcludingThis(
+ mozilla::MallocSizeOf aMallocSizeOf) {
+ return counts_.ShallowSizeOfExcludingThis(aMallocSizeOf);
+}
+
+Histogram::Histogram(Sample minimum, Sample maximum, size_t bucket_count)
+ : declared_min_(minimum),
+ declared_max_(maximum),
+ bucket_count_(bucket_count),
+ flags_(kNoFlags),
+ range_checksum_(0) {
+ Initialize();
+}
+
+Histogram::Histogram(TimeDelta minimum, TimeDelta maximum, size_t bucket_count)
+ : declared_min_(static_cast<int>(minimum.InMilliseconds())),
+ declared_max_(static_cast<int>(maximum.InMilliseconds())),
+ bucket_count_(bucket_count),
+ flags_(kNoFlags),
+ range_checksum_(0) {
+ Initialize();
+}
+
+Histogram::~Histogram() {
+ // Just to make sure most derived class did this properly...
+ DCHECK(ValidateBucketRanges());
+}
+
+void Histogram::InitializeBucketRangeFromData(const int* buckets) {
+ ranges_ = buckets;
+ ResetRangeChecksum();
+ DCHECK(ValidateBucketRanges());
+}
+
+bool Histogram::PrintEmptyBucket(size_t index) const { return true; }
+
+size_t Histogram::BucketIndex(Sample value) const {
+ // Use simple binary search. This is very general, but there are better
+ // approaches if we knew that the buckets were linearly distributed.
+ DCHECK_LE(ranges(0), value);
+ DCHECK_GT(ranges(bucket_count()), value);
+ size_t under = 0;
+ size_t over = bucket_count();
+ size_t mid;
+
+ do {
+ DCHECK_GE(over, under);
+ mid = under + (over - under) / 2;
+ if (mid == under) break;
+ if (ranges(mid) <= value)
+ under = mid;
+ else
+ over = mid;
+ } while (true);
+
+ DCHECK_LE(ranges(mid), value);
+ CHECK_GT(ranges(mid + 1), value);
+ return mid;
+}
+
+// Use the actual bucket widths (like a linear histogram) until the widths get
+// over some transition value, and then use that transition width. Exponentials
+// get so big so fast (and we don't expect to see a lot of entries in the large
+// buckets), so we need this to make it possible to see what is going on and
+// not have 0-graphical-height buckets.
+double Histogram::GetBucketSize(Count current, size_t i) const {
+ DCHECK_GT(ranges(i + 1), ranges(i));
+ static const double kTransitionWidth = 5;
+ double denominator = ranges(i + 1) - ranges(i);
+ if (denominator > kTransitionWidth)
+ denominator = kTransitionWidth; // Stop trying to normalize.
+ return current / denominator;
+}
+
+void Histogram::ResetRangeChecksum() {
+ range_checksum_ = CalculateRangeChecksum();
+}
+
+const std::string Histogram::GetAsciiBucketRange(size_t i) const {
+ std::string result;
+ if (kHexRangePrintingFlag & flags_)
+ StringAppendF(&result, "%#x", ranges(i));
+ else
+ StringAppendF(&result, "%d", ranges(i));
+ return result;
+}
+
+// Update histogram data with new sample.
+void Histogram::Accumulate(Sample value, Count count, size_t index) {
+ sample_.Accumulate(value, count, index);
+}
+
+bool Histogram::ValidateBucketRanges() const {
+ // Standard assertions that all bucket ranges should satisfy.
+ DCHECK_EQ(0, ranges_[bucket_count_ + 1]);
+ DCHECK_EQ(0, ranges_[0]);
+ DCHECK_EQ(declared_min(), ranges_[1]);
+ DCHECK_EQ(declared_max(), ranges_[bucket_count_ - 1]);
+ DCHECK_EQ(kSampleType_MAX, ranges_[bucket_count_]);
+ return true;
+}
+
+uint32_t Histogram::CalculateRangeChecksum() const {
+ DCHECK_EQ(0, ranges_[bucket_count_ + 1]);
+ uint32_t checksum =
+ static_cast<uint32_t>(bucket_count_ + 1); // Seed checksum.
+ for (size_t index = 0; index < bucket_count(); ++index)
+ checksum = Crc32(checksum, ranges(index));
+ return checksum;
+}
+
+void Histogram::Initialize() {
+ sample_.Resize(*this);
+ if (declared_min_ < 1) declared_min_ = 1;
+ if (declared_max_ > kSampleType_MAX - 1) declared_max_ = kSampleType_MAX - 1;
+ DCHECK_LE(declared_min_, declared_max_);
+ DCHECK_GT(bucket_count_, 1u);
+ CHECK_LT(bucket_count_, kBucketCount_MAX);
+ size_t maximal_bucket_count = declared_max_ - declared_min_ + 2;
+ DCHECK_LE(bucket_count_, maximal_bucket_count);
+}
+
+// We generate the CRC-32 using the low order bits to select whether to XOR in
+// the reversed polynomial 0xedb88320L. This is nice and simple, and allows us
+// to keep the quotient in a uint32_t. Since we're not concerned about the
+// nature of corruptions (i.e., we don't care about bit sequencing, since we are
+// handling memory changes, which are more grotesque) so we don't bother to
+// get the CRC correct for big-endian vs little-ending calculations. All we
+// need is a nice hash, that tends to depend on all the bits of the sample, with
+// very little chance of changes in one place impacting changes in another
+// place.
+uint32_t Histogram::Crc32(uint32_t sum, Histogram::Sample range) {
+ const bool kUseRealCrc = true; // TODO(jar): Switch to false and watch stats.
+ if (kUseRealCrc) {
+ union {
+ Histogram::Sample range;
+ unsigned char bytes[sizeof(Histogram::Sample)];
+ } converter;
+ converter.range = range;
+ for (size_t i = 0; i < sizeof(converter); ++i)
+ sum = kCrcTable[(sum & 0xff) ^ converter.bytes[i]] ^ (sum >> 8);
+ } else {
+ // Use hash techniques provided in ReallyFastHash, except we don't care
+ // about "avalanching" (which would worsten the hash, and add collisions),
+ // and we don't care about edge cases since we have an even number of bytes.
+ union {
+ Histogram::Sample range;
+ uint16_t ints[sizeof(Histogram::Sample) / 2];
+ } converter;
+ DCHECK_EQ(sizeof(Histogram::Sample), sizeof(converter));
+ converter.range = range;
+ sum += converter.ints[0];
+ sum = (sum << 16) ^ sum ^ (static_cast<uint32_t>(converter.ints[1]) << 11);
+ sum += sum >> 11;
+ }
+ return sum;
+}
+
+//------------------------------------------------------------------------------
+// Private methods
+
+double Histogram::GetPeakBucketSize(const SampleSet& snapshot) const {
+ double max = 0;
+ for (size_t i = 0; i < bucket_count(); ++i) {
+ double current_size = GetBucketSize(snapshot.counts(i), i);
+ if (current_size > max) max = current_size;
+ }
+ return max;
+}
+
+//------------------------------------------------------------------------------
+// Methods for the Histogram::SampleSet class
+//------------------------------------------------------------------------------
+
+Histogram::SampleSet::SampleSet() : sum_(0), redundant_count_(0) {}
+
+Histogram::SampleSet::~SampleSet() = default;
+
+void Histogram::SampleSet::Resize(const Histogram& histogram) {
+ size_t oldSize = counts_.Length();
+ counts_.SetLength(histogram.bucket_count());
+
+ for (size_t i = oldSize; i < histogram.bucket_count(); ++i) counts_[i] = 0;
+}
+
+void Histogram::SampleSet::Accumulate(Sample value, Count count, size_t index) {
+ DCHECK(count == 1 || count == -1);
+ counts_[index] += count;
+ redundant_count_ += count;
+ sum_ += static_cast<int64_t>(count) * value;
+ DCHECK_GE(counts_[index], 0);
+ DCHECK_GE(sum_, 0);
+ DCHECK_GE(redundant_count_, 0);
+}
+
+Count Histogram::SampleSet::TotalCount() const {
+ Count total = 0;
+ for (Counts::const_iterator it = counts_.begin(); it != counts_.end(); ++it) {
+ total += *it;
+ }
+ return total;
+}
+
+void Histogram::SampleSet::Add(const SampleSet& other) {
+ DCHECK_EQ(counts_.Length(), other.counts_.Length());
+ sum_ += other.sum_;
+ redundant_count_ += other.redundant_count_;
+ for (size_t index = 0; index < counts_.Length(); ++index)
+ counts_[index] += other.counts_[index];
+}
+
+//------------------------------------------------------------------------------
+// LinearHistogram: This histogram uses a traditional set of evenly spaced
+// buckets.
+//------------------------------------------------------------------------------
+
+LinearHistogram::~LinearHistogram() = default;
+
+Histogram* LinearHistogram::FactoryGet(Sample minimum, Sample maximum,
+ size_t bucket_count, Flags flags,
+ const int* buckets) {
+ Histogram* histogram(NULL);
+
+ if (minimum < 1) minimum = 1;
+ if (maximum > kSampleType_MAX - 1) maximum = kSampleType_MAX - 1;
+
+ LinearHistogram* linear_histogram =
+ new LinearHistogram(minimum, maximum, bucket_count);
+ linear_histogram->InitializeBucketRangeFromData(buckets);
+ linear_histogram->SetFlags(flags);
+ histogram = linear_histogram;
+
+ DCHECK_EQ(LINEAR_HISTOGRAM, histogram->histogram_type());
+ DCHECK(histogram->HasConstructorArguments(minimum, maximum, bucket_count));
+ return histogram;
+}
+
+Histogram::ClassType LinearHistogram::histogram_type() const {
+ return LINEAR_HISTOGRAM;
+}
+
+void LinearHistogram::Accumulate(Sample value, Count count, size_t index) {
+ sample_.Accumulate(value, count, index);
+}
+
+void LinearHistogram::SetRangeDescriptions(
+ const DescriptionPair descriptions[]) {
+ for (int i = 0; descriptions[i].description; ++i) {
+ bucket_description_[descriptions[i].sample] = descriptions[i].description;
+ }
+}
+
+LinearHistogram::LinearHistogram(Sample minimum, Sample maximum,
+ size_t bucket_count)
+ : Histogram(minimum >= 1 ? minimum : 1, maximum, bucket_count) {}
+
+LinearHistogram::LinearHistogram(TimeDelta minimum, TimeDelta maximum,
+ size_t bucket_count)
+ : Histogram(minimum >= TimeDelta::FromMilliseconds(1)
+ ? minimum
+ : TimeDelta::FromMilliseconds(1),
+ maximum, bucket_count) {}
+
+double LinearHistogram::GetBucketSize(Count current, size_t i) const {
+ DCHECK_GT(ranges(i + 1), ranges(i));
+ // Adjacent buckets with different widths would have "surprisingly" many (few)
+ // samples in a histogram if we didn't normalize this way.
+ double denominator = ranges(i + 1) - ranges(i);
+ return current / denominator;
+}
+
+const std::string LinearHistogram::GetAsciiBucketRange(size_t i) const {
+ int range = ranges(i);
+ BucketDescriptionMap::const_iterator it = bucket_description_.find(range);
+ if (it == bucket_description_.end()) return Histogram::GetAsciiBucketRange(i);
+ return it->second;
+}
+
+bool LinearHistogram::PrintEmptyBucket(size_t index) const {
+ return bucket_description_.find(ranges(index)) == bucket_description_.end();
+}
+
+//------------------------------------------------------------------------------
+// This section provides implementation for BooleanHistogram.
+//------------------------------------------------------------------------------
+
+Histogram* BooleanHistogram::FactoryGet(Flags flags, const int* buckets) {
+ Histogram* histogram(NULL);
+
+ BooleanHistogram* tentative_histogram = new BooleanHistogram();
+ tentative_histogram->InitializeBucketRangeFromData(buckets);
+ tentative_histogram->SetFlags(flags);
+ histogram = tentative_histogram;
+
+ DCHECK_EQ(BOOLEAN_HISTOGRAM, histogram->histogram_type());
+ return histogram;
+}
+
+Histogram::ClassType BooleanHistogram::histogram_type() const {
+ return BOOLEAN_HISTOGRAM;
+}
+
+void BooleanHistogram::AddBoolean(bool value) { Add(value ? 1 : 0); }
+
+BooleanHistogram::BooleanHistogram() : LinearHistogram(1, 2, 3) {}
+
+void BooleanHistogram::Accumulate(Sample value, Count count, size_t index) {
+ // Callers will have computed index based on the non-booleanified value.
+ // So we need to adjust the index manually.
+ LinearHistogram::Accumulate(!!value, count, value ? 1 : 0);
+}
+
+//------------------------------------------------------------------------------
+// FlagHistogram:
+//------------------------------------------------------------------------------
+
+Histogram* FlagHistogram::FactoryGet(Flags flags, const int* buckets) {
+ Histogram* h(nullptr);
+
+ FlagHistogram* fh = new FlagHistogram();
+ fh->InitializeBucketRangeFromData(buckets);
+ fh->SetFlags(flags);
+ size_t zero_index = fh->BucketIndex(0);
+ fh->LinearHistogram::Accumulate(0, 1, zero_index);
+ h = fh;
+
+ return h;
+}
+
+FlagHistogram::FlagHistogram() : mSwitched(false) {}
+
+Histogram::ClassType FlagHistogram::histogram_type() const {
+ return FLAG_HISTOGRAM;
+}
+
+void FlagHistogram::Accumulate(Sample value, Count count, size_t index) {
+ if (mSwitched) {
+ return;
+ }
+
+ mSwitched = true;
+ DCHECK_EQ(value, 1);
+ LinearHistogram::Accumulate(value, 1, index);
+ size_t zero_index = BucketIndex(0);
+ LinearHistogram::Accumulate(0, -1, zero_index);
+}
+
+void FlagHistogram::AddSampleSet(const SampleSet& sample) {
+ DCHECK_EQ(bucket_count(), sample.size());
+ // We can't be sure the SampleSet provided came from another FlagHistogram,
+ // so we take the following steps:
+ // - If our flag has already been set do nothing.
+ // - Set our flag if the following hold:
+ // - The sum of the counts in the provided SampleSet is 1.
+ // - The bucket index for that single value is the same as the index
+ // where we
+ // would place our set flag.
+ // - Otherwise, take no action.
+
+ if (mSwitched) {
+ return;
+ }
+
+ if (sample.sum() != 1) {
+ return;
+ }
+
+ size_t one_index = BucketIndex(1);
+ if (sample.counts(one_index) == 1) {
+ Accumulate(1, 1, one_index);
+ }
+}
+
+void FlagHistogram::Clear() {
+ Histogram::Clear();
+
+ mSwitched = false;
+ size_t zero_index = BucketIndex(0);
+ LinearHistogram::Accumulate(0, 1, zero_index);
+}
+
+//------------------------------------------------------------------------------
+// CountHistogram:
+//------------------------------------------------------------------------------
+
+Histogram* CountHistogram::FactoryGet(Flags flags, const int* buckets) {
+ Histogram* h(nullptr);
+
+ CountHistogram* fh = new CountHistogram();
+ fh->InitializeBucketRangeFromData(buckets);
+ fh->SetFlags(flags);
+ h = fh;
+
+ return h;
+}
+
+CountHistogram::CountHistogram() : LinearHistogram(1, 2, 3) {}
+
+Histogram::ClassType CountHistogram::histogram_type() const {
+ return COUNT_HISTOGRAM;
+}
+
+void CountHistogram::Accumulate(Sample value, Count count, size_t index) {
+ size_t zero_index = BucketIndex(0);
+ LinearHistogram::Accumulate(value, 1, zero_index);
+}
+
+void CountHistogram::AddSampleSet(const SampleSet& sample) {
+ DCHECK_EQ(bucket_count(), sample.size());
+ // We can't be sure the SampleSet provided came from another CountHistogram,
+ // so we at least check that the unused buckets are empty.
+
+ const size_t indices[] = {BucketIndex(0), BucketIndex(1), BucketIndex(2)};
+
+ if (sample.counts(indices[1]) != 0 || sample.counts(indices[2]) != 0) {
+ return;
+ }
+
+ if (sample.counts(indices[0]) != 0) {
+ Histogram::AddSampleSet(sample);
+ }
+}
+
+} // namespace base
diff --git a/ipc/chromium/src/base/histogram.h b/ipc/chromium/src/base/histogram.h
new file mode 100644
index 0000000000..f9ea21c8df
--- /dev/null
+++ b/ipc/chromium/src/base/histogram.h
@@ -0,0 +1,432 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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.
+
+// Histogram is an object that aggregates statistics, and can summarize them in
+// various forms, including ASCII graphical, HTML, and numerically (as a
+// vector of numbers corresponding to each of the aggregating buckets).
+
+// It supports calls to accumulate either time intervals (which are processed
+// as integral number of milliseconds), or arbitrary integral units.
+
+// The default layout of buckets is exponential. For example, buckets might
+// contain (sequentially) the count of values in the following intervals:
+// [0,1), [1,2), [2,4), [4,8), [8,16), [16,32), [32,64), [64,infinity)
+// That bucket allocation would actually result from construction of a histogram
+// for values between 1 and 64, with 8 buckets, such as:
+// Histogram count(L"some name", 1, 64, 8);
+// Note that the underflow bucket [0,1) and the overflow bucket [64,infinity)
+// are not counted by the constructor in the user supplied "bucket_count"
+// argument.
+// The above example has an exponential ratio of 2 (doubling the bucket width
+// in each consecutive bucket. The Histogram class automatically calculates
+// the smallest ratio that it can use to construct the number of buckets
+// selected in the constructor. An another example, if you had 50 buckets,
+// and millisecond time values from 1 to 10000, then the ratio between
+// consecutive bucket widths will be approximately somewhere around the 50th
+// root of 10000. This approach provides very fine grain (narrow) buckets
+// at the low end of the histogram scale, but allows the histogram to cover a
+// gigantic range with the addition of very few buckets.
+
+// Histograms use a pattern involving a function static variable, that is a
+// pointer to a histogram. This static is explicitly initialized on any thread
+// that detects a uninitialized (NULL) pointer. The potentially racy
+// initialization is not a problem as it is always set to point to the same
+// value (i.e., the FactoryGet always returns the same value). FactoryGet
+// is also completely thread safe, which results in a completely thread safe,
+// and relatively fast, set of counters. To avoid races at shutdown, the static
+// pointer is NOT deleted, and we leak the histograms at process termination.
+
+#ifndef BASE_METRICS_HISTOGRAM_H_
+#define BASE_METRICS_HISTOGRAM_H_
+#pragma once
+
+#include "mozilla/Atomics.h"
+#include "mozilla/MemoryReporting.h"
+
+#include <map>
+#include <string>
+
+#include "base/time.h"
+
+#include "nsTArray.h"
+
+namespace base {
+
+//------------------------------------------------------------------------------
+
+class BooleanHistogram;
+class CustomHistogram;
+class Histogram;
+class LinearHistogram;
+
+class Histogram {
+ public:
+ typedef int Sample; // Used for samples (and ranges of samples).
+ typedef int Count; // Used to count samples in a bucket.
+ static const Sample kSampleType_MAX = INT_MAX;
+ // Initialize maximum number of buckets in histograms as 16,384.
+ static const size_t kBucketCount_MAX;
+
+ typedef nsTArray<Count> Counts;
+ typedef const Sample* Ranges;
+
+ // These enums are used to facilitate deserialization of renderer histograms
+ // into the browser.
+ enum ClassType {
+ HISTOGRAM,
+ LINEAR_HISTOGRAM,
+ BOOLEAN_HISTOGRAM,
+ FLAG_HISTOGRAM,
+ COUNT_HISTOGRAM,
+ CUSTOM_HISTOGRAM,
+ NOT_VALID_IN_RENDERER
+ };
+
+ enum BucketLayout { EXPONENTIAL, LINEAR, CUSTOM };
+
+ enum Flags {
+ kNoFlags = 0,
+ kUmaTargetedHistogramFlag = 0x1, // Histogram should be UMA uploaded.
+
+ kHexRangePrintingFlag = 0x8000 // Fancy bucket-naming supported.
+ };
+
+ enum Inconsistencies {
+ NO_INCONSISTENCIES = 0x0,
+ RANGE_CHECKSUM_ERROR = 0x1,
+ BUCKET_ORDER_ERROR = 0x2,
+ COUNT_HIGH_ERROR = 0x4,
+ COUNT_LOW_ERROR = 0x8,
+
+ NEVER_EXCEEDED_VALUE = 0x10
+ };
+
+ struct DescriptionPair {
+ Sample sample;
+ const char* description; // Null means end of a list of pairs.
+ };
+
+ size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
+
+ bool is_empty() const {
+ return this->sample_.counts(0) == 0 && this->sample_.sum() == 0;
+ }
+
+ //----------------------------------------------------------------------------
+ // Statistic values, developed over the life of the histogram.
+
+ class SampleSet {
+ public:
+ explicit SampleSet();
+ ~SampleSet();
+ SampleSet(SampleSet&&) = default;
+
+ // None of the methods in this class are thread-safe. Callers
+ // must deal with locking themselves.
+
+ // Adjust size of counts_ for use with given histogram.
+ void Resize(const Histogram& histogram);
+
+ // Accessor for histogram to make routine additions.
+ void Accumulate(Sample value, Count count, size_t index);
+
+ // Arithmetic manipulation of corresponding elements of the set.
+ void Add(const SampleSet& other);
+
+ size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf);
+
+ Count counts(size_t i) const { return counts_[i]; }
+ Count TotalCount() const;
+ int64_t sum() const { return sum_; }
+ int64_t redundant_count() const { return redundant_count_; }
+ size_t size() const { return counts_.Length(); }
+ SampleSet Clone() const {
+ SampleSet result;
+ result.counts_ = counts_.Clone();
+ result.sum_ = sum_;
+ result.redundant_count_ = redundant_count_;
+ return result;
+ }
+ void Clear() {
+ sum_ = 0;
+ redundant_count_ = 0;
+ for (int& i : counts_) {
+ i = 0;
+ }
+ }
+
+ protected:
+ // Actual histogram data is stored in buckets, showing the count of values
+ // that fit into each bucket.
+ Counts counts_;
+
+ // Save simple stats locally. Note that this MIGHT get done in base class
+ // without shared memory at some point.
+ int64_t sum_; // sum of samples.
+
+ // To help identify memory corruption, we reduntantly save the number of
+ // samples we've accumulated into all of our buckets. We can compare this
+ // count to the sum of the counts in all buckets, and detect problems. Note
+ // that due to races in histogram accumulation (if a histogram is indeed
+ // updated on several threads simultaneously), the tallies might mismatch,
+ // and also the snapshotting code may asynchronously get a mismatch (though
+ // generally either race based mismatch cause is VERY rare).
+ int64_t redundant_count_;
+ };
+
+ //----------------------------------------------------------------------------
+ // minimum should start from 1. 0 is invalid as a minimum. 0 is an implicit
+ // default underflow bucket.
+ static Histogram* FactoryGet(Sample minimum, Sample maximum,
+ size_t bucket_count, Flags flags,
+ const int* buckets);
+
+ virtual ~Histogram();
+
+ void Add(int value);
+ void Subtract(int value);
+
+ // This method is an interface, used only by BooleanHistogram.
+ virtual void AddBoolean(bool value);
+
+ // Accept a TimeDelta to increment.
+ void AddTime(TimeDelta time) { Add(static_cast<int>(time.InMilliseconds())); }
+
+ virtual void AddSampleSet(const SampleSet& sample);
+
+ virtual void Clear();
+
+ // This method is an interface, used only by LinearHistogram.
+ virtual void SetRangeDescriptions(const DescriptionPair descriptions[]);
+
+ // Support generic flagging of Histograms.
+ // 0x1 Currently used to mark this histogram to be recorded by UMA..
+ // 0x8000 means print ranges in hex.
+ void SetFlags(Flags flags) { flags_ = static_cast<Flags>(flags_ | flags); }
+ void ClearFlags(Flags flags) { flags_ = static_cast<Flags>(flags_ & ~flags); }
+ int flags() const { return flags_; }
+
+ // Check to see if bucket ranges, counts and tallies in the snapshot are
+ // consistent with the bucket ranges and checksums in our histogram. This can
+ // produce a false-alarm if a race occurred in the reading of the data during
+ // a SnapShot process, but should otherwise be false at all times (unless we
+ // have memory over-writes, or DRAM failures).
+ virtual Inconsistencies FindCorruption(const SampleSet& snapshot) const;
+
+ //----------------------------------------------------------------------------
+ // Accessors for factory constuction, serialization and testing.
+ //----------------------------------------------------------------------------
+ virtual ClassType histogram_type() const;
+ Sample declared_min() const { return declared_min_; }
+ Sample declared_max() const { return declared_max_; }
+ virtual Sample ranges(size_t i) const;
+ uint32_t range_checksum() const { return range_checksum_; }
+ virtual size_t bucket_count() const;
+
+ virtual SampleSet SnapshotSample() const;
+
+ virtual bool HasConstructorArguments(Sample minimum, Sample maximum,
+ size_t bucket_count);
+
+ virtual bool HasConstructorTimeDeltaArguments(TimeDelta minimum,
+ TimeDelta maximum,
+ size_t bucket_count);
+ // Return true iff the range_checksum_ matches current ranges_ vector.
+ bool HasValidRangeChecksum() const;
+
+ protected:
+ Histogram(Sample minimum, Sample maximum, size_t bucket_count);
+ Histogram(TimeDelta minimum, TimeDelta maximum, size_t bucket_count);
+
+ // Initialize ranges_ mapping from raw data.
+ void InitializeBucketRangeFromData(const int* buckets);
+
+ // Method to override to skip the display of the i'th bucket if it's empty.
+ virtual bool PrintEmptyBucket(size_t index) const;
+
+ //----------------------------------------------------------------------------
+ // Methods to override to create histogram with different bucket widths.
+ //----------------------------------------------------------------------------
+ // Find bucket to increment for sample value.
+ virtual size_t BucketIndex(Sample value) const;
+ // Get normalized size, relative to the ranges_[i].
+ virtual double GetBucketSize(Count current, size_t i) const;
+
+ // Recalculate range_checksum_.
+ void ResetRangeChecksum();
+
+ // Return a string description of what goes in a given bucket.
+ // Most commonly this is the numeric value, but in derived classes it may
+ // be a name (or string description) given to the bucket.
+ virtual const std::string GetAsciiBucketRange(size_t it) const;
+
+ //----------------------------------------------------------------------------
+ // Methods to override to create thread safe histogram.
+ //----------------------------------------------------------------------------
+ // Update all our internal data, including histogram
+ virtual void Accumulate(Sample value, Count count, size_t index);
+
+ // Validate that ranges_ was created sensibly (top and bottom range
+ // values relate properly to the declared_min_ and declared_max_)..
+ bool ValidateBucketRanges() const;
+
+ virtual uint32_t CalculateRangeChecksum() const;
+
+ // Finally, provide the state that changes with the addition of each new
+ // sample.
+ SampleSet sample_;
+
+ private:
+ // Post constructor initialization.
+ void Initialize();
+
+ // Checksum function for accumulating range values into a checksum.
+ static uint32_t Crc32(uint32_t sum, Sample range);
+
+ //----------------------------------------------------------------------------
+ // Helpers for emitting Ascii graphic. Each method appends data to output.
+
+ // Find out how large the (graphically) the largest bucket will appear to be.
+ double GetPeakBucketSize(const SampleSet& snapshot) const;
+
+ //----------------------------------------------------------------------------
+ // Table for generating Crc32 values.
+ static const uint32_t kCrcTable[256];
+ //----------------------------------------------------------------------------
+ // Invariant values set at/near construction time
+
+ Sample declared_min_; // Less than this goes into counts_[0]
+ Sample declared_max_; // Over this goes into counts_[bucket_count_ - 1].
+ size_t bucket_count_; // Dimension of counts_[].
+
+ // Flag the histogram for recording by UMA via metric_services.h.
+ Flags flags_;
+
+ // For each index, show the least value that can be stored in the
+ // corresponding bucket. We also append one extra element in this array,
+ // containing kSampleType_MAX, to make calculations easy.
+ // The dimension of ranges_ is bucket_count + 1.
+ Ranges ranges_;
+
+ // For redundancy, we store a checksum of all the sample ranges when ranges
+ // are generated. If ever there is ever a difference, then the histogram must
+ // have been corrupted.
+ uint32_t range_checksum_;
+
+ DISALLOW_COPY_AND_ASSIGN(Histogram);
+};
+
+//------------------------------------------------------------------------------
+
+// LinearHistogram is a more traditional histogram, with evenly spaced
+// buckets.
+class LinearHistogram : public Histogram {
+ public:
+ virtual ~LinearHistogram();
+
+ /* minimum should start from 1. 0 is as minimum is invalid. 0 is an implicit
+ default underflow bucket. */
+ static Histogram* FactoryGet(Sample minimum, Sample maximum,
+ size_t bucket_count, Flags flags,
+ const int* buckets);
+
+ // Overridden from Histogram:
+ virtual ClassType histogram_type() const override;
+
+ virtual void Accumulate(Sample value, Count count, size_t index) override;
+
+ // Store a list of number/text values for use in rendering the histogram.
+ // The last element in the array has a null in its "description" slot.
+ virtual void SetRangeDescriptions(
+ const DescriptionPair descriptions[]) override;
+
+ protected:
+ LinearHistogram(Sample minimum, Sample maximum, size_t bucket_count);
+
+ LinearHistogram(TimeDelta minimum, TimeDelta maximum, size_t bucket_count);
+
+ virtual double GetBucketSize(Count current, size_t i) const override;
+
+ // If we have a description for a bucket, then return that. Otherwise
+ // let parent class provide a (numeric) description.
+ virtual const std::string GetAsciiBucketRange(size_t i) const override;
+
+ // Skip printing of name for numeric range if we have a name (and if this is
+ // an empty bucket).
+ virtual bool PrintEmptyBucket(size_t index) const override;
+
+ private:
+ // For some ranges, we store a printable description of a bucket range.
+ // If there is no desciption, then GetAsciiBucketRange() uses parent class
+ // to provide a description.
+ typedef std::map<Sample, std::string> BucketDescriptionMap;
+ BucketDescriptionMap bucket_description_;
+
+ DISALLOW_COPY_AND_ASSIGN(LinearHistogram);
+};
+
+//------------------------------------------------------------------------------
+
+// BooleanHistogram is a histogram for booleans.
+class BooleanHistogram : public LinearHistogram {
+ public:
+ static Histogram* FactoryGet(Flags flags, const int* buckets);
+
+ virtual ClassType histogram_type() const override;
+
+ virtual void AddBoolean(bool value) override;
+
+ virtual void Accumulate(Sample value, Count count, size_t index) override;
+
+ protected:
+ explicit BooleanHistogram();
+
+ DISALLOW_COPY_AND_ASSIGN(BooleanHistogram);
+};
+
+//------------------------------------------------------------------------------
+
+// FlagHistogram is like boolean histogram, but only allows a single off/on
+// value.
+class FlagHistogram : public BooleanHistogram {
+ public:
+ static Histogram* FactoryGet(Flags flags, const int* buckets);
+
+ virtual ClassType histogram_type() const override;
+
+ virtual void Accumulate(Sample value, Count count, size_t index) override;
+
+ virtual void AddSampleSet(const SampleSet& sample) override;
+
+ virtual void Clear() override;
+
+ private:
+ explicit FlagHistogram();
+ bool mSwitched;
+
+ DISALLOW_COPY_AND_ASSIGN(FlagHistogram);
+};
+
+// CountHistogram only allows a single monotic counter value.
+class CountHistogram : public LinearHistogram {
+ public:
+ static Histogram* FactoryGet(Flags flags, const int* buckets);
+
+ virtual ClassType histogram_type() const override;
+
+ virtual void Accumulate(Sample value, Count count, size_t index) override;
+
+ virtual void AddSampleSet(const SampleSet& sample) override;
+
+ private:
+ explicit CountHistogram();
+
+ DISALLOW_COPY_AND_ASSIGN(CountHistogram);
+};
+
+} // namespace base
+
+#endif // BASE_METRICS_HISTOGRAM_H_
diff --git a/ipc/chromium/src/base/linked_ptr.h b/ipc/chromium/src/base/linked_ptr.h
new file mode 100644
index 0000000000..7b428312b8
--- /dev/null
+++ b/ipc/chromium/src/base/linked_ptr.h
@@ -0,0 +1,185 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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 "smart" pointer type with reference tracking. Every pointer to a
+// particular object is kept on a circular linked list. When the last pointer
+// to an object is destroyed or reassigned, the object is deleted.
+//
+// Used properly, this deletes the object when the last reference goes away.
+// There are several caveats:
+// - Like all reference counting schemes, cycles lead to leaks.
+// - Each smart pointer is actually two pointers (8 bytes instead of 4).
+// - Every time a pointer is released, the entire list of pointers to that
+// object is traversed. This class is therefore NOT SUITABLE when there
+// will often be more than two or three pointers to a particular object.
+// - References are only tracked as long as linked_ptr<> objects are copied.
+// If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS
+// will happen (double deletion).
+//
+// A good use of this class is storing object references in STL containers.
+// You can safely put linked_ptr<> in a vector<>.
+// Other uses may not be as good.
+//
+// Note: If you use an incomplete type with linked_ptr<>, the class
+// *containing* linked_ptr<> must have a constructor and destructor (even
+// if they do nothing!).
+//
+// Thread Safety:
+// A linked_ptr is NOT thread safe. Copying a linked_ptr object is
+// effectively a read-write operation.
+//
+// Alternative: to linked_ptr is shared_ptr, which
+// - is also two pointers in size (8 bytes for 32 bit addresses)
+// - is thread safe for copying and deletion
+// - supports weak_ptrs
+
+#ifndef BASE_LINKED_PTR_H_
+#define BASE_LINKED_PTR_H_
+
+#include "base/logging.h" // for CHECK macros
+
+// This is used internally by all instances of linked_ptr<>. It needs to be
+// a non-template class because different types of linked_ptr<> can refer to
+// the same object (linked_ptr<Superclass>(obj) vs linked_ptr<Subclass>(obj)).
+// So, it needs to be possible for different types of linked_ptr to participate
+// in the same circular linked list, so we need a single class type here.
+//
+// DO NOT USE THIS CLASS DIRECTLY YOURSELF. Use linked_ptr<T>.
+class linked_ptr_internal {
+ public:
+ // Create a new circle that includes only this instance.
+ void join_new() { next_ = this; }
+
+ // Join an existing circle.
+ void join(linked_ptr_internal const* ptr) {
+ next_ = ptr->next_;
+ ptr->next_ = this;
+ }
+
+ // Leave whatever circle we're part of. Returns true iff we were the
+ // last member of the circle. Once this is done, you can join() another.
+ bool depart() {
+ if (next_ == this) return true;
+ linked_ptr_internal const* p = next_;
+ while (p->next_ != this) p = p->next_;
+ p->next_ = next_;
+ return false;
+ }
+
+ private:
+ mutable linked_ptr_internal const* next_;
+};
+
+template <typename T>
+class linked_ptr {
+ public:
+ typedef T element_type;
+
+ // Take over ownership of a raw pointer. This should happen as soon as
+ // possible after the object is created.
+ explicit linked_ptr(T* ptr = NULL) { capture(ptr); }
+ ~linked_ptr() { depart(); }
+
+ // Copy an existing linked_ptr<>, adding ourselves to the list of references.
+ template <typename U>
+ linked_ptr(linked_ptr<U> const& ptr) {
+ copy(&ptr);
+ }
+ linked_ptr(linked_ptr const& ptr) {
+ DCHECK_NE(&ptr, this);
+ copy(&ptr);
+ }
+
+ // Assignment releases the old value and acquires the new.
+ template <typename U>
+ linked_ptr& operator=(linked_ptr<U> const& ptr) {
+ depart();
+ copy(&ptr);
+ return *this;
+ }
+
+ linked_ptr& operator=(linked_ptr const& ptr) {
+ if (&ptr != this) {
+ depart();
+ copy(&ptr);
+ }
+ return *this;
+ }
+
+ // Smart pointer members.
+ void reset(T* ptr = NULL) {
+ depart();
+ capture(ptr);
+ }
+ T* get() const { return value_; }
+ T* operator->() const { return value_; }
+ T& operator*() const { return *value_; }
+ // Release ownership of the pointed object and returns it.
+ // Sole ownership by this linked_ptr object is required.
+ T* release() {
+ bool last = link_.depart();
+ CHECK(last);
+ T* v = value_;
+ value_ = NULL;
+ return v;
+ }
+
+ bool operator==(const T* p) const { return value_ == p; }
+ bool operator!=(const T* p) const { return value_ != p; }
+ template <typename U>
+ bool operator==(linked_ptr<U> const& ptr) const {
+ return value_ == ptr.get();
+ }
+ template <typename U>
+ bool operator!=(linked_ptr<U> const& ptr) const {
+ return value_ != ptr.get();
+ }
+
+ private:
+ template <typename U>
+ friend class linked_ptr;
+
+ T* value_;
+ linked_ptr_internal link_;
+
+ void depart() {
+ if (link_.depart()) delete value_;
+ }
+
+ void capture(T* ptr) {
+ value_ = ptr;
+ link_.join_new();
+ }
+
+ template <typename U>
+ void copy(linked_ptr<U> const* ptr) {
+ value_ = ptr->get();
+ if (value_)
+ link_.join(&ptr->link_);
+ else
+ link_.join_new();
+ }
+};
+
+template <typename T>
+inline bool operator==(T* ptr, const linked_ptr<T>& x) {
+ return ptr == x.get();
+}
+
+template <typename T>
+inline bool operator!=(T* ptr, const linked_ptr<T>& x) {
+ return ptr != x.get();
+}
+
+// A function to convert T* into linked_ptr<T>
+// Doing e.g. make_linked_ptr(new FooBarBaz<type>(arg)) is a shorter notation
+// for linked_ptr<FooBarBaz<type> >(new FooBarBaz<type>(arg))
+template <typename T>
+linked_ptr<T> make_linked_ptr(T* ptr) {
+ return linked_ptr<T>(ptr);
+}
+
+#endif // BASE_LINKED_PTR_H_
diff --git a/ipc/chromium/src/base/linux_memfd_defs.h b/ipc/chromium/src/base/linux_memfd_defs.h
new file mode 100644
index 0000000000..f5b0de1de8
--- /dev/null
+++ b/ipc/chromium/src/base/linux_memfd_defs.h
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+#ifndef BASE_LINUX_MEMFD_DEFS_H
+#define BASE_LINUX_MEMFD_DEFS_H
+
+#include <sys/syscall.h>
+
+// glibc before 2.27 didn't have a memfd_create wrapper, and if the
+// build system is old enough then it won't have the syscall number
+// and various related constants either.
+
+#if defined(__x86_64__)
+# define MEMFD_CREATE_NR 319
+#elif defined(__i386__)
+# define MEMFD_CREATE_NR 356
+#elif defined(__aarch64__)
+# define MEMFD_CREATE_NR 279
+#elif defined(__arm__)
+# define MEMFD_CREATE_NR 385
+#elif defined(__powerpc__)
+# define MEMFD_CREATE_NR 360
+#elif defined(__s390__)
+# define MEMFD_CREATE_NR 350
+#elif defined(__mips__)
+# include <sgidefs.h>
+# if _MIPS_SIM == _MIPS_SIM_ABI32
+# define MEMFD_CREATE_NR 4354
+# elif _MIPS_SIM == _MIPS_SIM_ABI64
+# define MEMFD_CREATE_NR 5314
+# elif _MIPS_SIM == _MIPS_SIM_NABI32
+# define MEMFD_CREATE_NR 6318
+# endif // mips subarch
+#endif // arch
+
+#ifdef MEMFD_CREATE_NR
+# ifdef SYS_memfd_create
+static_assert(MEMFD_CREATE_NR == SYS_memfd_create,
+ "MEMFD_CREATE_NR should match the actual SYS_memfd_create value");
+# else // defined here but not in system headers
+# define SYS_memfd_create MEMFD_CREATE_NR
+# endif
+#endif
+
+#ifndef MFD_CLOEXEC
+# define MFD_CLOEXEC 0x0001U
+# define MFD_ALLOW_SEALING 0x0002U
+#endif
+
+#ifndef F_ADD_SEALS
+# ifndef F_LINUX_SPECIFIC_BASE
+# define F_LINUX_SPECIFIC_BASE 1024
+# endif
+# define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9)
+# define F_GET_SEALS (F_LINUX_SPECIFIC_BASE + 10)
+# define F_SEAL_SEAL 0x0001 /* prevent further seals from being set */
+# define F_SEAL_SHRINK 0x0002 /* prevent file from shrinking */
+# define F_SEAL_GROW 0x0004 /* prevent file from growing */
+# define F_SEAL_WRITE 0x0008 /* prevent writes */
+#endif
+
+#ifndef F_SEAL_FUTURE_WRITE
+# define F_SEAL_FUTURE_WRITE 0x0010
+#endif
+
+#endif // BASE_LINUX_MEMFD_DEFS_H
diff --git a/ipc/chromium/src/base/lock.h b/ipc/chromium/src/base/lock.h
new file mode 100644
index 0000000000..085e70e725
--- /dev/null
+++ b/ipc/chromium/src/base/lock.h
@@ -0,0 +1,97 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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_LOCK_H_
+#define BASE_LOCK_H_
+
+#include "base/basictypes.h"
+#include "base/lock_impl.h"
+#include "base/platform_thread.h"
+
+// A convenient wrapper for an OS specific critical section.
+class Lock {
+ public:
+ // Optimized wrapper implementation
+ Lock() = default;
+ ~Lock() = default;
+ 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 {}
+
+ // Whether Lock mitigates priority inversion when used from different thread
+ // priorities.
+ static bool HandlesMultipleThreadPriorities() {
+#if defined(XP_UNIX)
+ // POSIX mitigates priority inversion by setting the priority of a thread
+ // holding a Lock to the maximum priority of any other thread waiting on it.
+ return base::internal::LockImpl::PriorityInheritanceAvailable();
+#else
+ // Windows mitigates priority inversion by randomly boosting the priority of
+ // ready threads.
+ // https://msdn.microsoft.com/library/windows/desktop/ms684831.aspx
+ return true;
+#endif
+ }
+
+ // Both Windows and POSIX implementations of ConditionVariable need to be
+ // able to see our lock and tweak our debugging counters, as they release and
+ // acquire locks inside of their condition variable APIs.
+ friend class ConditionVariable;
+
+ private:
+ // Platform specific underlying lock implementation.
+ ::base::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:
+ struct AlreadyAcquired {};
+
+ explicit AutoLock(Lock& lock) : lock_(lock) { lock_.Acquire(); }
+
+ AutoLock(Lock& lock, const AlreadyAcquired&) : lock_(lock) {
+ lock_.AssertAcquired();
+ }
+
+ ~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);
+};
+
+#endif // BASE_LOCK_H_
diff --git a/ipc/chromium/src/base/lock_impl.h b/ipc/chromium/src/base/lock_impl.h
new file mode 100644
index 0000000000..95588bcca2
--- /dev/null
+++ b/ipc/chromium/src/base/lock_impl.h
@@ -0,0 +1,65 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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_LOCK_IMPL_H_
+#define BASE_LOCK_IMPL_H_
+
+#include "base/basictypes.h"
+
+#if defined(XP_WIN)
+# include <windows.h>
+#else
+# include <pthread.h>
+#endif
+
+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 LockImpl {
+ public:
+#if defined(XP_WIN)
+ using NativeHandle = SRWLOCK;
+#else
+ using NativeHandle = pthread_mutex_t;
+#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.
+ // TODO(awalker): refactor lock and condition variables so that this is
+ // unnecessary.
+ NativeHandle* native_handle() { return &native_handle_; }
+
+#if defined(XP_UNIX)
+ // Whether this lock will attempt to use priority inheritance.
+ static bool PriorityInheritanceAvailable();
+#endif
+
+ private:
+ NativeHandle native_handle_;
+
+ DISALLOW_COPY_AND_ASSIGN(LockImpl);
+};
+
+} // namespace internal
+} // namespace base
+
+#endif // BASE_LOCK_IMPL_H_
diff --git a/ipc/chromium/src/base/lock_impl_posix.cc b/ipc/chromium/src/base/lock_impl_posix.cc
new file mode 100644
index 0000000000..a4a2ce87b6
--- /dev/null
+++ b/ipc/chromium/src/base/lock_impl_posix.cc
@@ -0,0 +1,98 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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/lock_impl.h"
+
+#include <errno.h>
+#include <string.h>
+
+#include "base/logging.h"
+#include "base/lock.h"
+
+namespace base {
+namespace internal {
+
+// Determines which platforms can consider using priority inheritance locks. Use
+// this define for platform code that may not compile if priority inheritance
+// locks aren't available. For this platform code,
+// PRIORITY_INHERITANCE_LOCKS_POSSIBLE() is a necessary but insufficient check.
+// Lock::PriorityInheritanceAvailable still must be checked as the code may
+// compile but the underlying platform still may not correctly support priority
+// inheritance locks.
+#if defined(ANDROID)
+# define PRIORITY_INHERITANCE_LOCKS_POSSIBLE() 0
+#else
+# define PRIORITY_INHERITANCE_LOCKS_POSSIBLE() 1
+#endif
+
+LockImpl::LockImpl() {
+ pthread_mutexattr_t mta;
+ int rv = pthread_mutexattr_init(&mta);
+ DCHECK_EQ(rv, 0) << ". " << strerror(rv);
+#if PRIORITY_INHERITANCE_LOCKS_POSSIBLE()
+ if (PriorityInheritanceAvailable()) {
+ rv = pthread_mutexattr_setprotocol(&mta, PTHREAD_PRIO_INHERIT);
+ DCHECK_EQ(rv, 0) << ". " << strerror(rv);
+ }
+#endif
+#ifndef NDEBUG
+ // In debug, setup attributes for lock error checking.
+ rv = pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_ERRORCHECK);
+ DCHECK_EQ(rv, 0) << ". " << strerror(rv);
+#endif
+ rv = pthread_mutex_init(&native_handle_, &mta);
+ DCHECK_EQ(rv, 0) << ". " << strerror(rv);
+ rv = pthread_mutexattr_destroy(&mta);
+ DCHECK_EQ(rv, 0) << ". " << strerror(rv);
+}
+
+LockImpl::~LockImpl() {
+ int rv = pthread_mutex_destroy(&native_handle_);
+ DCHECK_EQ(rv, 0) << ". " << strerror(rv);
+}
+
+bool LockImpl::Try() {
+ int rv = pthread_mutex_trylock(&native_handle_);
+ DCHECK(rv == 0 || rv == EBUSY) << ". " << strerror(rv);
+ return rv == 0;
+}
+
+void LockImpl::Lock() {
+ int rv = pthread_mutex_lock(&native_handle_);
+ DCHECK_EQ(rv, 0) << ". " << strerror(rv);
+}
+
+void LockImpl::Unlock() {
+ int rv = pthread_mutex_unlock(&native_handle_);
+ DCHECK_EQ(rv, 0) << ". " << strerror(rv);
+}
+
+// static
+bool LockImpl::PriorityInheritanceAvailable() {
+#if PRIORITY_INHERITANCE_LOCKS_POSSIBLE() && defined(XP_DARWIN)
+ return true;
+#else
+ // Security concerns prevent the use of priority inheritance mutexes on Linux.
+ // * CVE-2010-0622 - wake_futex_pi unlocks incorrect, possible DoS.
+ // https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-0622
+ // * CVE-2012-6647 - Linux < 3.5.1, futex_wait_requeue_pi possible DoS.
+ // https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2012-6647
+ // * CVE-2014-3153 - Linux <= 3.14.5, futex_requeue, privilege escalation.
+ // https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-3153
+ //
+ // If the above were all addressed, we still need a runtime check to deal with
+ // the bug below.
+ // * glibc Bug 14652: https://sourceware.org/bugzilla/show_bug.cgi?id=14652
+ // Fixed in glibc 2.17.
+ // Priority inheritance mutexes may deadlock with condition variables
+ // during recacquisition of the mutex after the condition variable is
+ // signalled.
+ return false;
+#endif
+}
+
+} // namespace internal
+} // namespace base
diff --git a/ipc/chromium/src/base/lock_impl_win.cc b/ipc/chromium/src/base/lock_impl_win.cc
new file mode 100644
index 0000000000..fc16b3a464
--- /dev/null
+++ b/ipc/chromium/src/base/lock_impl_win.cc
@@ -0,0 +1,23 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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/lock_impl.h"
+
+namespace base {
+namespace internal {
+
+LockImpl::LockImpl() : native_handle_(SRWLOCK_INIT) {}
+
+LockImpl::~LockImpl() = default;
+
+bool LockImpl::Try() { return !!::TryAcquireSRWLockExclusive(&native_handle_); }
+
+void LockImpl::Lock() { ::AcquireSRWLockExclusive(&native_handle_); }
+
+void LockImpl::Unlock() { ::ReleaseSRWLockExclusive(&native_handle_); }
+
+} // namespace internal
+} // namespace base
diff --git a/ipc/chromium/src/base/logging.cc b/ipc/chromium/src/base/logging.cc
new file mode 100644
index 0000000000..217ae80844
--- /dev/null
+++ b/ipc/chromium/src/base/logging.cc
@@ -0,0 +1,87 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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 "base/logging.h"
+
+#include <utility>
+
+#include "base/string_util.h"
+#include "nsXPCOM.h"
+
+namespace mozilla {
+
+Logger::~Logger() {
+ LogLevel prlevel = LogLevel::Debug;
+ int xpcomlevel = -1;
+
+ switch (mSeverity) {
+ case LOG_INFO:
+ prlevel = LogLevel::Debug;
+ xpcomlevel = -1;
+ break;
+
+ case LOG_WARNING:
+ prlevel = LogLevel::Warning;
+ xpcomlevel = NS_DEBUG_WARNING;
+ break;
+
+ case LOG_ERROR:
+ prlevel = LogLevel::Error;
+ xpcomlevel = NS_DEBUG_WARNING;
+ break;
+
+ case LOG_ERROR_REPORT:
+ prlevel = LogLevel::Error;
+ xpcomlevel = NS_DEBUG_ASSERTION;
+ break;
+
+ case LOG_FATAL:
+ prlevel = LogLevel::Error;
+ xpcomlevel = NS_DEBUG_ABORT;
+ break;
+ }
+
+ MOZ_LOG(gChromiumPRLog, prlevel,
+ ("%s:%i: %s", mFile, mLine, mMsg ? mMsg.get() : "<no message>"));
+ if (xpcomlevel != -1)
+ NS_DebugBreak(xpcomlevel, mMsg.get(), NULL, mFile, mLine);
+}
+
+void Logger::printf(const char* fmt, ...) {
+ va_list args;
+ va_start(args, fmt);
+ mMsg = mozilla::VsmprintfAppend(std::move(mMsg), fmt, args);
+ va_end(args);
+}
+
+LazyLogModule Logger::gChromiumPRLog("chromium");
+
+mozilla::Logger& operator<<(mozilla::Logger& log, const char* s) {
+ log.printf("%s", s);
+ return log;
+}
+
+mozilla::Logger& operator<<(mozilla::Logger& log, const std::string& s) {
+ log.printf("%s", s.c_str());
+ return log;
+}
+
+mozilla::Logger& operator<<(mozilla::Logger& log, int i) {
+ log.printf("%i", i);
+ return log;
+}
+
+mozilla::Logger& operator<<(mozilla::Logger& log, const std::wstring& s) {
+ log.printf("%s", WideToASCII(s).c_str());
+ return log;
+}
+
+mozilla::Logger& operator<<(mozilla::Logger& log, void* p) {
+ log.printf("%p", p);
+ return log;
+}
+
+} // namespace mozilla
diff --git a/ipc/chromium/src/base/logging.h b/ipc/chromium/src/base/logging.h
new file mode 100644
index 0000000000..4313f131b3
--- /dev/null
+++ b/ipc/chromium/src/base/logging.h
@@ -0,0 +1,132 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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_LOGGING_H_
+#define BASE_LOGGING_H_
+
+#include <string>
+#include <cstring>
+
+#include "base/basictypes.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/Logging.h"
+#include "mozilla/Printf.h"
+
+#ifdef NO_CHROMIUM_LOGGING
+# include <sstream>
+#endif
+
+// Replace the Chromium logging code with NSPR-based logging code and
+// some C++ wrappers to emulate std::ostream
+
+namespace mozilla {
+
+enum LogSeverity {
+ LOG_INFO,
+ LOG_WARNING,
+ LOG_ERROR,
+ LOG_ERROR_REPORT,
+ LOG_FATAL,
+ LOG_0 = LOG_ERROR
+};
+
+class Logger {
+ public:
+ Logger(LogSeverity severity, const char* file, int line)
+ : mSeverity(severity), mFile(file), mLine(line) {}
+
+ ~Logger();
+
+ // not private so that the operator<< overloads can get to it
+ void printf(const char* fmt, ...) MOZ_FORMAT_PRINTF(2, 3);
+
+ private:
+ static mozilla::LazyLogModule gChromiumPRLog;
+ // static PRLogModuleInfo* GetLog();
+
+ LogSeverity mSeverity;
+ const char* mFile;
+ int mLine;
+ SmprintfPointer mMsg;
+
+ DISALLOW_EVIL_CONSTRUCTORS(Logger);
+};
+
+class LogWrapper {
+ public:
+ LogWrapper(LogSeverity severity, const char* file, int line)
+ : log(severity, file, line) {}
+
+ operator Logger&() const { return log; }
+
+ private:
+ mutable Logger log;
+
+ DISALLOW_EVIL_CONSTRUCTORS(LogWrapper);
+};
+
+struct EmptyLog {};
+
+mozilla::Logger& operator<<(mozilla::Logger& log, const char* s);
+mozilla::Logger& operator<<(mozilla::Logger& log, const std::string& s);
+mozilla::Logger& operator<<(mozilla::Logger& log, int i);
+mozilla::Logger& operator<<(mozilla::Logger& log, const std::wstring& s);
+mozilla::Logger& operator<<(mozilla::Logger& log, void* p);
+
+template <class T>
+const mozilla::EmptyLog& operator<<(const mozilla::EmptyLog& log, const T&) {
+ return log;
+}
+
+} // namespace mozilla
+
+#ifdef NO_CHROMIUM_LOGGING
+# define CHROMIUM_LOG(info) std::stringstream()
+# define LOG_IF(info, condition) \
+ if (!(condition)) std::stringstream()
+#else
+# define CHROMIUM_LOG(info) \
+ mozilla::LogWrapper(mozilla::LOG_##info, __FILE__, __LINE__)
+# define LOG_IF(info, condition) \
+ if (!(condition)) \
+ mozilla::LogWrapper(mozilla::LOG_##info, __FILE__, __LINE__)
+#endif
+
+#ifdef DEBUG
+# define DLOG(info) CHROMIUM_LOG(info)
+# define DLOG_IF(info, condition) LOG_IF(info, condition)
+# define DCHECK(condition) CHECK(condition)
+#else
+# define DLOG(info) mozilla::EmptyLog()
+# define DLOG_IF(info, condition) mozilla::EmptyLog()
+# define DCHECK(condition) \
+ while (false && (condition)) mozilla::EmptyLog()
+#endif
+
+#define DVLOG(level) DLOG(INFO)
+
+#undef LOG_ASSERT
+#define LOG_ASSERT(cond) CHECK(0)
+#define DLOG_ASSERT(cond) DCHECK(0)
+
+#define NOTREACHED() CHROMIUM_LOG(ERROR)
+#define NOTIMPLEMENTED() CHROMIUM_LOG(ERROR)
+
+#undef CHECK
+#ifdef FUZZING
+# define CHECK(condition) LOG_IF(WARNING, condition)
+#else
+# define CHECK(condition) LOG_IF(FATAL, condition)
+#endif
+
+#define DCHECK_EQ(v1, v2) DCHECK((v1) == (v2))
+#define DCHECK_NE(v1, v2) DCHECK((v1) != (v2))
+#define DCHECK_LE(v1, v2) DCHECK((v1) <= (v2))
+#define DCHECK_LT(v1, v2) DCHECK((v1) < (v2))
+#define DCHECK_GE(v1, v2) DCHECK((v1) >= (v2))
+#define DCHECK_GT(v1, v2) DCHECK((v1) > (v2))
+
+#endif // BASE_LOGGING_H_
diff --git a/ipc/chromium/src/base/mac_util.h b/ipc/chromium/src/base/mac_util.h
new file mode 100644
index 0000000000..6af2bd7032
--- /dev/null
+++ b/ipc/chromium/src/base/mac_util.h
@@ -0,0 +1,17 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MAC_UTIL_H_
+#define BASE_MAC_UTIL_H_
+
+namespace mac_util {
+
+// Returns true if the application is running from a bundle
+bool AmIBundled();
+
+} // namespace mac_util
+
+#endif // BASE_MAC_UTIL_H_
diff --git a/ipc/chromium/src/base/mac_util.mm b/ipc/chromium/src/base/mac_util.mm
new file mode 100644
index 0000000000..dde8d9a273
--- /dev/null
+++ b/ipc/chromium/src/base/mac_util.mm
@@ -0,0 +1,33 @@
+// Copyright (c) 2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/mac_util.h"
+
+#include <Carbon/Carbon.h>
+#import <Cocoa/Cocoa.h>
+
+#include "base/file_path.h"
+#include "base/logging.h"
+#include "base/scoped_cftyperef.h"
+#include "base/sys_string_conversions.h"
+
+namespace mac_util {
+
+// Adapted from http://developer.apple.com/carbon/tipsandtricks.html#AmIBundled
+bool AmIBundled() {
+ ProcessSerialNumber psn = {0, kCurrentProcess};
+
+ FSRef fsref;
+ if (GetProcessBundleLocation(&psn, &fsref) != noErr) return false;
+
+ FSCatalogInfo info;
+ if (FSGetCatalogInfo(&fsref, kFSCatInfoNodeFlags, &info, NULL, NULL, NULL) !=
+ noErr) {
+ return false;
+ }
+
+ return info.nodeFlags & kFSNodeIsDirectoryMask;
+}
+
+} // namespace mac_util
diff --git a/ipc/chromium/src/base/message_loop.cc b/ipc/chromium/src/base/message_loop.cc
new file mode 100644
index 0000000000..c82d555ee5
--- /dev/null
+++ b/ipc/chromium/src/base/message_loop.cc
@@ -0,0 +1,725 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=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/message_loop.h"
+
+#include <algorithm>
+
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/message_pump_default.h"
+#include "base/string_util.h"
+#include "base/thread_local.h"
+#include "mozilla/Atomics.h"
+#include "mozilla/Mutex.h"
+#include "mozilla/ProfilerRunnable.h"
+#include "nsIEventTarget.h"
+#include "nsITargetShutdownTask.h"
+#include "nsThreadUtils.h"
+
+#if defined(XP_DARWIN)
+# include "base/message_pump_mac.h"
+#endif
+#if defined(XP_UNIX)
+# include "base/message_pump_libevent.h"
+#endif
+#if defined(XP_LINUX) || defined(__DragonFly__) || defined(XP_FREEBSD) || \
+ defined(XP_NETBSD) || defined(XP_OPENBSD)
+# if defined(MOZ_WIDGET_GTK)
+# include "base/message_pump_glib.h"
+# endif
+#endif
+#ifdef ANDROID
+# include "base/message_pump_android.h"
+#endif
+#include "nsISerialEventTarget.h"
+
+#include "mozilla/ipc/MessagePump.h"
+#include "nsThreadUtils.h"
+
+using base::Time;
+using base::TimeDelta;
+using base::TimeTicks;
+
+using mozilla::Runnable;
+
+static base::ThreadLocalPointer<MessageLoop>& get_tls_ptr() {
+ static base::ThreadLocalPointer<MessageLoop> tls_ptr;
+ return tls_ptr;
+}
+
+//------------------------------------------------------------------------------
+
+#if defined(XP_WIN)
+
+// Upon a SEH exception in this thread, it restores the original unhandled
+// exception filter.
+static int SEHFilter(LPTOP_LEVEL_EXCEPTION_FILTER old_filter) {
+ ::SetUnhandledExceptionFilter(old_filter);
+ return EXCEPTION_CONTINUE_SEARCH;
+}
+
+// Retrieves a pointer to the current unhandled exception filter. There
+// is no standalone getter method.
+static LPTOP_LEVEL_EXCEPTION_FILTER GetTopSEHFilter() {
+ LPTOP_LEVEL_EXCEPTION_FILTER top_filter = NULL;
+ top_filter = ::SetUnhandledExceptionFilter(0);
+ ::SetUnhandledExceptionFilter(top_filter);
+ return top_filter;
+}
+
+#endif // defined(XP_WIN)
+
+//------------------------------------------------------------------------------
+
+class MessageLoop::EventTarget : public nsISerialEventTarget,
+ public nsITargetShutdownTask,
+ public MessageLoop::DestructionObserver {
+ public:
+ NS_DECL_THREADSAFE_ISUPPORTS
+ NS_DECL_NSIEVENTTARGET_FULL
+
+ void TargetShutdown() override {
+ nsTArray<nsCOMPtr<nsITargetShutdownTask>> shutdownTasks;
+ {
+ mozilla::MutexAutoLock lock(mMutex);
+ if (mShutdownTasksRun) {
+ return;
+ }
+ mShutdownTasksRun = true;
+ shutdownTasks = std::move(mShutdownTasks);
+ mShutdownTasks.Clear();
+ }
+
+ for (auto& task : shutdownTasks) {
+ task->TargetShutdown();
+ }
+ }
+
+ explicit EventTarget(MessageLoop* aLoop)
+ : mMutex("MessageLoop::EventTarget"), mLoop(aLoop) {
+ aLoop->AddDestructionObserver(this);
+ }
+
+ private:
+ virtual ~EventTarget() {
+ if (mLoop) {
+ mLoop->RemoveDestructionObserver(this);
+ }
+ MOZ_ASSERT(mShutdownTasks.IsEmpty());
+ }
+
+ void WillDestroyCurrentMessageLoop() override {
+ {
+ mozilla::MutexAutoLock lock(mMutex);
+ // The MessageLoop is being destroyed and we are called from its
+ // destructor There's no real need to remove ourselves from the
+ // destruction observer list. But it makes things look tidier.
+ mLoop->RemoveDestructionObserver(this);
+ mLoop = nullptr;
+ }
+
+ TargetShutdown();
+ }
+
+ mozilla::Mutex mMutex;
+ bool mShutdownTasksRun MOZ_GUARDED_BY(mMutex) = false;
+ nsTArray<nsCOMPtr<nsITargetShutdownTask>> mShutdownTasks
+ MOZ_GUARDED_BY(mMutex);
+ MessageLoop* mLoop MOZ_GUARDED_BY(mMutex);
+};
+
+NS_IMPL_ISUPPORTS(MessageLoop::EventTarget, nsIEventTarget,
+ nsISerialEventTarget)
+
+NS_IMETHODIMP_(bool)
+MessageLoop::EventTarget::IsOnCurrentThreadInfallible() {
+ mozilla::MutexAutoLock lock(mMutex);
+ return mLoop == MessageLoop::current();
+}
+
+NS_IMETHODIMP
+MessageLoop::EventTarget::IsOnCurrentThread(bool* aResult) {
+ *aResult = IsOnCurrentThreadInfallible();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+MessageLoop::EventTarget::DispatchFromScript(nsIRunnable* aEvent,
+ uint32_t aFlags) {
+ nsCOMPtr<nsIRunnable> event(aEvent);
+ return Dispatch(event.forget(), aFlags);
+}
+
+NS_IMETHODIMP
+MessageLoop::EventTarget::Dispatch(already_AddRefed<nsIRunnable> aEvent,
+ uint32_t aFlags) {
+ mozilla::MutexAutoLock lock(mMutex);
+ if (!mLoop) {
+ return NS_ERROR_NOT_INITIALIZED;
+ }
+
+ if (aFlags != NS_DISPATCH_NORMAL) {
+ return NS_ERROR_NOT_IMPLEMENTED;
+ }
+
+ mLoop->PostTask(std::move(aEvent));
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+MessageLoop::EventTarget::DelayedDispatch(already_AddRefed<nsIRunnable> aEvent,
+ uint32_t aDelayMs) {
+ mozilla::MutexAutoLock lock(mMutex);
+ if (!mLoop) {
+ return NS_ERROR_NOT_INITIALIZED;
+ }
+
+ mLoop->PostDelayedTask(std::move(aEvent), aDelayMs);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+MessageLoop::EventTarget::RegisterShutdownTask(nsITargetShutdownTask* aTask) {
+ mozilla::MutexAutoLock lock(mMutex);
+ if (!mLoop || mShutdownTasksRun) {
+ return NS_ERROR_UNEXPECTED;
+ }
+ MOZ_ASSERT(!mShutdownTasks.Contains(aTask));
+ mShutdownTasks.AppendElement(aTask);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+MessageLoop::EventTarget::UnregisterShutdownTask(nsITargetShutdownTask* aTask) {
+ mozilla::MutexAutoLock lock(mMutex);
+ if (!mLoop || mShutdownTasksRun) {
+ return NS_ERROR_UNEXPECTED;
+ }
+ return mShutdownTasks.RemoveElement(aTask) ? NS_OK : NS_ERROR_UNEXPECTED;
+}
+
+//------------------------------------------------------------------------------
+
+// static
+MessageLoop* MessageLoop::current() { return get_tls_ptr().Get(); }
+
+// static
+void MessageLoop::set_current(MessageLoop* loop) { get_tls_ptr().Set(loop); }
+
+static mozilla::Atomic<int32_t> message_loop_id_seq(0);
+
+MessageLoop::MessageLoop(Type type, nsISerialEventTarget* aEventTarget)
+ : type_(type),
+ id_(++message_loop_id_seq),
+ nestable_tasks_allowed_(true),
+ exception_restoration_(false),
+ incoming_queue_lock_("MessageLoop Incoming Queue Lock"),
+ state_(NULL),
+ run_depth_base_(1),
+ shutting_down_(false),
+#ifdef XP_WIN
+ os_modal_loop_(false),
+#endif // XP_WIN
+ transient_hang_timeout_(0),
+ permanent_hang_timeout_(0),
+ next_sequence_num_(0) {
+ DCHECK(!current()) << "should only have one message loop per thread";
+ get_tls_ptr().Set(this);
+
+ // Must initialize after current() is initialized.
+ mEventTarget = new EventTarget(this);
+
+ switch (type_) {
+ case TYPE_MOZILLA_PARENT:
+ MOZ_RELEASE_ASSERT(!aEventTarget);
+ pump_ = new mozilla::ipc::MessagePump(aEventTarget);
+ return;
+ case TYPE_MOZILLA_CHILD:
+ MOZ_RELEASE_ASSERT(!aEventTarget);
+ pump_ = new mozilla::ipc::MessagePumpForChildProcess();
+ // There is a MessageLoop Run call from XRE_InitChildProcess
+ // and another one from MessagePumpForChildProcess. The one
+ // from MessagePumpForChildProcess becomes the base, so we need
+ // to set run_depth_base_ to 2 or we'll never be able to process
+ // Idle tasks.
+ run_depth_base_ = 2;
+ return;
+ case TYPE_MOZILLA_NONMAINTHREAD:
+ pump_ = new mozilla::ipc::MessagePumpForNonMainThreads(aEventTarget);
+ return;
+#if defined(XP_WIN) || defined(XP_DARWIN)
+ case TYPE_MOZILLA_NONMAINUITHREAD:
+ pump_ = new mozilla::ipc::MessagePumpForNonMainUIThreads(aEventTarget);
+ return;
+#elif defined(MOZ_WIDGET_ANDROID)
+ case TYPE_MOZILLA_ANDROID_UI:
+ MOZ_RELEASE_ASSERT(aEventTarget);
+ pump_ = new mozilla::ipc::MessagePumpForAndroidUI(aEventTarget);
+ return;
+#endif // defined(MOZ_WIDGET_ANDROID)
+ default:
+ // Create one of Chromium's standard MessageLoop types below.
+ break;
+ }
+
+#if defined(XP_WIN)
+ // TODO(rvargas): Get rid of the OS guards.
+ if (type_ == TYPE_DEFAULT) {
+ pump_ = new base::MessagePumpDefault();
+ } else if (type_ == TYPE_IO) {
+ pump_ = new base::MessagePumpForIO();
+ } else {
+ DCHECK(type_ == TYPE_UI);
+ pump_ = new base::MessagePumpForUI();
+ }
+#else
+ if (type_ == TYPE_UI) {
+# if defined(XP_DARWIN)
+ pump_ = base::MessagePumpMac::Create();
+# elif defined(XP_LINUX) || defined(__DragonFly__) || defined(XP_FREEBSD) || \
+ defined(XP_NETBSD) || defined(XP_OPENBSD)
+ pump_ = new base::MessagePumpForUI();
+# endif // XP_LINUX
+ } else if (type_ == TYPE_IO) {
+ pump_ = new base::MessagePumpLibevent();
+ } else {
+ pump_ = new base::MessagePumpDefault();
+ }
+#endif
+
+ // We want GetCurrentSerialEventTarget() to return the real nsThread if it
+ // will be used to dispatch tasks. However, under all other cases; we'll want
+ // it to return this MessageLoop's EventTarget.
+ if (nsISerialEventTarget* thread = pump_->GetXPCOMThread()) {
+ MOZ_ALWAYS_SUCCEEDS(thread->RegisterShutdownTask(mEventTarget));
+ } else {
+ mozilla::SerialEventTargetGuard::Set(mEventTarget);
+ }
+}
+
+MessageLoop::~MessageLoop() {
+ DCHECK(this == current());
+
+ // Let interested parties have one last shot at accessing this.
+ FOR_EACH_OBSERVER(DestructionObserver, destruction_observers_,
+ WillDestroyCurrentMessageLoop());
+
+ DCHECK(!state_);
+
+ // Clean up any unprocessed tasks, but take care: deleting a task could
+ // result in the addition of more tasks (e.g., via DeleteSoon). We set a
+ // limit on the number of times we will allow a deleted task to generate more
+ // tasks. Normally, we should only pass through this loop once or twice. If
+ // we end up hitting the loop limit, then it is probably due to one task that
+ // is being stubborn. Inspect the queues to see who is left.
+ bool did_work;
+ for (int i = 0; i < 100; ++i) {
+ DeletePendingTasks();
+ ReloadWorkQueue();
+ // If we end up with empty queues, then break out of the loop.
+ did_work = DeletePendingTasks();
+ if (!did_work) break;
+ }
+ DCHECK(!did_work);
+
+ // OK, now make it so that no one can find us.
+ get_tls_ptr().Set(NULL);
+}
+
+void MessageLoop::AddDestructionObserver(DestructionObserver* obs) {
+ DCHECK(this == current());
+ destruction_observers_.AddObserver(obs);
+}
+
+void MessageLoop::RemoveDestructionObserver(DestructionObserver* obs) {
+ DCHECK(this == current());
+ destruction_observers_.RemoveObserver(obs);
+}
+
+void MessageLoop::Run() {
+ AutoRunState save_state(this);
+ RunHandler();
+}
+
+// Runs the loop in two different SEH modes:
+// enable_SEH_restoration_ = false : any unhandled exception goes to the last
+// one that calls SetUnhandledExceptionFilter().
+// enable_SEH_restoration_ = true : any unhandled exception goes to the filter
+// that was existed before the loop was run.
+void MessageLoop::RunHandler() {
+#if defined(XP_WIN)
+ if (exception_restoration_) {
+ LPTOP_LEVEL_EXCEPTION_FILTER current_filter = GetTopSEHFilter();
+ MOZ_SEH_TRY { RunInternal(); }
+ MOZ_SEH_EXCEPT(SEHFilter(current_filter)) {}
+ return;
+ }
+#endif
+
+ RunInternal();
+}
+
+//------------------------------------------------------------------------------
+
+void MessageLoop::RunInternal() {
+ DCHECK(this == current());
+ pump_->Run(this);
+}
+
+//------------------------------------------------------------------------------
+// Wrapper functions for use in above message loop framework.
+
+bool MessageLoop::ProcessNextDelayedNonNestableTask() {
+ if (state_->run_depth > run_depth_base_) return false;
+
+ if (deferred_non_nestable_work_queue_.empty()) return false;
+
+ nsCOMPtr<nsIRunnable> task =
+ std::move(deferred_non_nestable_work_queue_.front().task);
+ deferred_non_nestable_work_queue_.pop();
+
+ RunTask(task.forget());
+ return true;
+}
+
+//------------------------------------------------------------------------------
+
+void MessageLoop::Quit() {
+ DCHECK(current() == this);
+ if (state_) {
+ state_->quit_received = true;
+ } else {
+ NOTREACHED() << "Must be inside Run to call Quit";
+ }
+}
+
+void MessageLoop::PostTask(already_AddRefed<nsIRunnable> task) {
+ PostTask_Helper(std::move(task), 0);
+}
+
+void MessageLoop::PostDelayedTask(already_AddRefed<nsIRunnable> task,
+ int delay_ms) {
+ PostTask_Helper(std::move(task), delay_ms);
+}
+
+void MessageLoop::PostIdleTask(already_AddRefed<nsIRunnable> task) {
+ DCHECK(current() == this);
+ MOZ_ASSERT(NS_IsMainThread());
+
+ PendingTask pending_task(std::move(task), false);
+ mozilla::LogRunnable::LogDispatch(pending_task.task.get());
+ deferred_non_nestable_work_queue_.push(std::move(pending_task));
+}
+
+// Possibly called on a background thread!
+void MessageLoop::PostTask_Helper(already_AddRefed<nsIRunnable> task,
+ int delay_ms) {
+ if (nsISerialEventTarget* target = pump_->GetXPCOMThread()) {
+ nsresult rv;
+ if (delay_ms) {
+ rv = target->DelayedDispatch(std::move(task), delay_ms);
+ } else {
+ rv = target->Dispatch(std::move(task), 0);
+ }
+ MOZ_ALWAYS_SUCCEEDS(rv);
+ return;
+ }
+
+ // Tasks should only be queued before or during the Run loop, not after.
+ MOZ_ASSERT(!shutting_down_);
+
+ PendingTask pending_task(std::move(task), true);
+
+ if (delay_ms > 0) {
+ pending_task.delayed_run_time =
+ TimeTicks::Now() + TimeDelta::FromMilliseconds(delay_ms);
+ } else {
+ DCHECK(delay_ms == 0) << "delay should not be negative";
+ }
+
+ // Warning: Don't try to short-circuit, and handle this thread's tasks more
+ // directly, as it could starve handling of foreign threads. Put every task
+ // into this queue.
+
+ RefPtr<base::MessagePump> pump;
+ {
+ mozilla::MutexAutoLock locked(incoming_queue_lock_);
+ mozilla::LogRunnable::LogDispatch(pending_task.task.get());
+ incoming_queue_.push(std::move(pending_task));
+ pump = pump_;
+ }
+ // Since the incoming_queue_ may contain a task that destroys this message
+ // loop, we cannot exit incoming_queue_lock_ until we are done with |this|.
+ // We use a stack-based reference to the message pump so that we can call
+ // ScheduleWork outside of incoming_queue_lock_.
+
+ pump->ScheduleWork();
+}
+
+void MessageLoop::SetNestableTasksAllowed(bool allowed) {
+ if (nestable_tasks_allowed_ != allowed) {
+ nestable_tasks_allowed_ = allowed;
+ if (!nestable_tasks_allowed_) return;
+ // Start the native pump if we are not already pumping.
+ pump_->ScheduleWorkForNestedLoop();
+ }
+}
+
+void MessageLoop::ScheduleWork() {
+ // Start the native pump if we are not already pumping.
+ pump_->ScheduleWork();
+}
+
+bool MessageLoop::NestableTasksAllowed() const {
+ return nestable_tasks_allowed_;
+}
+
+//------------------------------------------------------------------------------
+
+void MessageLoop::RunTask(already_AddRefed<nsIRunnable> aTask) {
+ DCHECK(nestable_tasks_allowed_);
+ // Execute the task and assume the worst: It is probably not reentrant.
+ nestable_tasks_allowed_ = false;
+
+ nsCOMPtr<nsIRunnable> task = aTask;
+
+ {
+ mozilla::LogRunnable::Run log(task.get());
+ AUTO_PROFILE_FOLLOWING_RUNNABLE(task);
+ task->Run();
+ task = nullptr;
+ }
+
+ nestable_tasks_allowed_ = true;
+}
+
+bool MessageLoop::DeferOrRunPendingTask(PendingTask&& pending_task) {
+ if (pending_task.nestable || state_->run_depth <= run_depth_base_) {
+ RunTask(pending_task.task.forget());
+ // Show that we ran a task (Note: a new one might arrive as a
+ // consequence!).
+ return true;
+ }
+
+ // We couldn't run the task now because we're in a nested message loop
+ // and the task isn't nestable.
+ mozilla::LogRunnable::LogDispatch(pending_task.task.get());
+ deferred_non_nestable_work_queue_.push(std::move(pending_task));
+ return false;
+}
+
+void MessageLoop::AddToDelayedWorkQueue(const PendingTask& pending_task) {
+ // Move to the delayed work queue. Initialize the sequence number
+ // before inserting into the delayed_work_queue_. The sequence number
+ // is used to faciliate FIFO sorting when two tasks have the same
+ // delayed_run_time value.
+ PendingTask new_pending_task(pending_task);
+ new_pending_task.sequence_num = next_sequence_num_++;
+ mozilla::LogRunnable::LogDispatch(new_pending_task.task.get());
+ delayed_work_queue_.push(std::move(new_pending_task));
+}
+
+void MessageLoop::ReloadWorkQueue() {
+ // We can improve performance of our loading tasks from incoming_queue_ to
+ // work_queue_ by waiting until the last minute (work_queue_ is empty) to
+ // load. That reduces the number of locks-per-task significantly when our
+ // queues get large.
+ if (!work_queue_.empty())
+ return; // Wait till we *really* need to lock and load.
+
+ // Acquire all we can from the inter-thread queue with one lock acquisition.
+ {
+ mozilla::MutexAutoLock lock(incoming_queue_lock_);
+ if (incoming_queue_.empty()) return;
+ std::swap(incoming_queue_, work_queue_);
+ DCHECK(incoming_queue_.empty());
+ }
+}
+
+bool MessageLoop::DeletePendingTasks() {
+ MOZ_ASSERT(work_queue_.empty());
+ bool did_work = !deferred_non_nestable_work_queue_.empty();
+ while (!deferred_non_nestable_work_queue_.empty()) {
+ deferred_non_nestable_work_queue_.pop();
+ }
+ did_work |= !delayed_work_queue_.empty();
+ while (!delayed_work_queue_.empty()) {
+ delayed_work_queue_.pop();
+ }
+ return did_work;
+}
+
+bool MessageLoop::DoWork() {
+ if (!nestable_tasks_allowed_) {
+ // Task can't be executed right now.
+ return false;
+ }
+
+ for (;;) {
+ ReloadWorkQueue();
+ if (work_queue_.empty()) break;
+
+ // Execute oldest task.
+ do {
+ PendingTask pending_task = std::move(work_queue_.front());
+ work_queue_.pop();
+ if (!pending_task.delayed_run_time.is_null()) {
+ // NB: Don't move, because we use this later!
+ AddToDelayedWorkQueue(pending_task);
+ // If we changed the topmost task, then it is time to re-schedule.
+ if (delayed_work_queue_.top().task == pending_task.task)
+ pump_->ScheduleDelayedWork(pending_task.delayed_run_time);
+ } else {
+ if (DeferOrRunPendingTask(std::move(pending_task))) return true;
+ }
+ } while (!work_queue_.empty());
+ }
+
+ // Nothing happened.
+ return false;
+}
+
+bool MessageLoop::DoDelayedWork(TimeTicks* next_delayed_work_time) {
+ if (!nestable_tasks_allowed_ || delayed_work_queue_.empty()) {
+ *next_delayed_work_time = TimeTicks();
+ return false;
+ }
+
+ if (delayed_work_queue_.top().delayed_run_time > TimeTicks::Now()) {
+ *next_delayed_work_time = delayed_work_queue_.top().delayed_run_time;
+ return false;
+ }
+
+ PendingTask pending_task = delayed_work_queue_.top();
+ delayed_work_queue_.pop();
+
+ if (!delayed_work_queue_.empty())
+ *next_delayed_work_time = delayed_work_queue_.top().delayed_run_time;
+
+ return DeferOrRunPendingTask(std::move(pending_task));
+}
+
+bool MessageLoop::DoIdleWork() {
+ if (ProcessNextDelayedNonNestableTask()) return true;
+
+ if (state_->quit_received) pump_->Quit();
+
+ return false;
+}
+
+//------------------------------------------------------------------------------
+// MessageLoop::AutoRunState
+
+MessageLoop::AutoRunState::AutoRunState(MessageLoop* loop) : loop_(loop) {
+ // Top-level Run should only get called once.
+ MOZ_ASSERT(!loop_->shutting_down_);
+
+ // Make the loop reference us.
+ previous_state_ = loop_->state_;
+ if (previous_state_) {
+ run_depth = previous_state_->run_depth + 1;
+ } else {
+ run_depth = 1;
+ }
+ loop_->state_ = this;
+
+ // Initialize the other fields:
+ quit_received = false;
+#if defined(XP_WIN)
+ dispatcher = NULL;
+#endif
+}
+
+MessageLoop::AutoRunState::~AutoRunState() {
+ loop_->state_ = previous_state_;
+
+ // If exiting a top-level Run, then we're shutting down.
+ loop_->shutting_down_ = !previous_state_;
+}
+
+//------------------------------------------------------------------------------
+// MessageLoop::PendingTask
+
+bool MessageLoop::PendingTask::operator<(const PendingTask& other) const {
+ // Since the top of a priority queue is defined as the "greatest" element, we
+ // need to invert the comparison here. We want the smaller time to be at the
+ // top of the heap.
+
+ if (delayed_run_time < other.delayed_run_time) return false;
+
+ if (delayed_run_time > other.delayed_run_time) return true;
+
+ // If the times happen to match, then we use the sequence number to decide.
+ // Compare the difference to support integer roll-over.
+ return (sequence_num - other.sequence_num) > 0;
+}
+
+//------------------------------------------------------------------------------
+// MessageLoop::SerialEventTarget
+
+nsISerialEventTarget* MessageLoop::SerialEventTarget() { return mEventTarget; }
+
+//------------------------------------------------------------------------------
+// MessageLoopForUI
+
+#if defined(XP_WIN)
+
+void MessageLoopForUI::Run(Dispatcher* dispatcher) {
+ AutoRunState save_state(this);
+ state_->dispatcher = dispatcher;
+ RunHandler();
+}
+
+void MessageLoopForUI::AddObserver(Observer* observer) {
+ pump_win()->AddObserver(observer);
+}
+
+void MessageLoopForUI::RemoveObserver(Observer* observer) {
+ pump_win()->RemoveObserver(observer);
+}
+
+void MessageLoopForUI::WillProcessMessage(const MSG& message) {
+ pump_win()->WillProcessMessage(message);
+}
+void MessageLoopForUI::DidProcessMessage(const MSG& message) {
+ pump_win()->DidProcessMessage(message);
+}
+void MessageLoopForUI::PumpOutPendingPaintMessages() {
+ pump_ui()->PumpOutPendingPaintMessages();
+}
+
+#endif // defined(XP_WIN)
+
+//------------------------------------------------------------------------------
+// MessageLoopForIO
+
+#if defined(XP_WIN)
+
+void MessageLoopForIO::RegisterIOHandler(HANDLE file, IOHandler* handler) {
+ pump_io()->RegisterIOHandler(file, handler);
+}
+
+bool MessageLoopForIO::WaitForIOCompletion(DWORD timeout, IOHandler* filter) {
+ return pump_io()->WaitForIOCompletion(timeout, filter);
+}
+
+#else
+
+bool MessageLoopForIO::WatchFileDescriptor(int fd, bool persistent, Mode mode,
+ FileDescriptorWatcher* controller,
+ Watcher* delegate) {
+ return pump_libevent()->WatchFileDescriptor(
+ fd, persistent, static_cast<base::MessagePumpLibevent::Mode>(mode),
+ controller, delegate);
+}
+
+bool MessageLoopForIO::CatchSignal(int sig, SignalEvent* sigevent,
+ SignalWatcher* delegate) {
+ return pump_libevent()->CatchSignal(sig, sigevent, delegate);
+}
+
+#endif
diff --git a/ipc/chromium/src/base/message_loop.h b/ipc/chromium/src/base/message_loop.h
new file mode 100644
index 0000000000..ee3f118ac3
--- /dev/null
+++ b/ipc/chromium/src/base/message_loop.h
@@ -0,0 +1,559 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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_MESSAGE_LOOP_H_
+#define BASE_MESSAGE_LOOP_H_
+
+#include <deque>
+#include <queue>
+#include <string>
+#include <vector>
+#include <map>
+
+#include "base/message_pump.h"
+#include "base/observer_list.h"
+
+#include "mozilla/Mutex.h"
+
+#if defined(XP_WIN)
+// We need this to declare base::MessagePumpWin::Dispatcher, which we should
+// really just eliminate.
+# include "base/message_pump_win.h"
+#else
+# include "base/message_pump_libevent.h"
+#endif
+
+#include "nsCOMPtr.h"
+#include "nsIRunnable.h"
+#include "nsThreadUtils.h"
+
+class nsISerialEventTarget;
+
+namespace mozilla {
+namespace ipc {
+
+class DoWorkRunnable;
+
+} /* namespace ipc */
+} /* namespace mozilla */
+
+// A MessageLoop is used to process events for a particular thread. There is
+// at most one MessageLoop instance per thread.
+//
+// Events include at a minimum Task instances submitted to PostTask or those
+// managed by TimerManager. Depending on the type of message pump used by the
+// MessageLoop other events such as UI messages may be processed. On Windows
+// APC calls (as time permits) and signals sent to a registered set of HANDLEs
+// may also be processed.
+//
+// NOTE: Unless otherwise specified, a MessageLoop's methods may only be called
+// on the thread where the MessageLoop's Run method executes.
+//
+// NOTE: MessageLoop has task reentrancy protection. This means that if a
+// task is being processed, a second task cannot start until the first task is
+// finished. Reentrancy can happen when processing a task, and an inner
+// message pump is created. That inner pump then processes native messages
+// which could implicitly start an inner task. Inner message pumps are created
+// with dialogs (DialogBox), common dialogs (GetOpenFileName), OLE functions
+// (DoDragDrop), printer functions (StartDoc) and *many* others.
+//
+// Sample workaround when inner task processing is needed:
+// bool old_state = MessageLoop::current()->NestableTasksAllowed();
+// MessageLoop::current()->SetNestableTasksAllowed(true);
+// HRESULT hr = DoDragDrop(...); // Implicitly runs a modal message loop here.
+// MessageLoop::current()->SetNestableTasksAllowed(old_state);
+// // Process hr (the result returned by DoDragDrop().
+//
+// Please be SURE your task is reentrant (nestable) and all global variables
+// are stable and accessible before calling SetNestableTasksAllowed(true).
+//
+class MessageLoop : public base::MessagePump::Delegate {
+ friend class mozilla::ipc::DoWorkRunnable;
+
+ public:
+ // A DestructionObserver is notified when the current MessageLoop is being
+ // destroyed. These obsevers are notified prior to MessageLoop::current()
+ // being changed to return NULL. This gives interested parties the chance to
+ // do final cleanup that depends on the MessageLoop.
+ //
+ // NOTE: Any tasks posted to the MessageLoop during this notification will
+ // not be run. Instead, they will be deleted.
+ //
+ class DestructionObserver {
+ public:
+ virtual ~DestructionObserver() {}
+ virtual void WillDestroyCurrentMessageLoop() = 0;
+ };
+
+ // Add a DestructionObserver, which will start receiving notifications
+ // immediately.
+ void AddDestructionObserver(DestructionObserver* destruction_observer);
+
+ // Remove a DestructionObserver. It is safe to call this method while a
+ // DestructionObserver is receiving a notification callback.
+ void RemoveDestructionObserver(DestructionObserver* destruction_observer);
+
+ // The "PostTask" family of methods call the task's Run method asynchronously
+ // from within a message loop at some point in the future.
+ //
+ // With the PostTask variant, tasks are invoked in FIFO order, inter-mixed
+ // with normal UI or IO event processing. With the PostDelayedTask variant,
+ // tasks are called after at least approximately 'delay_ms' have elapsed.
+ //
+ // The NonNestable variants work similarly except that they promise never to
+ // dispatch the task from a nested invocation of MessageLoop::Run. Instead,
+ // such tasks get deferred until the top-most MessageLoop::Run is executing.
+ //
+ // The MessageLoop takes ownership of the Task, and deletes it after it has
+ // been Run().
+ //
+ // New tasks should not be posted after the invocation of a MessageLoop's
+ // Run method. Otherwise, they may fail to actually run. Callers should check
+ // if the MessageLoop is processing tasks if necessary by calling
+ // IsAcceptingTasks().
+ //
+ // NOTE: These methods may be called on any thread. The Task will be invoked
+ // on the thread that executes MessageLoop::Run().
+
+ bool IsAcceptingTasks() const { return !shutting_down_; }
+
+ void PostTask(already_AddRefed<nsIRunnable> task);
+
+ void PostDelayedTask(already_AddRefed<nsIRunnable> task, int delay_ms);
+
+ // PostIdleTask is not thread safe and should be called on this thread
+ void PostIdleTask(already_AddRefed<nsIRunnable> task);
+
+ // Run the message loop.
+ void Run();
+
+ // Signals the Run method to return after it is done processing all pending
+ // messages. This method may only be called on the same thread that called
+ // Run, and Run must still be on the call stack.
+ //
+ // Use QuitTask if you need to Quit another thread's MessageLoop, but note
+ // that doing so is fairly dangerous if the target thread makes nested calls
+ // to MessageLoop::Run. The problem being that you won't know which nested
+ // run loop you are quiting, so be careful!
+ //
+ void Quit();
+
+ // Invokes Quit on the current MessageLoop when run. Useful to schedule an
+ // arbitrary MessageLoop to Quit.
+ class QuitTask : public mozilla::Runnable {
+ public:
+ QuitTask() : mozilla::Runnable("QuitTask") {}
+ NS_IMETHOD Run() override {
+ MessageLoop::current()->Quit();
+ return NS_OK;
+ }
+ };
+
+ // Return an XPCOM-compatible event target for this thread.
+ nsISerialEventTarget* SerialEventTarget();
+
+ // A MessageLoop has a particular type, which indicates the set of
+ // asynchronous events it may process in addition to tasks and timers.
+ //
+ // TYPE_DEFAULT
+ // This type of ML only supports tasks and timers.
+ //
+ // TYPE_UI
+ // This type of ML also supports native UI events (e.g., Windows messages).
+ // See also MessageLoopForUI.
+ //
+ // TYPE_IO
+ // This type of ML also supports asynchronous IO. See also
+ // MessageLoopForIO.
+ //
+ // TYPE_MOZILLA_CHILD
+ // This type of ML is used in Mozilla child processes which initialize
+ // XPCOM and use the gecko event loop.
+ //
+ // TYPE_MOZILLA_PARENT
+ // This type of ML is used in Mozilla parent processes which initialize
+ // XPCOM and use the gecko event loop.
+ //
+ // TYPE_MOZILLA_NONMAINTHREAD
+ // This type of ML is used in Mozilla parent processes which initialize
+ // XPCOM and use the nsThread event loop.
+ //
+ // TYPE_MOZILLA_NONMAINUITHREAD
+ // This type of ML is used in Mozilla processes which initialize XPCOM
+ // and use TYPE_UI loop logic.
+ //
+ enum Type {
+ TYPE_DEFAULT,
+ TYPE_UI,
+ TYPE_IO,
+ TYPE_MOZILLA_CHILD,
+ TYPE_MOZILLA_PARENT,
+ TYPE_MOZILLA_NONMAINTHREAD,
+ TYPE_MOZILLA_NONMAINUITHREAD,
+ TYPE_MOZILLA_ANDROID_UI
+ };
+
+ // Normally, it is not necessary to instantiate a MessageLoop. Instead, it
+ // is typical to make use of the current thread's MessageLoop instance.
+ explicit MessageLoop(Type type = TYPE_DEFAULT,
+ nsISerialEventTarget* aEventTarget = nullptr);
+ ~MessageLoop();
+
+ // Returns the type passed to the constructor.
+ Type type() const { return type_; }
+
+ // Unique, non-repeating ID for this message loop.
+ int32_t id() const { return id_; }
+
+ // Optional call to connect the thread name with this loop.
+ void set_thread_name(const std::string& aThreadName) {
+ DCHECK(thread_name_.empty()) << "Should not rename this thread!";
+ thread_name_ = aThreadName;
+ }
+ const std::string& thread_name() const { return thread_name_; }
+
+ // Returns the MessageLoop object for the current thread, or null if none.
+ static MessageLoop* current();
+
+ static void set_current(MessageLoop* loop);
+
+ // Enables or disables the recursive task processing. This happens in the case
+ // of recursive message loops. Some unwanted message loop may occurs when
+ // using common controls or printer functions. By default, recursive task
+ // processing is disabled.
+ //
+ // The specific case where tasks get queued is:
+ // - The thread is running a message loop.
+ // - It receives a task #1 and execute it.
+ // - The task #1 implicitly start a message loop, like a MessageBox in the
+ // unit test. This can also be StartDoc or GetSaveFileName.
+ // - The thread receives a task #2 before or while in this second message
+ // loop.
+ // - With NestableTasksAllowed set to true, the task #2 will run right away.
+ // Otherwise, it will get executed right after task #1 completes at "thread
+ // message loop level".
+ void SetNestableTasksAllowed(bool allowed);
+ void ScheduleWork();
+ bool NestableTasksAllowed() const;
+
+ // Enables or disables the restoration during an exception of the unhandled
+ // exception filter that was active when Run() was called. This can happen
+ // if some third party code call SetUnhandledExceptionFilter() and never
+ // restores the previous filter.
+ void set_exception_restoration(bool restore) {
+ exception_restoration_ = restore;
+ }
+
+#if defined(XP_WIN)
+ void set_os_modal_loop(bool os_modal_loop) { os_modal_loop_ = os_modal_loop; }
+
+ bool& os_modal_loop() { return os_modal_loop_; }
+#endif // XP_WIN
+
+ // Set the timeouts for background hang monitoring.
+ // A value of 0 indicates there is no timeout.
+ void set_hang_timeouts(uint32_t transient_timeout_ms,
+ uint32_t permanent_timeout_ms) {
+ transient_hang_timeout_ = transient_timeout_ms;
+ permanent_hang_timeout_ = permanent_timeout_ms;
+ }
+ uint32_t transient_hang_timeout() const { return transient_hang_timeout_; }
+ uint32_t permanent_hang_timeout() const { return permanent_hang_timeout_; }
+
+ //----------------------------------------------------------------------------
+ protected:
+ struct RunState {
+ // Used to count how many Run() invocations are on the stack.
+ int run_depth;
+
+ // Used to record that Quit() was called, or that we should quit the pump
+ // once it becomes idle.
+ bool quit_received;
+
+#if defined(XP_WIN)
+ base::MessagePumpWin::Dispatcher* dispatcher;
+#endif
+ };
+
+ class AutoRunState : RunState {
+ public:
+ explicit AutoRunState(MessageLoop* loop);
+ ~AutoRunState();
+
+ private:
+ MessageLoop* loop_;
+ RunState* previous_state_;
+ };
+
+ // This structure is copied around by value.
+ struct PendingTask {
+ nsCOMPtr<nsIRunnable> task; // The task to run.
+ base::TimeTicks delayed_run_time; // The time when the task should be run.
+ int sequence_num; // Secondary sort key for run time.
+ bool nestable; // OK to dispatch from a nested loop.
+
+ PendingTask(already_AddRefed<nsIRunnable> aTask, bool aNestable)
+ : task(aTask), sequence_num(0), nestable(aNestable) {}
+
+ PendingTask(PendingTask&& aOther)
+ : task(std::move(aOther.task)),
+ delayed_run_time(aOther.delayed_run_time),
+ sequence_num(aOther.sequence_num),
+ nestable(aOther.nestable) {}
+
+ // std::priority_queue<T>::top is dumb, so we have to have this.
+ PendingTask(const PendingTask& aOther)
+ : task(aOther.task),
+ delayed_run_time(aOther.delayed_run_time),
+ sequence_num(aOther.sequence_num),
+ nestable(aOther.nestable) {}
+ PendingTask& operator=(const PendingTask& aOther) {
+ task = aOther.task;
+ delayed_run_time = aOther.delayed_run_time;
+ sequence_num = aOther.sequence_num;
+ nestable = aOther.nestable;
+ return *this;
+ }
+
+ // Used to support sorting.
+ bool operator<(const PendingTask& other) const;
+ };
+
+ typedef std::queue<PendingTask> TaskQueue;
+ typedef std::priority_queue<PendingTask> DelayedTaskQueue;
+
+#if defined(XP_WIN)
+ base::MessagePumpWin* pump_win() {
+ return static_cast<base::MessagePumpWin*>(pump_.get());
+ }
+#else
+ base::MessagePumpLibevent* pump_libevent() {
+ return static_cast<base::MessagePumpLibevent*>(pump_.get());
+ }
+#endif
+
+ // A function to encapsulate all the exception handling capability in the
+ // stacks around the running of a main message loop. It will run the message
+ // loop in a SEH try block or not depending on the set_SEH_restoration()
+ // flag.
+ void RunHandler();
+
+ // A surrounding stack frame around the running of the message loop that
+ // supports all saving and restoring of state, as is needed for any/all (ugly)
+ // recursive calls.
+ void RunInternal();
+
+ // Called to process any delayed non-nestable tasks.
+ bool ProcessNextDelayedNonNestableTask();
+
+ //----------------------------------------------------------------------------
+ // Run a work_queue_ task or new_task, and delete it (if it was processed by
+ // PostTask). If there are queued tasks, the oldest one is executed and
+ // new_task is queued. new_task is optional and can be NULL. In this NULL
+ // case, the method will run one pending task (if any exist). Returns true if
+ // it executes a task. Queued tasks accumulate only when there is a
+ // non-nestable task currently processing, in which case the new_task is
+ // appended to the list work_queue_. Such re-entrancy generally happens when
+ // an unrequested message pump (typical of a native dialog) is executing in
+ // the context of a task.
+ bool QueueOrRunTask(already_AddRefed<nsIRunnable> new_task);
+
+ // Runs the specified task and deletes it.
+ void RunTask(already_AddRefed<nsIRunnable> task);
+
+ // Calls RunTask or queues the pending_task on the deferred task list if it
+ // cannot be run right now. Returns true if the task was run.
+ bool DeferOrRunPendingTask(PendingTask&& pending_task);
+
+ // Adds the pending task to delayed_work_queue_.
+ void AddToDelayedWorkQueue(const PendingTask& pending_task);
+
+ // Load tasks from the incoming_queue_ into work_queue_ if the latter is
+ // empty. The former requires a lock to access, while the latter is directly
+ // accessible on this thread.
+ void ReloadWorkQueue();
+
+ // Delete tasks that haven't run yet without running them. Used in the
+ // destructor to make sure all the task's destructors get called. Returns
+ // true if some work was done.
+ bool DeletePendingTasks();
+
+ // Post a task to our incomming queue.
+ void PostTask_Helper(already_AddRefed<nsIRunnable> task, int delay_ms);
+
+ // base::MessagePump::Delegate methods:
+ virtual bool DoWork() override;
+ virtual bool DoDelayedWork(base::TimeTicks* next_delayed_work_time) override;
+ virtual bool DoIdleWork() override;
+
+ Type type_;
+ int32_t id_;
+
+ // A list of tasks that need to be processed by this instance. Note that
+ // this queue is only accessed (push/pop) by our current thread.
+ TaskQueue work_queue_;
+
+ // Contains delayed tasks, sorted by their 'delayed_run_time' property.
+ DelayedTaskQueue delayed_work_queue_;
+
+ // A queue of non-nestable tasks that we had to defer because when it came
+ // time to execute them we were in a nested message loop. They will execute
+ // once we're out of nested message loops.
+ TaskQueue deferred_non_nestable_work_queue_;
+
+ RefPtr<base::MessagePump> pump_;
+
+ base::ObserverList<DestructionObserver> destruction_observers_;
+
+ // A recursion block that prevents accidentally running additonal tasks when
+ // insider a (accidentally induced?) nested message pump.
+ bool nestable_tasks_allowed_;
+
+ bool exception_restoration_;
+
+ std::string thread_name_;
+
+ // A null terminated list which creates an incoming_queue of tasks that are
+ // aquired under a mutex for processing on this instance's thread. These tasks
+ // have not yet been sorted out into items for our work_queue_ vs items that
+ // will be handled by the TimerManager.
+ TaskQueue incoming_queue_ MOZ_GUARDED_BY(incoming_queue_lock_);
+ // Protect access to incoming_queue_.
+ mozilla::Mutex incoming_queue_lock_;
+
+ RunState* state_;
+ int run_depth_base_;
+ bool shutting_down_;
+
+#if defined(XP_WIN)
+ // Should be set to true before calling Windows APIs like TrackPopupMenu, etc
+ // which enter a modal message loop.
+ bool os_modal_loop_;
+#endif
+
+ // Timeout values for hang monitoring
+ uint32_t transient_hang_timeout_;
+ uint32_t permanent_hang_timeout_;
+
+ // The next sequence number to use for delayed tasks.
+ int next_sequence_num_;
+
+ class EventTarget;
+ RefPtr<EventTarget> mEventTarget;
+
+ DISALLOW_COPY_AND_ASSIGN(MessageLoop);
+};
+
+//-----------------------------------------------------------------------------
+// MessageLoopForUI extends MessageLoop with methods that are particular to a
+// MessageLoop instantiated with TYPE_UI.
+//
+// This class is typically used like so:
+// MessageLoopForUI::current()->...call some method...
+//
+class MessageLoopForUI : public MessageLoop {
+ public:
+ explicit MessageLoopForUI(Type aType = TYPE_UI) : MessageLoop(aType) {}
+
+ // Returns the MessageLoopForUI of the current thread.
+ static MessageLoopForUI* current() {
+ MessageLoop* loop = MessageLoop::current();
+ if (!loop) return NULL;
+ Type type = loop->type();
+ DCHECK(type == MessageLoop::TYPE_UI ||
+ type == MessageLoop::TYPE_MOZILLA_PARENT ||
+ type == MessageLoop::TYPE_MOZILLA_CHILD);
+ return static_cast<MessageLoopForUI*>(loop);
+ }
+
+#if defined(XP_WIN)
+ typedef base::MessagePumpWin::Dispatcher Dispatcher;
+ typedef base::MessagePumpWin::Observer Observer;
+
+ // Please see MessagePumpWin for definitions of these methods.
+ void Run(Dispatcher* dispatcher);
+ void AddObserver(Observer* observer);
+ void RemoveObserver(Observer* observer);
+ void WillProcessMessage(const MSG& message);
+ void DidProcessMessage(const MSG& message);
+ void PumpOutPendingPaintMessages();
+
+ protected:
+ // TODO(rvargas): Make this platform independent.
+ base::MessagePumpForUI* pump_ui() {
+ return static_cast<base::MessagePumpForUI*>(pump_.get());
+ }
+#endif // defined(XP_WIN)
+};
+
+// Do not add any member variables to MessageLoopForUI! This is important b/c
+// MessageLoopForUI is often allocated via MessageLoop(TYPE_UI). Any extra
+// data that you need should be stored on the MessageLoop's pump_ instance.
+COMPILE_ASSERT(sizeof(MessageLoop) == sizeof(MessageLoopForUI),
+ MessageLoopForUI_should_not_have_extra_member_variables);
+
+//-----------------------------------------------------------------------------
+// MessageLoopForIO extends MessageLoop with methods that are particular to a
+// MessageLoop instantiated with TYPE_IO.
+//
+// This class is typically used like so:
+// MessageLoopForIO::current()->...call some method...
+//
+class MessageLoopForIO : public MessageLoop {
+ public:
+ MessageLoopForIO() : MessageLoop(TYPE_IO) {}
+
+ // Returns the MessageLoopForIO of the current thread.
+ static MessageLoopForIO* current() {
+ MessageLoop* loop = MessageLoop::current();
+ DCHECK_EQ(MessageLoop::TYPE_IO, loop->type());
+ return static_cast<MessageLoopForIO*>(loop);
+ }
+
+#if defined(XP_WIN)
+ typedef base::MessagePumpForIO::IOHandler IOHandler;
+ typedef base::MessagePumpForIO::IOContext IOContext;
+
+ // Please see MessagePumpWin for definitions of these methods.
+ void RegisterIOHandler(HANDLE file_handle, IOHandler* handler);
+ bool WaitForIOCompletion(DWORD timeout, IOHandler* filter);
+
+ protected:
+ // TODO(rvargas): Make this platform independent.
+ base::MessagePumpForIO* pump_io() {
+ return static_cast<base::MessagePumpForIO*>(pump_.get());
+ }
+
+#else
+ typedef base::MessagePumpLibevent::Watcher Watcher;
+ typedef base::MessagePumpLibevent::FileDescriptorWatcher
+ FileDescriptorWatcher;
+
+ enum Mode {
+ WATCH_READ = base::MessagePumpLibevent::WATCH_READ,
+ WATCH_WRITE = base::MessagePumpLibevent::WATCH_WRITE,
+ WATCH_READ_WRITE = base::MessagePumpLibevent::WATCH_READ_WRITE
+ };
+
+ // Please see MessagePumpLibevent for definition.
+ bool WatchFileDescriptor(int fd, bool persistent, Mode mode,
+ FileDescriptorWatcher* controller,
+ Watcher* delegate);
+
+ typedef base::MessagePumpLibevent::SignalEvent SignalEvent;
+ typedef base::MessagePumpLibevent::SignalWatcher SignalWatcher;
+ bool CatchSignal(int sig, SignalEvent* sigevent, SignalWatcher* delegate);
+
+#endif
+};
+
+// Do not add any member variables to MessageLoopForIO! This is important b/c
+// MessageLoopForIO is often allocated via MessageLoop(TYPE_IO). Any extra
+// data that you need should be stored on the MessageLoop's pump_ instance.
+COMPILE_ASSERT(sizeof(MessageLoop) == sizeof(MessageLoopForIO),
+ MessageLoopForIO_should_not_have_extra_member_variables);
+
+#endif // BASE_MESSAGE_LOOP_H_
diff --git a/ipc/chromium/src/base/message_pump.h b/ipc/chromium/src/base/message_pump.h
new file mode 100644
index 0000000000..884c016d20
--- /dev/null
+++ b/ipc/chromium/src/base/message_pump.h
@@ -0,0 +1,140 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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_MESSAGE_PUMP_H_
+#define BASE_MESSAGE_PUMP_H_
+
+#include "nsISupportsImpl.h"
+
+class nsISerialEventTarget;
+
+namespace base {
+
+class TimeTicks;
+
+class MessagePump {
+ public:
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MessagePump)
+
+ // Please see the comments above the Run method for an illustration of how
+ // these delegate methods are used.
+ class Delegate {
+ public:
+ virtual ~Delegate() {}
+
+ // Called from within Run in response to ScheduleWork or when the message
+ // pump would otherwise call DoDelayedWork. Returns true to indicate that
+ // work was done. DoDelayedWork will not be called if DoWork returns true.
+ virtual bool DoWork() = 0;
+
+ // Called from within Run in response to ScheduleDelayedWork or when the
+ // message pump would otherwise sleep waiting for more work. Returns true
+ // to indicate that delayed work was done. DoIdleWork will not be called
+ // if DoDelayedWork returns true. Upon return |next_delayed_work_time|
+ // indicates the time when DoDelayedWork should be called again. If
+ // |next_delayed_work_time| is null (per Time::is_null), then the queue of
+ // future delayed work (timer events) is currently empty, and no additional
+ // calls to this function need to be scheduled.
+ virtual bool DoDelayedWork(TimeTicks* next_delayed_work_time) = 0;
+
+ // Called from within Run just before the message pump goes to sleep.
+ // Returns true to indicate that idle work was done.
+ virtual bool DoIdleWork() = 0;
+ };
+
+ // The Run method is called to enter the message pump's run loop.
+ //
+ // Within the method, the message pump is responsible for processing native
+ // messages as well as for giving cycles to the delegate periodically. The
+ // message pump should take care to mix delegate callbacks with native
+ // message processing so neither type of event starves the other of cycles.
+ //
+ // The anatomy of a typical run loop:
+ //
+ // for (;;) {
+ // bool did_work = DoInternalWork();
+ // if (should_quit_)
+ // break;
+ //
+ // did_work |= delegate_->DoWork();
+ // if (should_quit_)
+ // break;
+ //
+ // did_work |= delegate_->DoDelayedWork();
+ // if (should_quit_)
+ // break;
+ //
+ // if (did_work)
+ // continue;
+ //
+ // did_work = delegate_->DoIdleWork();
+ // if (should_quit_)
+ // break;
+ //
+ // if (did_work)
+ // continue;
+ //
+ // WaitForWork();
+ // }
+ //
+ // Here, DoInternalWork is some private method of the message pump that is
+ // responsible for dispatching the next UI message or notifying the next IO
+ // completion (for example). WaitForWork is a private method that simply
+ // blocks until there is more work of any type to do.
+ //
+ // Notice that the run loop cycles between calling DoInternalWork, DoWork,
+ // and DoDelayedWork methods. This helps ensure that neither work queue
+ // starves the other. This is important for message pumps that are used to
+ // drive animations, for example.
+ //
+ // Notice also that after each callout to foreign code, the run loop checks
+ // to see if it should quit. The Quit method is responsible for setting this
+ // flag. No further work is done once the quit flag is set.
+ //
+ // NOTE: Care must be taken to handle Run being called again from within any
+ // of the callouts to foreign code. Native message pumps may also need to
+ // deal with other native message pumps being run outside their control
+ // (e.g., the MessageBox API on Windows pumps UI messages!). To be specific,
+ // the callouts (DoWork and DoDelayedWork) MUST still be provided even in
+ // nested sub-loops that are "seemingly" outside the control of this message
+ // pump. DoWork in particular must never be starved for time slices unless
+ // it returns false (meaning it has run out of things to do).
+ //
+ virtual void Run(Delegate* delegate) = 0;
+
+ // Quit immediately from the most recently entered run loop. This method may
+ // only be used on the thread that called Run.
+ virtual void Quit() = 0;
+
+ // Schedule a DoWork callback to happen reasonably soon. Does nothing if a
+ // DoWork callback is already scheduled. This method may be called from any
+ // thread. Once this call is made, DoWork should not be "starved" at least
+ // until it returns a value of false.
+ virtual void ScheduleWork() = 0;
+
+ // This method may only called from the thread that called Run.
+ //
+ // Ensure that DoWork will be called if a nested loop is entered.
+ // If a MessagePump can already guarantee that DoWork will be called
+ // "reasonably soon", this method can be a no-op to avoid expensive
+ // atomic tests and/or syscalls required for ScheduleWork().
+ virtual void ScheduleWorkForNestedLoop() { ScheduleWork(); };
+
+ // Schedule a DoDelayedWork callback to happen at the specified time,
+ // cancelling any pending DoDelayedWork callback. This method may only be
+ // used on the thread that called Run.
+ virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) = 0;
+
+ // If returned, just use the nsThread.
+ virtual nsISerialEventTarget* GetXPCOMThread() { return nullptr; }
+
+ protected:
+ virtual ~MessagePump(){};
+};
+
+} // namespace base
+
+#endif // BASE_MESSAGE_PUMP_H_
diff --git a/ipc/chromium/src/base/message_pump_android.cc b/ipc/chromium/src/base/message_pump_android.cc
new file mode 100644
index 0000000000..6d35534e5c
--- /dev/null
+++ b/ipc/chromium/src/base/message_pump_android.cc
@@ -0,0 +1,104 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_pump_android.h"
+
+#include <fcntl.h>
+#include <math.h>
+
+#include "base/eintr_wrapper.h"
+#include "base/logging.h"
+#include "base/platform_thread.h"
+
+namespace mozilla {
+bool ProcessNextEvent();
+void NotifyEvent();
+} // namespace mozilla
+
+namespace base {
+
+MessagePumpForUI::MessagePumpForUI() : state_(NULL) {}
+
+MessagePumpForUI::~MessagePumpForUI() {}
+
+void MessagePumpForUI::Run(Delegate* delegate) {
+ RunState state;
+ state.delegate = delegate;
+ state.should_quit = false;
+ state.run_depth = state_ ? state_->run_depth + 1 : 1;
+ // We really only do a single task for each iteration of the loop. If we
+ // have done something, assume there is likely something more to do. This
+ // will mean that we don't block on the message pump until there was nothing
+ // more to do. We also set this to true to make sure not to block on the
+ // first iteration of the loop, so RunAllPending() works correctly.
+ state.more_work_is_plausible = true;
+
+ RunState* previous_state = state_;
+ state_ = &state;
+
+ // We run our own loop instead of using g_main_loop_quit in one of the
+ // callbacks. This is so we only quit our own loops, and we don't quit
+ // nested loops run by others. TODO(deanm): Is this what we want?
+
+ while (!state_->should_quit) {
+ mozilla::ProcessNextEvent();
+ if (work_scheduled) {
+ work_scheduled = false;
+ HandleDispatch();
+ }
+ }
+
+ state_ = previous_state;
+}
+
+void MessagePumpForUI::HandleDispatch() {
+ // We should only ever have a single message on the wakeup pipe, since we
+ // are only signaled when the queue went from empty to non-empty. The qApp
+ // poll will tell us whether there was data, so this read shouldn't block.
+ if (state_->should_quit) return;
+
+ state_->more_work_is_plausible = false;
+
+ if (state_->delegate->DoWork()) state_->more_work_is_plausible = true;
+
+ if (state_->should_quit) return;
+
+ if (state_->delegate->DoDelayedWork(&delayed_work_time_))
+ state_->more_work_is_plausible = true;
+ if (state_->should_quit) return;
+
+ // Don't do idle work if we think there are more important things
+ // that we could be doing.
+ if (state_->more_work_is_plausible) return;
+
+ if (state_->delegate->DoIdleWork()) state_->more_work_is_plausible = true;
+ if (state_->should_quit) return;
+}
+
+void MessagePumpForUI::Quit() {
+ if (state_) {
+ state_->should_quit = true;
+ } else {
+ NOTREACHED() << "Quit called outside Run!";
+ }
+}
+
+void MessagePumpForUI::ScheduleWork() {
+ // This can be called on any thread, so we don't want to touch any state
+ // variables as we would then need locks all over. This ensures that if
+ // we are sleeping in a poll that we will wake up.
+ work_scheduled = true;
+ mozilla::NotifyEvent();
+}
+
+void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
+ // We need to wake up the loop in case the poll timeout needs to be
+ // adjusted. This will cause us to try to do work, but that's ok.
+ delayed_work_time_ = delayed_work_time;
+ ScheduleWork();
+}
+
+} // namespace base
diff --git a/ipc/chromium/src/base/message_pump_android.h b/ipc/chromium/src/base/message_pump_android.h
new file mode 100644
index 0000000000..8dd3fdac86
--- /dev/null
+++ b/ipc/chromium/src/base/message_pump_android.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MESSAGE_PUMP_ANDROID_H_
+#define BASE_MESSAGE_PUMP_ANDROID_H_
+
+#include "base/message_pump.h"
+#include "base/time.h"
+
+namespace base {
+
+// This class implements a MessagePump needed for TYPE_UI MessageLoops on
+// Android
+class MessagePumpForUI : public MessagePump {
+ public:
+ MessagePumpForUI();
+ ~MessagePumpForUI();
+
+ virtual void Run(Delegate* delegate);
+ virtual void Quit();
+ virtual void ScheduleWork();
+ virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time);
+
+ // Internal methods used for processing the pump callbacks. They are
+ // public for simplicity but should not be used directly.
+ // HandleDispatch is called after the poll has completed.
+ void HandleDispatch();
+
+ private:
+ // We may make recursive calls to Run, so we save state that needs to be
+ // separate between them in this structure type.
+ struct RunState {
+ Delegate* delegate;
+
+ // Used to flag that the current Run() invocation should return ASAP.
+ bool should_quit;
+
+ // Used to count how many Run() invocations are on the stack.
+ int run_depth;
+
+ // Used internally for controlling whether we want a message pump
+ // iteration to be blocking or not.
+ bool more_work_is_plausible;
+ };
+
+ RunState* state_;
+
+ // This is the time when we need to do delayed work.
+ TimeTicks delayed_work_time_;
+
+ bool work_scheduled;
+
+ DISALLOW_COPY_AND_ASSIGN(MessagePumpForUI);
+};
+
+} // namespace base
+
+#endif // BASE_MESSAGE_PUMP_ANDROID_H_
diff --git a/ipc/chromium/src/base/message_pump_default.cc b/ipc/chromium/src/base/message_pump_default.cc
new file mode 100644
index 0000000000..9db5789f1a
--- /dev/null
+++ b/ipc/chromium/src/base/message_pump_default.cc
@@ -0,0 +1,96 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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 "base/message_pump_default.h"
+
+#include "base/logging.h"
+#include "base/message_loop.h"
+#include "base/scoped_nsautorelease_pool.h"
+
+#include "mozilla/BackgroundHangMonitor.h"
+#include "mozilla/ProfilerLabels.h"
+#include "mozilla/ProfilerThreadSleep.h"
+
+namespace base {
+
+MessagePumpDefault::MessagePumpDefault()
+ : keep_running_(true), event_(false, false) {}
+
+void MessagePumpDefault::Run(Delegate* delegate) {
+ AUTO_PROFILER_LABEL("MessagePumpDefault::Run", OTHER);
+
+ DCHECK(keep_running_) << "Quit must have been called outside of Run!";
+
+ const MessageLoop* const loop = MessageLoop::current();
+ mozilla::BackgroundHangMonitor hangMonitor(loop->thread_name().c_str(),
+ loop->transient_hang_timeout(),
+ loop->permanent_hang_timeout());
+
+ for (;;) {
+ ScopedNSAutoreleasePool autorelease_pool;
+
+ hangMonitor.NotifyActivity();
+ bool did_work = delegate->DoWork();
+ if (!keep_running_) break;
+
+ hangMonitor.NotifyActivity();
+ did_work |= delegate->DoDelayedWork(&delayed_work_time_);
+ if (!keep_running_) break;
+
+ if (did_work) continue;
+
+ hangMonitor.NotifyActivity();
+ did_work = delegate->DoIdleWork();
+ if (!keep_running_) break;
+
+ if (did_work) continue;
+
+ if (delayed_work_time_.is_null()) {
+ hangMonitor.NotifyWait();
+ AUTO_PROFILER_LABEL("MessagePumpDefault::Run:Wait", IDLE);
+ {
+ AUTO_PROFILER_THREAD_SLEEP;
+ event_.Wait();
+ }
+ } else {
+ TimeDelta delay = delayed_work_time_ - TimeTicks::Now();
+ if (delay > TimeDelta()) {
+ hangMonitor.NotifyWait();
+ AUTO_PROFILER_LABEL("MessagePumpDefault::Run:Wait", IDLE);
+ {
+ AUTO_PROFILER_THREAD_SLEEP;
+ event_.TimedWait(delay);
+ }
+ } else {
+ // It looks like delayed_work_time_ indicates a time in the past, so we
+ // need to call DoDelayedWork now.
+ delayed_work_time_ = TimeTicks();
+ }
+ }
+ // Since event_ is auto-reset, we don't need to do anything special here
+ // other than service each delegate method.
+ }
+
+ keep_running_ = true;
+}
+
+void MessagePumpDefault::Quit() { keep_running_ = false; }
+
+void MessagePumpDefault::ScheduleWork() {
+ // Since this can be called on any thread, we need to ensure that our Run
+ // loop wakes up.
+ event_.Signal();
+}
+
+void MessagePumpDefault::ScheduleDelayedWork(
+ const TimeTicks& delayed_work_time) {
+ // We know that we can't be blocked on Wait right now since this method can
+ // only be called on the same thread as Run, so we only need to update our
+ // record of how long to sleep when we do sleep.
+ delayed_work_time_ = delayed_work_time;
+}
+
+} // namespace base
diff --git a/ipc/chromium/src/base/message_pump_default.h b/ipc/chromium/src/base/message_pump_default.h
new file mode 100644
index 0000000000..99abaf6580
--- /dev/null
+++ b/ipc/chromium/src/base/message_pump_default.h
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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_MESSAGE_PUMP_DEFAULT_H_
+#define BASE_MESSAGE_PUMP_DEFAULT_H_
+
+#include "base/message_pump.h"
+#include "base/time.h"
+#include "base/waitable_event.h"
+
+namespace base {
+
+class MessagePumpDefault : public MessagePump {
+ public:
+ MessagePumpDefault();
+ ~MessagePumpDefault() {}
+
+ // MessagePump methods:
+ virtual void Run(Delegate* delegate) override;
+ virtual void Quit() override;
+ virtual void ScheduleWork() override;
+ virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) override;
+
+ protected:
+ // This flag is set to false when Run should return.
+ bool keep_running_;
+
+ // Used to sleep until there is more work to do.
+ WaitableEvent event_;
+
+ // The time at which we should call DoDelayedWork.
+ TimeTicks delayed_work_time_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MessagePumpDefault);
+};
+
+} // namespace base
+
+#endif // BASE_MESSAGE_PUMP_DEFAULT_H_
diff --git a/ipc/chromium/src/base/message_pump_glib.cc b/ipc/chromium/src/base/message_pump_glib.cc
new file mode 100644
index 0000000000..7f3dc0f965
--- /dev/null
+++ b/ipc/chromium/src/base/message_pump_glib.cc
@@ -0,0 +1,291 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_pump_glib.h"
+
+#include <unistd.h>
+#include <math.h>
+
+#include <gtk/gtk.h>
+#include <glib.h>
+
+#include "base/eintr_wrapper.h"
+#include "base/logging.h"
+#include "base/platform_thread.h"
+
+namespace {
+
+// Return a timeout suitable for the glib loop, -1 to block forever,
+// 0 to return right away, or a timeout in milliseconds from now.
+int GetTimeIntervalMilliseconds(const base::TimeTicks& from) {
+ if (from.is_null()) return -1;
+
+ // Be careful here. TimeDelta has a precision of microseconds, but we want a
+ // value in milliseconds. If there are 5.5ms left, should the delay be 5 or
+ // 6? It should be 6 to avoid executing delayed work too early.
+ int delay =
+ static_cast<int>(ceil((from - base::TimeTicks::Now()).InMillisecondsF()));
+
+ // If this value is negative, then we need to run delayed work soon.
+ return delay < 0 ? 0 : delay;
+}
+
+// A brief refresher on GLib:
+// GLib sources have four callbacks: Prepare, Check, Dispatch and Finalize.
+// On each iteration of the GLib pump, it calls each source's Prepare function.
+// This function should return TRUE if it wants GLib to call its Dispatch, and
+// FALSE otherwise. It can also set a timeout in this case for the next time
+// Prepare should be called again (it may be called sooner).
+// After the Prepare calls, GLib does a poll to check for events from the
+// system. File descriptors can be attached to the sources. The poll may block
+// if none of the Prepare calls returned TRUE. It will block indefinitely, or
+// by the minimum time returned by a source in Prepare.
+// After the poll, GLib calls Check for each source that returned FALSE
+// from Prepare. The return value of Check has the same meaning as for Prepare,
+// making Check a second chance to tell GLib we are ready for Dispatch.
+// Finally, GLib calls Dispatch for each source that is ready. If Dispatch
+// returns FALSE, GLib will destroy the source. Dispatch calls may be recursive
+// (i.e., you can call Run from them), but Prepare and Check cannot.
+// Finalize is called when the source is destroyed.
+// NOTE: It is common for subsytems to want to process pending events while
+// doing intensive work, for example the flash plugin. They usually use the
+// following pattern (recommended by the GTK docs):
+// while (gtk_events_pending()) {
+// gtk_main_iteration();
+// }
+//
+// gtk_events_pending just calls g_main_context_pending, which does the
+// following:
+// - Call prepare on all the sources.
+// - Do the poll with a timeout of 0 (not blocking).
+// - Call check on all the sources.
+// - *Does not* call dispatch on the sources.
+// - Return true if any of prepare() or check() returned true.
+//
+// gtk_main_iteration just calls g_main_context_iteration, which does the whole
+// thing, respecting the timeout for the poll (and block, although it is
+// expected not to if gtk_events_pending returned true), and call dispatch.
+//
+// Thus it is important to only return true from prepare or check if we
+// actually have events or work to do. We also need to make sure we keep
+// internal state consistent so that if prepare/check return true when called
+// from gtk_events_pending, they will still return true when called right
+// after, from gtk_main_iteration.
+//
+// For the GLib pump we try to follow the Windows UI pump model:
+// - Whenever we receive a wakeup event or the timer for delayed work expires,
+// we run DoWork and/or DoDelayedWork. That part will also run in the other
+// event pumps.
+// - We also run DoWork, DoDelayedWork, and possibly DoIdleWork in the main
+// loop, around event handling.
+
+struct WorkSource : public GSource {
+ base::MessagePumpForUI* pump;
+};
+
+gboolean WorkSourcePrepare(GSource* source, gint* timeout_ms) {
+ *timeout_ms = static_cast<WorkSource*>(source)->pump->HandlePrepare();
+ // We always return FALSE, so that our timeout is honored. If we were
+ // to return TRUE, the timeout would be considered to be 0 and the poll
+ // would never block. Once the poll is finished, Check will be called.
+ return FALSE;
+}
+
+gboolean WorkSourceCheck(GSource* source) {
+ // Only return TRUE if Dispatch should be called.
+ return static_cast<WorkSource*>(source)->pump->HandleCheck();
+}
+
+gboolean WorkSourceDispatch(GSource* source, GSourceFunc unused_func,
+ gpointer unused_data) {
+ static_cast<WorkSource*>(source)->pump->HandleDispatch();
+ // Always return TRUE so our source stays registered.
+ return TRUE;
+}
+
+// I wish these could be const, but g_source_new wants non-const.
+GSourceFuncs WorkSourceFuncs = {WorkSourcePrepare, WorkSourceCheck,
+ WorkSourceDispatch, NULL};
+
+} // namespace
+
+namespace base {
+
+MessagePumpForUI::MessagePumpForUI()
+ : state_(NULL),
+ context_(g_main_context_default()),
+ wakeup_gpollfd_(new GPollFD),
+ pipe_full_(false) {
+ // Create our wakeup pipe, which is used to flag when work was scheduled.
+ int fds[2];
+ CHECK(pipe(fds) == 0);
+ wakeup_pipe_read_ = fds[0];
+ wakeup_pipe_write_ = fds[1];
+ wakeup_gpollfd_->fd = wakeup_pipe_read_;
+ wakeup_gpollfd_->events = G_IO_IN;
+
+ work_source_ = g_source_new(&WorkSourceFuncs, sizeof(WorkSource));
+ static_cast<WorkSource*>(work_source_)->pump = this;
+ g_source_add_poll(work_source_, wakeup_gpollfd_.get());
+ // Use a low priority so that we let other events in the queue go first.
+ g_source_set_priority(work_source_, G_PRIORITY_DEFAULT_IDLE);
+ // This is needed to allow Run calls inside Dispatch.
+ g_source_set_can_recurse(work_source_, TRUE);
+ g_source_attach(work_source_, context_);
+}
+
+MessagePumpForUI::~MessagePumpForUI() {
+ gdk_event_handler_set(reinterpret_cast<GdkEventFunc>(gtk_main_do_event), this,
+ NULL);
+ g_source_destroy(work_source_);
+ g_source_unref(work_source_);
+ close(wakeup_pipe_read_);
+ close(wakeup_pipe_write_);
+}
+
+void MessagePumpForUI::Run(Delegate* delegate) {
+#ifndef NDEBUG
+ // Make sure we only run this on one thread. GTK only has one message pump
+ // so we can only have one UI loop per process.
+ static PlatformThreadId thread_id = PlatformThread::CurrentId();
+ DCHECK(thread_id == PlatformThread::CurrentId())
+ << "Running MessagePumpForUI on two different threads; "
+ "this is unsupported by GLib!";
+#endif
+
+ RunState state;
+ state.delegate = delegate;
+ state.should_quit = false;
+ state.run_depth = state_ ? state_->run_depth + 1 : 1;
+ state.has_work = false;
+
+ RunState* previous_state = state_;
+ state_ = &state;
+
+ // We really only do a single task for each iteration of the loop. If we
+ // have done something, assume there is likely something more to do. This
+ // will mean that we don't block on the message pump until there was nothing
+ // more to do. We also set this to true to make sure not to block on the
+ // first iteration of the loop, so RunAllPending() works correctly.
+ bool more_work_is_plausible = true;
+
+ // We run our own loop instead of using g_main_loop_quit in one of the
+ // callbacks. This is so we only quit our own loops, and we don't quit
+ // nested loops run by others. TODO(deanm): Is this what we want?
+ for (;;) {
+ // Don't block if we think we have more work to do.
+ bool block = !more_work_is_plausible;
+
+ // g_main_context_iteration returns true if events have been dispatched.
+ more_work_is_plausible = g_main_context_iteration(context_, block);
+ if (state_->should_quit) break;
+
+ more_work_is_plausible |= state_->delegate->DoWork();
+ if (state_->should_quit) break;
+
+ more_work_is_plausible |=
+ state_->delegate->DoDelayedWork(&delayed_work_time_);
+ if (state_->should_quit) break;
+
+ if (more_work_is_plausible) continue;
+
+ more_work_is_plausible = state_->delegate->DoIdleWork();
+ if (state_->should_quit) break;
+ }
+
+ state_ = previous_state;
+}
+
+// Return the timeout we want passed to poll.
+int MessagePumpForUI::HandlePrepare() {
+ // We know we have work, but we haven't called HandleDispatch yet. Don't let
+ // the pump block so that we can do some processing.
+ if (state_ && // state_ may be null during tests.
+ state_->has_work)
+ return 0;
+
+ // We don't think we have work to do, but make sure not to block
+ // longer than the next time we need to run delayed work.
+ return GetTimeIntervalMilliseconds(delayed_work_time_);
+}
+
+bool MessagePumpForUI::HandleCheck() {
+ if (!state_) // state_ may be null during tests.
+ return false;
+
+ // We should only ever have a single message on the wakeup pipe since we only
+ // write to the pipe when pipe_full_ is false. The glib poll will tell us
+ // whether there was data, so this read shouldn't block.
+ if (wakeup_gpollfd_->revents & G_IO_IN) {
+ pipe_full_ = false;
+
+ char msg;
+ if (HANDLE_EINTR(read(wakeup_pipe_read_, &msg, 1)) != 1 || msg != '!') {
+ NOTREACHED() << "Error reading from the wakeup pipe.";
+ }
+ // Since we ate the message, we need to record that we have more work,
+ // because HandleCheck() may be called without HandleDispatch being called
+ // afterwards.
+ state_->has_work = true;
+ }
+
+ if (state_->has_work) return true;
+
+ if (GetTimeIntervalMilliseconds(delayed_work_time_) == 0) {
+ // The timer has expired. That condition will stay true until we process
+ // that delayed work, so we don't need to record this differently.
+ return true;
+ }
+
+ return false;
+}
+
+void MessagePumpForUI::HandleDispatch() {
+ state_->has_work = false;
+ if (state_->delegate->DoWork()) {
+ // NOTE: on Windows at this point we would call ScheduleWork (see
+ // MessagePumpForUI::HandleWorkMessage in message_pump_win.cc). But here,
+ // instead of posting a message on the wakeup pipe, we can avoid the
+ // syscalls and just signal that we have more work.
+ state_->has_work = true;
+ }
+
+ if (state_->should_quit) return;
+
+ state_->delegate->DoDelayedWork(&delayed_work_time_);
+}
+
+void MessagePumpForUI::Quit() {
+ if (state_) {
+ state_->should_quit = true;
+ } else {
+ NOTREACHED() << "Quit called outside Run!";
+ }
+}
+
+void MessagePumpForUI::ScheduleWork() {
+ bool was_full = pipe_full_.exchange(true);
+ if (was_full) {
+ return;
+ }
+
+ // This can be called on any thread, so we don't want to touch any state
+ // variables as we would then need locks all over. This ensures that if
+ // we are sleeping in a poll that we will wake up.
+ char msg = '!';
+ if (HANDLE_EINTR(write(wakeup_pipe_write_, &msg, 1)) != 1) {
+ NOTREACHED() << "Could not write to the UI message loop wakeup pipe!";
+ }
+}
+
+void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
+ // We need to wake up the loop in case the poll timeout needs to be
+ // adjusted. This will cause us to try to do work, but that's ok.
+ delayed_work_time_ = delayed_work_time;
+ ScheduleWork();
+}
+
+} // namespace base
diff --git a/ipc/chromium/src/base/message_pump_glib.h b/ipc/chromium/src/base/message_pump_glib.h
new file mode 100644
index 0000000000..c7888b25b9
--- /dev/null
+++ b/ipc/chromium/src/base/message_pump_glib.h
@@ -0,0 +1,92 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MESSAGE_PUMP_GLIB_H_
+#define BASE_MESSAGE_PUMP_GLIB_H_
+
+#include "base/message_pump.h"
+#include "base/observer_list.h"
+#include "base/time.h"
+#include "mozilla/UniquePtr.h"
+#include "mozilla/Atomics.h"
+
+typedef struct _GMainContext GMainContext;
+typedef struct _GPollFD GPollFD;
+typedef struct _GSource GSource;
+
+namespace base {
+
+// This class implements a MessagePump needed for TYPE_UI MessageLoops on
+// XP_LINUX platforms using GLib.
+class MessagePumpForUI : public MessagePump {
+ public:
+ MessagePumpForUI();
+ virtual ~MessagePumpForUI();
+
+ void Run(Delegate* delegate) override;
+ void Quit() override;
+ void ScheduleWork() override;
+ void ScheduleDelayedWork(const TimeTicks& delayed_work_time) override;
+
+ // Internal methods used for processing the pump callbacks. They are
+ // public for simplicity but should not be used directly. HandlePrepare
+ // is called during the prepare step of glib, and returns a timeout that
+ // will be passed to the poll. HandleCheck is called after the poll
+ // has completed, and returns whether or not HandleDispatch should be called.
+ // HandleDispatch is called if HandleCheck returned true.
+ int HandlePrepare();
+ bool HandleCheck();
+ void HandleDispatch();
+
+ private:
+ // We may make recursive calls to Run, so we save state that needs to be
+ // separate between them in this structure type.
+ struct RunState {
+ Delegate* delegate;
+
+ // Used to flag that the current Run() invocation should return ASAP.
+ bool should_quit;
+
+ // Used to count how many Run() invocations are on the stack.
+ int run_depth;
+
+ // This keeps the state of whether the pump got signaled that there was new
+ // work to be done. Since we eat the message on the wake up pipe as soon as
+ // we get it, we keep that state here to stay consistent.
+ bool has_work;
+ };
+
+ RunState* state_;
+
+ // This is a GLib structure that we can add event sources to. We use the
+ // default GLib context, which is the one to which all GTK events are
+ // dispatched.
+ GMainContext* context_;
+
+ // This is the time when we need to do delayed work.
+ TimeTicks delayed_work_time_;
+
+ // The work source. It is shared by all calls to Run and destroyed when
+ // the message pump is destroyed.
+ GSource* work_source_;
+
+ // We use a wakeup pipe to make sure we'll get out of the glib polling phase
+ // when another thread has scheduled us to do some work. There is a glib
+ // mechanism g_main_context_wakeup, but this won't guarantee that our event's
+ // Dispatch() will be called.
+ int wakeup_pipe_read_;
+ int wakeup_pipe_write_;
+ // Use an autoptr to avoid needing the definition of GPollFD in the header.
+ mozilla::UniquePtr<GPollFD> wakeup_gpollfd_;
+
+ mozilla::Atomic<bool> pipe_full_;
+
+ DISALLOW_COPY_AND_ASSIGN(MessagePumpForUI);
+};
+
+} // namespace base
+
+#endif // BASE_MESSAGE_PUMP_GLIB_H_
diff --git a/ipc/chromium/src/base/message_pump_libevent.cc b/ipc/chromium/src/base/message_pump_libevent.cc
new file mode 100644
index 0000000000..004001fddd
--- /dev/null
+++ b/ipc/chromium/src/base/message_pump_libevent.cc
@@ -0,0 +1,410 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_pump_libevent.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#if defined(ANDROID) || defined(XP_UNIX)
+# include <unistd.h>
+#endif
+
+#include "eintr_wrapper.h"
+#include "base/logging.h"
+#include "base/scoped_nsautorelease_pool.h"
+#include "base/time.h"
+#include "event.h"
+#include "mozilla/ProfilerLabels.h"
+#include "mozilla/ProfilerThreadSleep.h"
+#include "mozilla/UniquePtr.h"
+
+// This macro checks that the _EVENT_SIZEOF_* constants defined in
+// ipc/chromiume/src/third_party/<platform>/event2/event-config.h are correct.
+#if defined(_EVENT_SIZEOF_SHORT)
+# define CHECK_EVENT_SIZEOF(TYPE, type) \
+ static_assert(_EVENT_SIZEOF_##TYPE == sizeof(type), \
+ "bad _EVENT_SIZEOF_" #TYPE);
+#elif defined(EVENT__SIZEOF_SHORT)
+# define CHECK_EVENT_SIZEOF(TYPE, type) \
+ static_assert(EVENT__SIZEOF_##TYPE == sizeof(type), \
+ "bad EVENT__SIZEOF_" #TYPE);
+#else
+# error Cannot find libevent type sizes
+#endif
+
+CHECK_EVENT_SIZEOF(LONG, long);
+CHECK_EVENT_SIZEOF(LONG_LONG, long long);
+CHECK_EVENT_SIZEOF(OFF_T, ev_off_t);
+CHECK_EVENT_SIZEOF(PTHREAD_T, pthread_t);
+CHECK_EVENT_SIZEOF(SHORT, short);
+CHECK_EVENT_SIZEOF(SIZE_T, size_t);
+CHECK_EVENT_SIZEOF(TIME_T, time_t);
+CHECK_EVENT_SIZEOF(VOID_P, void*);
+
+// Lifecycle of struct event
+// Libevent uses two main data structures:
+// struct event_base (of which there is one per message pump), and
+// struct event (of which there is roughly one per socket).
+// The socket's struct event is created in
+// MessagePumpLibevent::WatchFileDescriptor(),
+// is owned by the FileDescriptorWatcher, and is destroyed in
+// StopWatchingFileDescriptor().
+// It is moved into and out of lists in struct event_base by
+// the libevent functions event_add() and event_del().
+//
+// TODO(dkegel):
+// At the moment bad things happen if a FileDescriptorWatcher
+// is active after its MessagePumpLibevent has been destroyed.
+// See MessageLoopTest.FileDescriptorWatcherOutlivesMessageLoop
+// Not clear yet whether that situation occurs in practice,
+// but if it does, we need to fix it.
+
+namespace base {
+
+// Return 0 on success
+// Too small a function to bother putting in a library?
+static int SetNonBlocking(int fd) {
+ int flags = fcntl(fd, F_GETFL, 0);
+ if (flags == -1) flags = 0;
+ return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+}
+
+MessagePumpLibevent::FileDescriptorWatcher::FileDescriptorWatcher()
+ : is_persistent_(false), event_(NULL) {}
+
+MessagePumpLibevent::FileDescriptorWatcher::~FileDescriptorWatcher() {
+ if (event_) {
+ StopWatchingFileDescriptor();
+ }
+}
+
+void MessagePumpLibevent::FileDescriptorWatcher::Init(event* e,
+ bool is_persistent) {
+ DCHECK(e);
+ DCHECK(event_ == NULL);
+
+ is_persistent_ = is_persistent;
+ event_ = e;
+}
+
+event* MessagePumpLibevent::FileDescriptorWatcher::ReleaseEvent() {
+ struct event* e = event_;
+ event_ = NULL;
+ return e;
+}
+
+bool MessagePumpLibevent::FileDescriptorWatcher::StopWatchingFileDescriptor() {
+ event* e = ReleaseEvent();
+ if (e == NULL) return true;
+
+ // event_del() is a no-op if the event isn't active.
+ int rv = event_del(e);
+ delete e;
+ return (rv == 0);
+}
+
+bool MessagePumpLibevent::awake_ = false;
+
+// Called if a byte is received on the wakeup pipe.
+void MessagePumpLibevent::OnWakeup(int socket, short flags, void* context) {
+ if (!awake_) {
+ profiler_thread_wake();
+ awake_ = true;
+ }
+
+ AUTO_PROFILER_LABEL("MessagePumpLibevent::OnWakeup", OTHER);
+
+ base::MessagePumpLibevent* that =
+ static_cast<base::MessagePumpLibevent*>(context);
+ DCHECK(that->wakeup_pipe_out_ == socket);
+
+ // Remove and discard the wakeup byte.
+ char buf;
+ int nread = HANDLE_EINTR(read(socket, &buf, 1));
+ DCHECK_EQ(nread, 1);
+ // Tell libevent to break out of inner loop.
+ event_base_loopbreak(that->event_base_);
+}
+
+MessagePumpLibevent::MessagePumpLibevent()
+ : keep_running_(true),
+ in_run_(false),
+ event_base_(event_base_new()),
+ wakeup_pipe_in_(-1),
+ wakeup_pipe_out_(-1) {
+ if (!Init()) NOTREACHED();
+}
+
+bool MessagePumpLibevent::Init() {
+ int fds[2];
+ if (pipe(fds)) {
+ DLOG(ERROR) << "pipe() failed, errno: " << errno;
+ return false;
+ }
+ if (SetNonBlocking(fds[0])) {
+ DLOG(ERROR) << "SetNonBlocking for pipe fd[0] failed, errno: " << errno;
+ return false;
+ }
+ if (SetNonBlocking(fds[1])) {
+ DLOG(ERROR) << "SetNonBlocking for pipe fd[1] failed, errno: " << errno;
+ return false;
+ }
+ wakeup_pipe_out_ = fds[0];
+ wakeup_pipe_in_ = fds[1];
+
+ wakeup_event_ = new event;
+ event_set(wakeup_event_, wakeup_pipe_out_, EV_READ | EV_PERSIST, OnWakeup,
+ this);
+ event_base_set(event_base_, wakeup_event_);
+
+ if (event_add(wakeup_event_, 0)) return false;
+ return true;
+}
+
+MessagePumpLibevent::~MessagePumpLibevent() {
+ DCHECK(wakeup_event_);
+ DCHECK(event_base_);
+ event_del(wakeup_event_);
+ delete wakeup_event_;
+ if (wakeup_pipe_in_ >= 0) close(wakeup_pipe_in_);
+ if (wakeup_pipe_out_ >= 0) close(wakeup_pipe_out_);
+ event_base_free(event_base_);
+}
+
+bool MessagePumpLibevent::WatchFileDescriptor(int fd, bool persistent,
+ Mode mode,
+ FileDescriptorWatcher* controller,
+ Watcher* delegate) {
+ DCHECK(fd > 0);
+ DCHECK(controller);
+ DCHECK(delegate);
+ DCHECK(mode == WATCH_READ || mode == WATCH_WRITE || mode == WATCH_READ_WRITE);
+
+ int event_mask = persistent ? EV_PERSIST : 0;
+ if ((mode & WATCH_READ) != 0) {
+ event_mask |= EV_READ;
+ }
+ if ((mode & WATCH_WRITE) != 0) {
+ event_mask |= EV_WRITE;
+ }
+
+ // |should_delete_event| is true if we're modifying an event that's currently
+ // active in |controller|.
+ // If we're modifying an existing event and there's an error then we need to
+ // tell libevent to clean it up via event_delete() before returning.
+ bool should_delete_event = true;
+ mozilla::UniquePtr<event> evt(controller->ReleaseEvent());
+ if (evt.get() == NULL) {
+ should_delete_event = false;
+ // Ownership is transferred to the controller.
+ evt = mozilla::MakeUnique<event>();
+ } else {
+ // It's illegal to use this function to listen on 2 separate fds with the
+ // same |controller|.
+ if (EVENT_FD(evt.get()) != fd) {
+ NOTREACHED() << "FDs don't match" << EVENT_FD(evt.get()) << "!=" << fd;
+ return false;
+ }
+
+ // Make sure we don't pick up any funky internal libevent masks.
+ int old_interest_mask =
+ evt.get()->ev_events & (EV_READ | EV_WRITE | EV_PERSIST);
+
+ // Combine old/new event masks.
+ event_mask |= old_interest_mask;
+
+ // Must disarm the event before we can reuse it.
+ event_del(evt.get());
+ }
+
+ // Set current interest mask and message pump for this event.
+ event_set(evt.get(), fd, event_mask, OnLibeventNotification, delegate);
+
+ // Tell libevent which message pump this socket will belong to when we add it.
+ if (event_base_set(event_base_, evt.get()) != 0) {
+ if (should_delete_event) {
+ event_del(evt.get());
+ }
+ return false;
+ }
+
+ // Add this socket to the list of monitored sockets.
+ if (event_add(evt.get(), NULL) != 0) {
+ if (should_delete_event) {
+ event_del(evt.get());
+ }
+ return false;
+ }
+
+ // Transfer ownership of evt to controller.
+ controller->Init(evt.release(), persistent);
+ return true;
+}
+
+void MessagePumpLibevent::OnLibeventNotification(int fd, short flags,
+ void* context) {
+ if (!awake_) {
+ profiler_thread_wake();
+ awake_ = true;
+ }
+ AUTO_PROFILER_LABEL("MessagePumpLibevent::OnLibeventNotification", OTHER);
+
+ Watcher* watcher = static_cast<Watcher*>(context);
+
+ if (flags & EV_WRITE) {
+ watcher->OnFileCanWriteWithoutBlocking(fd);
+ }
+ if (flags & EV_READ) {
+ watcher->OnFileCanReadWithoutBlocking(fd);
+ }
+}
+
+MessagePumpLibevent::SignalEvent::SignalEvent() : event_(NULL) {}
+
+MessagePumpLibevent::SignalEvent::~SignalEvent() {
+ if (event_) {
+ StopCatching();
+ }
+}
+
+void MessagePumpLibevent::SignalEvent::Init(event* e) {
+ DCHECK(e);
+ DCHECK(event_ == NULL);
+ event_ = e;
+}
+
+bool MessagePumpLibevent::SignalEvent::StopCatching() {
+ // XXX/cjones: this code could be shared with
+ // FileDescriptorWatcher. ironic that libevent is "more"
+ // object-oriented than this C++
+ event* e = ReleaseEvent();
+ if (e == NULL) return true;
+
+ // event_del() is a no-op if the event isn't active.
+ int rv = event_del(e);
+ delete e;
+ return (rv == 0);
+}
+
+event* MessagePumpLibevent::SignalEvent::ReleaseEvent() {
+ event* e = event_;
+ event_ = NULL;
+ return e;
+}
+
+bool MessagePumpLibevent::CatchSignal(int sig, SignalEvent* sigevent,
+ SignalWatcher* delegate) {
+ DCHECK(sig > 0);
+ DCHECK(sigevent);
+ DCHECK(delegate);
+ // TODO if we want to support re-using SignalEvents, this code needs
+ // to jump through the same hoops as WatchFileDescriptor(). Not
+ // needed at present
+ DCHECK(NULL == sigevent->event_);
+
+ mozilla::UniquePtr<event> evt = mozilla::MakeUnique<event>();
+ signal_set(evt.get(), sig, OnLibeventSignalNotification, delegate);
+
+ if (event_base_set(event_base_, evt.get())) return false;
+
+ if (signal_add(evt.get(), NULL)) return false;
+
+ // Transfer ownership of evt to controller.
+ sigevent->Init(evt.release());
+ return true;
+}
+
+void MessagePumpLibevent::OnLibeventSignalNotification(int sig, short flags,
+ void* context) {
+ if (!awake_) {
+ profiler_thread_wake();
+ awake_ = true;
+ }
+ AUTO_PROFILER_LABEL("MessagePumpLibevent::OnLibeventSignalNotification",
+ OTHER);
+
+ DCHECK(sig > 0);
+ DCHECK(EV_SIGNAL == flags);
+ DCHECK(context);
+ reinterpret_cast<SignalWatcher*>(context)->OnSignal(sig);
+}
+
+// Reentrant!
+void MessagePumpLibevent::Run(Delegate* delegate) {
+ DCHECK(keep_running_) << "Quit must have been called outside of Run!";
+
+ bool old_in_run = in_run_;
+ in_run_ = true;
+
+ for (;;) {
+ ScopedNSAutoreleasePool autorelease_pool;
+
+ bool did_work = delegate->DoWork();
+ if (!keep_running_) break;
+
+ did_work |= delegate->DoDelayedWork(&delayed_work_time_);
+ if (!keep_running_) break;
+
+ if (did_work) continue;
+
+ did_work = delegate->DoIdleWork();
+ if (!keep_running_) break;
+
+ if (did_work) continue;
+
+ // EVLOOP_ONCE tells libevent to only block once,
+ // but to service all pending events when it wakes up.
+ AUTO_PROFILER_LABEL("MessagePumpLibevent::Run::Wait", IDLE);
+ if (delayed_work_time_.is_null()) {
+ profiler_thread_sleep();
+ awake_ = false;
+ event_base_loop(event_base_, EVLOOP_ONCE);
+ } else {
+ TimeDelta delay = delayed_work_time_ - TimeTicks::Now();
+ if (delay > TimeDelta()) {
+ struct timeval poll_tv;
+ poll_tv.tv_sec = delay.InSeconds();
+ poll_tv.tv_usec = delay.InMicroseconds() % Time::kMicrosecondsPerSecond;
+ event_base_loopexit(event_base_, &poll_tv);
+ profiler_thread_sleep();
+ awake_ = false;
+ event_base_loop(event_base_, EVLOOP_ONCE);
+ } else {
+ // It looks like delayed_work_time_ indicates a time in the past, so we
+ // need to call DoDelayedWork now.
+ delayed_work_time_ = TimeTicks();
+ }
+ }
+ }
+
+ keep_running_ = true;
+ in_run_ = old_in_run;
+}
+
+void MessagePumpLibevent::Quit() {
+ DCHECK(in_run_);
+ // Tell both libevent and Run that they should break out of their loops.
+ keep_running_ = false;
+ ScheduleWork();
+}
+
+void MessagePumpLibevent::ScheduleWork() {
+ // Tell libevent (in a threadsafe way) that it should break out of its loop.
+ char buf = 0;
+ int nwrite = HANDLE_EINTR(write(wakeup_pipe_in_, &buf, 1));
+ DCHECK(nwrite == 1 || errno == EAGAIN)
+ << "[nwrite:" << nwrite << "] [errno:" << errno << "]";
+}
+
+void MessagePumpLibevent::ScheduleDelayedWork(
+ const TimeTicks& delayed_work_time) {
+ // We know that we can't be blocked on Wait right now since this method can
+ // only be called on the same thread as Run, so we only need to update our
+ // record of how long to sleep when we do sleep.
+ delayed_work_time_ = delayed_work_time;
+}
+
+} // namespace base
diff --git a/ipc/chromium/src/base/message_pump_libevent.h b/ipc/chromium/src/base/message_pump_libevent.h
new file mode 100644
index 0000000000..b1a7d474b3
--- /dev/null
+++ b/ipc/chromium/src/base/message_pump_libevent.h
@@ -0,0 +1,181 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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_MESSAGE_PUMP_LIBEVENT_H_
+#define BASE_MESSAGE_PUMP_LIBEVENT_H_
+
+#include "base/message_pump.h"
+#include "base/time.h"
+
+// Declare structs we need from libevent.h rather than including it
+struct event_base;
+struct event;
+
+namespace base {
+
+// Class to monitor sockets and issue callbacks when sockets are ready for I/O
+// TODO(dkegel): add support for background file IO somehow
+class MessagePumpLibevent : public MessagePump {
+ public:
+ // Object returned by WatchFileDescriptor to manage further watching.
+ class FileDescriptorWatcher {
+ public:
+ FileDescriptorWatcher();
+ ~FileDescriptorWatcher(); // Implicitly calls StopWatchingFileDescriptor.
+
+ // NOTE: These methods aren't called StartWatching()/StopWatching() to
+ // avoid confusion with the win32 ObjectWatcher class.
+
+ // Stop watching the FD, always safe to call. No-op if there's nothing
+ // to do.
+ bool StopWatchingFileDescriptor();
+
+ private:
+ // Called by MessagePumpLibevent, ownership of |e| is transferred to this
+ // object.
+ void Init(event* e, bool is_persistent);
+
+ // Used by MessagePumpLibevent to take ownership of event_.
+ event* ReleaseEvent();
+ friend class MessagePumpLibevent;
+
+ private:
+ bool is_persistent_; // false if this event is one-shot.
+ event* event_;
+ DISALLOW_COPY_AND_ASSIGN(FileDescriptorWatcher);
+ };
+
+ // Used with WatchFileDescptor to asynchronously monitor the I/O readiness of
+ // a File Descriptor.
+ class Watcher {
+ public:
+ virtual ~Watcher() {}
+ // Called from MessageLoop::Run when an FD can be read from/written to
+ // without blocking
+ virtual void OnFileCanReadWithoutBlocking(int fd) = 0;
+ virtual void OnFileCanWriteWithoutBlocking(int fd) = 0;
+ };
+
+ MessagePumpLibevent();
+
+ enum Mode {
+ WATCH_READ = 1 << 0,
+ WATCH_WRITE = 1 << 1,
+ WATCH_READ_WRITE = WATCH_READ | WATCH_WRITE
+ };
+
+ // Have the current thread's message loop watch for a a situation in which
+ // reading/writing to the FD can be performed without Blocking.
+ // Callers must provide a preallocated FileDescriptorWatcher object which
+ // can later be used to manage the Lifetime of this event.
+ // If a FileDescriptorWatcher is passed in which is already attached to
+ // an event, then the effect is cumulative i.e. after the call |controller|
+ // will watch both the previous event and the new one.
+ // If an error occurs while calling this method in a cumulative fashion, the
+ // event previously attached to |controller| is aborted.
+ // Returns true on success.
+ // TODO(dkegel): switch to edge-triggered readiness notification
+ bool WatchFileDescriptor(int fd, bool persistent, Mode mode,
+ FileDescriptorWatcher* controller,
+ Watcher* delegate);
+
+ // This is analagous to FileDescriptorWatcher above, which really is
+ // just a wrapper around libevent's |struct event|. This class acts
+ // as a sort of "scoped event watcher" in that it guarantees that
+ // when this class is out of scope, the signal-event it wraps is
+ // removed from libevent's guts.
+ //
+ // XXX/cjones: this isn't my favorite API, but preserving it in
+ // order to match code above
+ class SignalEvent {
+ friend class MessagePumpLibevent;
+
+ public:
+ SignalEvent();
+ ~SignalEvent(); // implicitly calls StopCatching()
+
+ // Have libevent forget this event.
+ bool StopCatching();
+
+ private:
+ void Init(event* e);
+ event* ReleaseEvent();
+
+ event* event_;
+
+ DISALLOW_COPY_AND_ASSIGN(SignalEvent);
+ };
+
+ class SignalWatcher {
+ public:
+ virtual ~SignalWatcher() {}
+ // Called from MessageLoop::Run when |sig| has been delivered to
+ // this process
+ virtual void OnSignal(int sig) = 0;
+ };
+
+ // Have the current thread's message loop catch the signal |sig|.
+ // Multiple watchers can catch the same signal; they're all notified
+ // upon its delivery. Callers must provide a preallocated
+ // SignalEvent object which can be used to manage the lifetime of
+ // this event. Returns true on success.
+ bool CatchSignal(int sig, SignalEvent* sigevent, SignalWatcher* delegate);
+
+ // MessagePump methods:
+ virtual void Run(Delegate* delegate) override;
+ virtual void Quit() override;
+ virtual void ScheduleWork() override;
+ virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) override;
+
+ protected:
+ virtual ~MessagePumpLibevent();
+
+ private:
+ // Risky part of constructor. Returns true on success.
+ bool Init();
+
+ // This flag is set to false when Run should return.
+ bool keep_running_;
+
+ // This flag is set when inside Run.
+ bool in_run_;
+
+ // The time at which we should call DoDelayedWork.
+ TimeTicks delayed_work_time_;
+
+ // Libevent dispatcher. Watches all sockets registered with it, and sends
+ // readiness callbacks when a socket is ready for I/O.
+ event_base* event_base_;
+
+ // Called by libevent to tell us a registered FD can be read/written to.
+ static void OnLibeventNotification(int fd, short flags, void* context);
+
+ // Called by libevent upon receiving a signal
+ static void OnLibeventSignalNotification(int sig, short flags, void* context);
+
+ // Unix pipe used to implement ScheduleWork()
+ // ... callback; called by libevent inside Run() when pipe is ready to read
+ static void OnWakeup(int socket, short flags, void* context);
+ // ... write end; ScheduleWork() writes a single byte to it
+ int wakeup_pipe_in_;
+ // ... read end; OnWakeup reads it and then breaks Run() out of its sleep
+ int wakeup_pipe_out_;
+ // ... libevent wrapper for read end
+ event* wakeup_event_;
+
+ // Set to false when calling event_base_loop and to true when either of the
+ // OnWakeup, OnLibeventNotification or OnLibeventSignalNotification callbacks
+ // is called.
+ // Used to ensure our calls to profiler_thread_sleep and profiler_thread_wake
+ // are paired correctly.
+ static bool awake_;
+
+ DISALLOW_COPY_AND_ASSIGN(MessagePumpLibevent);
+};
+
+} // namespace base
+
+#endif // BASE_MESSAGE_PUMP_LIBEVENT_H_
diff --git a/ipc/chromium/src/base/message_pump_mac.h b/ipc/chromium/src/base/message_pump_mac.h
new file mode 100644
index 0000000000..13902bbf3e
--- /dev/null
+++ b/ipc/chromium/src/base/message_pump_mac.h
@@ -0,0 +1,280 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// The basis for all native run loops on the Mac is the CFRunLoop. It can be
+// used directly, it can be used as the driving force behind the similar
+// Foundation NSRunLoop, and it can be used to implement higher-level event
+// loops such as the NSApplication event loop.
+//
+// This file introduces a basic CFRunLoop-based implementation of the
+// MessagePump interface called CFRunLoopBase. CFRunLoopBase contains all
+// of the machinery necessary to dispatch events to a delegate, but does not
+// implement the specific run loop. Concrete subclasses must provide their
+// own DoRun and Quit implementations.
+//
+// A concrete subclass that just runs a CFRunLoop loop is provided in
+// MessagePumpCFRunLoop. For an NSRunLoop, the similar MessagePumpNSRunLoop
+// is provided.
+//
+// For the application's event loop, an implementation based on AppKit's
+// NSApplication event system is provided in MessagePumpNSApplication.
+//
+// Typically, MessagePumpNSApplication only makes sense on a Cocoa
+// application's main thread. If a CFRunLoop-based message pump is needed on
+// any other thread, one of the other concrete subclasses is preferrable.
+// MessagePumpMac::Create is defined, which returns a new NSApplication-based
+// or NSRunLoop-based MessagePump subclass depending on which thread it is
+// called on.
+
+#ifndef BASE_MESSAGE_PUMP_MAC_H_
+#define BASE_MESSAGE_PUMP_MAC_H_
+
+#include "base/message_pump.h"
+
+#include "base/basictypes.h"
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <IOKit/IOKitLib.h>
+
+#if defined(__OBJC__)
+@class NSAutoreleasePool;
+#else // defined(__OBJC__)
+class NSAutoreleasePool;
+#endif // defined(__OBJC__)
+
+namespace base {
+
+class TimeTicks;
+
+class MessagePumpCFRunLoopBase : public MessagePump {
+ // Needs access to CreateAutoreleasePool.
+ friend class MessagePumpScopedAutoreleasePool;
+
+ public:
+ MessagePumpCFRunLoopBase();
+ virtual ~MessagePumpCFRunLoopBase();
+
+ // Subclasses should implement the work they need to do in MessagePump::Run
+ // in the DoRun method. MessagePumpCFRunLoopBase::Run calls DoRun directly.
+ // This arrangement is used because MessagePumpCFRunLoopBase needs to set
+ // up and tear down things before and after the "meat" of DoRun.
+ virtual void Run(Delegate* delegate);
+ virtual void DoRun(Delegate* delegate) = 0;
+
+ virtual void ScheduleWork();
+ virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time);
+
+ protected:
+ // Accessors for private data members to be used by subclasses.
+ CFRunLoopRef run_loop() const { return run_loop_; }
+ int nesting_level() const { return nesting_level_; }
+ int run_nesting_level() const { return run_nesting_level_; }
+
+ // Return an autorelease pool to wrap around any work being performed.
+ // In some cases, CreateAutoreleasePool may return nil intentionally to
+ // preventing an autorelease pool from being created, allowing any
+ // objects autoreleased by work to fall into the current autorelease pool.
+ virtual NSAutoreleasePool* CreateAutoreleasePool();
+
+ private:
+ // Timer callback scheduled by ScheduleDelayedWork. This does not do any
+ // work, but it signals delayed_work_source_ so that delayed work can be
+ // performed within the appropriate priority constraints.
+ static void RunDelayedWorkTimer(CFRunLoopTimerRef timer, void* info);
+
+ // Perform highest-priority work. This is associated with work_source_
+ // signalled by ScheduleWork. The static method calls the instance method;
+ // the instance method returns true if work was done.
+ static void RunWorkSource(void* info);
+ bool RunWork();
+
+ // Perform delayed-priority work. This is associated with
+ // delayed_work_source_ signalled by RunDelayedWorkTimer, and is responsible
+ // for calling ScheduleDelayedWork again if appropriate. The static method
+ // calls the instance method; the instance method returns true if more
+ // delayed work is available.
+ static void RunDelayedWorkSource(void* info);
+ bool RunDelayedWork();
+
+ // Perform idle-priority work. This is normally called by PreWaitObserver,
+ // but is also associated with idle_work_source_. When this function
+ // actually does perform idle work, it will resignal that source. The
+ // static method calls the instance method; the instance method returns
+ // true if idle work was done.
+ static void RunIdleWorkSource(void* info);
+ bool RunIdleWork();
+
+ // Perform work that may have been deferred because it was not runnable
+ // within a nested run loop. This is associated with
+ // nesting_deferred_work_source_ and is signalled by
+ // MaybeScheduleNestingDeferredWork when returning from a nested loop,
+ // so that an outer loop will be able to perform the necessary tasks if it
+ // permits nestable tasks.
+ static void RunNestingDeferredWorkSource(void* info);
+ bool RunNestingDeferredWork();
+
+ // Schedules possible nesting-deferred work to be processed before the run
+ // loop goes to sleep, exits, or begins processing sources at the top of its
+ // loop. If this function detects that a nested loop had run since the
+ // previous attempt to schedule nesting-deferred work, it will schedule a
+ // call to RunNestingDeferredWorkSource.
+ void MaybeScheduleNestingDeferredWork();
+
+ // Observer callback responsible for performing idle-priority work, before
+ // the run loop goes to sleep. Associated with idle_work_observer_.
+ static void PreWaitObserver(CFRunLoopObserverRef observer,
+ CFRunLoopActivity activity, void* info);
+
+ // Observer callback called before the run loop processes any sources.
+ // Associated with pre_source_observer_.
+ static void PreSourceObserver(CFRunLoopObserverRef observer,
+ CFRunLoopActivity activity, void* info);
+
+ // Observer callback called when the run loop starts and stops, at the
+ // beginning and end of calls to CFRunLoopRun. This is used to maintain
+ // nesting_level_. Associated with enter_exit_observer_.
+ static void EnterExitObserver(CFRunLoopObserverRef observer,
+ CFRunLoopActivity activity, void* info);
+
+ // Called by EnterExitObserver after performing maintenance on nesting_level_.
+ // This allows subclasses an opportunity to perform additional processing on
+ // the basis of run loops starting and stopping.
+ virtual void EnterExitRunLoop(CFRunLoopActivity activity);
+
+ // IOKit power state change notification callback, called when the system
+ // enters and leaves the sleep state.
+ static void PowerStateNotification(void* info, io_service_t service,
+ uint32_t message_type,
+ void* message_argument);
+
+ // The thread's run loop.
+ CFRunLoopRef run_loop_;
+
+ // The timer, sources, and observers are described above alongside their
+ // callbacks.
+ CFRunLoopTimerRef delayed_work_timer_;
+ CFRunLoopSourceRef work_source_;
+ CFRunLoopSourceRef delayed_work_source_;
+ CFRunLoopSourceRef idle_work_source_;
+ CFRunLoopSourceRef nesting_deferred_work_source_;
+ CFRunLoopObserverRef pre_wait_observer_;
+ CFRunLoopObserverRef pre_source_observer_;
+ CFRunLoopObserverRef enter_exit_observer_;
+
+ // Objects used for power state notification. See PowerStateNotification.
+ io_connect_t root_power_domain_;
+ IONotificationPortRef power_notification_port_;
+ io_object_t power_notification_object_;
+
+ // (weak) Delegate passed as an argument to the innermost Run call.
+ Delegate* delegate_;
+
+ // The time that delayed_work_timer_ is scheduled to fire. This is tracked
+ // independently of CFRunLoopTimerGetNextFireDate(delayed_work_timer_)
+ // to be able to reset the timer properly after waking from system sleep.
+ // See PowerStateNotification.
+ CFAbsoluteTime delayed_work_fire_time_;
+
+ // The recursion depth of the currently-executing CFRunLoopRun loop on the
+ // run loop's thread. 0 if no run loops are running inside of whatever scope
+ // the object was created in.
+ int nesting_level_;
+
+ // The recursion depth (calculated in the same way as nesting_level_) of the
+ // innermost executing CFRunLoopRun loop started by a call to Run.
+ int run_nesting_level_;
+
+ // The deepest (numerically highest) recursion depth encountered since the
+ // most recent attempt to run nesting-deferred work.
+ int deepest_nesting_level_;
+
+ // "Delegateless" work flags are set when work is ready to be performed but
+ // must wait until a delegate is available to process it. This can happen
+ // when a MessagePumpCFRunLoopBase is instantiated and work arrives without
+ // any call to Run on the stack. The Run method will check for delegateless
+ // work on entry and redispatch it as needed once a delegate is available.
+ bool delegateless_work_;
+ bool delegateless_delayed_work_;
+ bool delegateless_idle_work_;
+
+ DISALLOW_COPY_AND_ASSIGN(MessagePumpCFRunLoopBase);
+};
+
+class MessagePumpCFRunLoop : public MessagePumpCFRunLoopBase {
+ public:
+ MessagePumpCFRunLoop();
+
+ virtual void DoRun(Delegate* delegate);
+ virtual void Quit();
+
+ private:
+ virtual void EnterExitRunLoop(CFRunLoopActivity activity);
+
+ // True if Quit is called to stop the innermost MessagePump
+ // (innermost_quittable_) but some other CFRunLoopRun loop (nesting_level_)
+ // is running inside the MessagePump's innermost Run call.
+ bool quit_pending_;
+
+ DISALLOW_COPY_AND_ASSIGN(MessagePumpCFRunLoop);
+};
+
+class MessagePumpNSRunLoop : public MessagePumpCFRunLoopBase {
+ public:
+ MessagePumpNSRunLoop();
+ virtual ~MessagePumpNSRunLoop();
+
+ virtual void DoRun(Delegate* delegate);
+ virtual void Quit();
+
+ private:
+ // A source that doesn't do anything but provide something signalable
+ // attached to the run loop. This source will be signalled when Quit
+ // is called, to cause the loop to wake up so that it can stop.
+ CFRunLoopSourceRef quit_source_;
+
+ // False after Quit is called.
+ bool keep_running_;
+
+ DISALLOW_COPY_AND_ASSIGN(MessagePumpNSRunLoop);
+};
+
+class MessagePumpNSApplication : public MessagePumpCFRunLoopBase {
+ public:
+ MessagePumpNSApplication();
+
+ virtual void DoRun(Delegate* delegate);
+ virtual void Quit();
+
+ protected:
+ // Returns nil if NSApp is currently in the middle of calling -sendEvent.
+ virtual NSAutoreleasePool* CreateAutoreleasePool();
+
+ private:
+ // False after Quit is called.
+ bool keep_running_;
+
+ // True if DoRun is managing its own run loop as opposed to letting
+ // -[NSApplication run] handle it. The outermost run loop in the application
+ // is managed by -[NSApplication run], inner run loops are handled by a loop
+ // in DoRun.
+ bool running_own_loop_;
+
+ DISALLOW_COPY_AND_ASSIGN(MessagePumpNSApplication);
+};
+
+class MessagePumpMac {
+ public:
+ // Returns a new instance of MessagePumpNSApplication if called on the main
+ // thread. Otherwise, returns a new instance of MessagePumpNSRunLoop.
+ static MessagePump* Create();
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(MessagePumpMac);
+};
+
+} // namespace base
+
+#endif // BASE_MESSAGE_PUMP_MAC_H_
diff --git a/ipc/chromium/src/base/message_pump_mac.mm b/ipc/chromium/src/base/message_pump_mac.mm
new file mode 100644
index 0000000000..1382e2a0dc
--- /dev/null
+++ b/ipc/chromium/src/base/message_pump_mac.mm
@@ -0,0 +1,735 @@
+// Copyright (c) 2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_pump_mac.h"
+
+#import <AppKit/AppKit.h>
+#import <Foundation/Foundation.h>
+#include <IOKit/IOMessage.h>
+#include <IOKit/pwr_mgt/IOPMLib.h>
+
+#include <limits>
+
+#import "base/chrome_application_mac.h"
+#include "base/logging.h"
+#include "base/time.h"
+
+namespace {
+
+void NoOp(void* info) {}
+
+const CFTimeInterval kCFTimeIntervalMax =
+ std::numeric_limits<CFTimeInterval>::max();
+
+} // namespace
+
+namespace base {
+
+// A scoper for autorelease pools created from message pump run loops.
+// Avoids dirtying up the ScopedNSAutoreleasePool interface for the rare
+// case where an autorelease pool needs to be passed in.
+class MessagePumpScopedAutoreleasePool {
+ public:
+ explicit MessagePumpScopedAutoreleasePool(MessagePumpCFRunLoopBase* pump)
+ : pool_(pump->CreateAutoreleasePool()) {}
+ ~MessagePumpScopedAutoreleasePool() { [pool_ drain]; }
+
+ private:
+ NSAutoreleasePool* pool_;
+ DISALLOW_COPY_AND_ASSIGN(MessagePumpScopedAutoreleasePool);
+};
+
+// Must be called on the run loop thread.
+MessagePumpCFRunLoopBase::MessagePumpCFRunLoopBase()
+ : delegate_(NULL),
+ delayed_work_fire_time_(kCFTimeIntervalMax),
+ nesting_level_(0),
+ run_nesting_level_(0),
+ deepest_nesting_level_(0),
+ delegateless_work_(false),
+ delegateless_delayed_work_(false),
+ delegateless_idle_work_(false) {
+ run_loop_ = CFRunLoopGetCurrent();
+ CFRetain(run_loop_);
+
+ // Set a repeating timer with a preposterous firing time and interval. The
+ // timer will effectively never fire as-is. The firing time will be adjusted
+ // as needed when ScheduleDelayedWork is called.
+ CFRunLoopTimerContext timer_context = CFRunLoopTimerContext();
+ timer_context.info = this;
+ delayed_work_timer_ =
+ CFRunLoopTimerCreate(NULL, // allocator
+ kCFTimeIntervalMax, // fire time
+ kCFTimeIntervalMax, // interval
+ 0, // flags
+ 0, // priority
+ RunDelayedWorkTimer, &timer_context);
+ CFRunLoopAddTimer(run_loop_, delayed_work_timer_, kCFRunLoopCommonModes);
+
+ CFRunLoopSourceContext source_context = CFRunLoopSourceContext();
+ source_context.info = this;
+ source_context.perform = RunWorkSource;
+ work_source_ = CFRunLoopSourceCreate(NULL, // allocator
+ 1, // priority
+ &source_context);
+ CFRunLoopAddSource(run_loop_, work_source_, kCFRunLoopCommonModes);
+
+ source_context.perform = RunDelayedWorkSource;
+ delayed_work_source_ = CFRunLoopSourceCreate(NULL, // allocator
+ 2, // priority
+ &source_context);
+ CFRunLoopAddSource(run_loop_, delayed_work_source_, kCFRunLoopCommonModes);
+
+ source_context.perform = RunIdleWorkSource;
+ idle_work_source_ = CFRunLoopSourceCreate(NULL, // allocator
+ 3, // priority
+ &source_context);
+ CFRunLoopAddSource(run_loop_, idle_work_source_, kCFRunLoopCommonModes);
+
+ source_context.perform = RunNestingDeferredWorkSource;
+ nesting_deferred_work_source_ = CFRunLoopSourceCreate(NULL, // allocator
+ 0, // priority
+ &source_context);
+ CFRunLoopAddSource(run_loop_, nesting_deferred_work_source_,
+ kCFRunLoopCommonModes);
+
+ CFRunLoopObserverContext observer_context = CFRunLoopObserverContext();
+ observer_context.info = this;
+ pre_wait_observer_ =
+ CFRunLoopObserverCreate(NULL, // allocator
+ kCFRunLoopBeforeWaiting,
+ true, // repeat
+ 0, // priority
+ PreWaitObserver, &observer_context);
+ CFRunLoopAddObserver(run_loop_, pre_wait_observer_, kCFRunLoopCommonModes);
+
+ pre_source_observer_ =
+ CFRunLoopObserverCreate(NULL, // allocator
+ kCFRunLoopBeforeSources,
+ true, // repeat
+ 0, // priority
+ PreSourceObserver, &observer_context);
+ CFRunLoopAddObserver(run_loop_, pre_source_observer_, kCFRunLoopCommonModes);
+
+ enter_exit_observer_ =
+ CFRunLoopObserverCreate(NULL, // allocator
+ kCFRunLoopEntry | kCFRunLoopExit,
+ true, // repeat
+ 0, // priority
+ EnterExitObserver, &observer_context);
+ CFRunLoopAddObserver(run_loop_, enter_exit_observer_, kCFRunLoopCommonModes);
+
+ root_power_domain_ = IORegisterForSystemPower(this, &power_notification_port_,
+ PowerStateNotification,
+ &power_notification_object_);
+ if (root_power_domain_ != MACH_PORT_NULL) {
+ CFRunLoopAddSource(
+ run_loop_, IONotificationPortGetRunLoopSource(power_notification_port_),
+ kCFRunLoopCommonModes);
+ }
+}
+
+// Ideally called on the run loop thread. If other run loops were running
+// lower on the run loop thread's stack when this object was created, the
+// same number of run loops must be running when this object is destroyed.
+MessagePumpCFRunLoopBase::~MessagePumpCFRunLoopBase() {
+ if (root_power_domain_ != MACH_PORT_NULL) {
+ CFRunLoopRemoveSource(
+ run_loop_, IONotificationPortGetRunLoopSource(power_notification_port_),
+ kCFRunLoopCommonModes);
+ IODeregisterForSystemPower(&power_notification_object_);
+ IOServiceClose(root_power_domain_);
+ IONotificationPortDestroy(power_notification_port_);
+ }
+
+ CFRunLoopRemoveObserver(run_loop_, enter_exit_observer_,
+ kCFRunLoopCommonModes);
+ CFRelease(enter_exit_observer_);
+
+ CFRunLoopRemoveObserver(run_loop_, pre_source_observer_,
+ kCFRunLoopCommonModes);
+ CFRelease(pre_source_observer_);
+
+ CFRunLoopRemoveObserver(run_loop_, pre_wait_observer_, kCFRunLoopCommonModes);
+ CFRelease(pre_wait_observer_);
+
+ CFRunLoopRemoveSource(run_loop_, nesting_deferred_work_source_,
+ kCFRunLoopCommonModes);
+ CFRelease(nesting_deferred_work_source_);
+
+ CFRunLoopRemoveSource(run_loop_, idle_work_source_, kCFRunLoopCommonModes);
+ CFRelease(idle_work_source_);
+
+ CFRunLoopRemoveSource(run_loop_, delayed_work_source_, kCFRunLoopCommonModes);
+ CFRelease(delayed_work_source_);
+
+ CFRunLoopRemoveSource(run_loop_, work_source_, kCFRunLoopCommonModes);
+ CFRelease(work_source_);
+
+ CFRunLoopRemoveTimer(run_loop_, delayed_work_timer_, kCFRunLoopCommonModes);
+ CFRelease(delayed_work_timer_);
+
+ CFRelease(run_loop_);
+}
+
+// Must be called on the run loop thread.
+void MessagePumpCFRunLoopBase::Run(Delegate* delegate) {
+ // nesting_level_ will be incremented in EnterExitRunLoop, so set
+ // run_nesting_level_ accordingly.
+ int last_run_nesting_level = run_nesting_level_;
+ run_nesting_level_ = nesting_level_ + 1;
+
+ Delegate* last_delegate = delegate_;
+ delegate_ = delegate;
+
+ if (delegate) {
+ // If any work showed up but could not be dispatched for want of a
+ // delegate, set it up for dispatch again now that a delegate is
+ // available.
+ if (delegateless_work_) {
+ CFRunLoopSourceSignal(work_source_);
+ delegateless_work_ = false;
+ }
+ if (delegateless_delayed_work_) {
+ CFRunLoopSourceSignal(delayed_work_source_);
+ delegateless_delayed_work_ = false;
+ }
+ if (delegateless_idle_work_) {
+ CFRunLoopSourceSignal(idle_work_source_);
+ delegateless_idle_work_ = false;
+ }
+ }
+
+ DoRun(delegate);
+
+ // Restore the previous state of the object.
+ delegate_ = last_delegate;
+ run_nesting_level_ = last_run_nesting_level;
+}
+
+// May be called on any thread.
+void MessagePumpCFRunLoopBase::ScheduleWork() {
+ CFRunLoopSourceSignal(work_source_);
+ CFRunLoopWakeUp(run_loop_);
+}
+
+// Must be called on the run loop thread.
+void MessagePumpCFRunLoopBase::ScheduleDelayedWork(
+ const TimeTicks& delayed_work_time) {
+ TimeDelta delta = delayed_work_time - TimeTicks::Now();
+ delayed_work_fire_time_ = CFAbsoluteTimeGetCurrent() + delta.InSecondsF();
+ CFRunLoopTimerSetNextFireDate(delayed_work_timer_, delayed_work_fire_time_);
+}
+
+// Called from the run loop.
+// static
+void MessagePumpCFRunLoopBase::RunDelayedWorkTimer(CFRunLoopTimerRef timer,
+ void* info) {
+ MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
+
+ // The timer won't fire again until it's reset.
+ self->delayed_work_fire_time_ = kCFTimeIntervalMax;
+
+ // CFRunLoopTimers fire outside of the priority scheme for CFRunLoopSources.
+ // In order to establish the proper priority where delegate_->DoDelayedWork
+ // can only be called if delegate_->DoWork returns false, the timer used
+ // to schedule delayed work must signal a CFRunLoopSource set at a lower
+ // priority than the one used for delegate_->DoWork.
+ CFRunLoopSourceSignal(self->delayed_work_source_);
+}
+
+// Called from the run loop.
+// static
+void MessagePumpCFRunLoopBase::RunWorkSource(void* info) {
+ MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
+ self->RunWork();
+}
+
+// Called by MessagePumpCFRunLoopBase::RunWorkSource.
+bool MessagePumpCFRunLoopBase::RunWork() {
+ if (!delegate_) {
+ // This point can be reached with a NULL delegate_ if Run is not on the
+ // stack but foreign code is spinning the CFRunLoop. Arrange to come back
+ // here when a delegate is available.
+ delegateless_work_ = true;
+ return false;
+ }
+
+ // The NSApplication-based run loop only drains the autorelease pool at each
+ // UI event (NSEvent). The autorelease pool is not drained for each
+ // CFRunLoopSource target that's run. Use a local pool for any autoreleased
+ // objects if the app is not currently handling a UI event to ensure they're
+ // released promptly even in the absence of UI events.
+ MessagePumpScopedAutoreleasePool autorelease_pool(this);
+
+ // Call DoWork once, and if something was done, arrange to come back here
+ // again as long as the loop is still running.
+ bool did_work = delegate_->DoWork();
+ if (did_work) {
+ CFRunLoopSourceSignal(work_source_);
+ }
+
+ return did_work;
+}
+
+// Called from the run loop.
+// static
+void MessagePumpCFRunLoopBase::RunDelayedWorkSource(void* info) {
+ MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
+ self->RunDelayedWork();
+}
+
+// Called by MessagePumpCFRunLoopBase::RunDelayedWorkSource.
+bool MessagePumpCFRunLoopBase::RunDelayedWork() {
+ if (!delegate_) {
+ // This point can be reached with a NULL delegate_ if Run is not on the
+ // stack but foreign code is spinning the CFRunLoop. Arrange to come back
+ // here when a delegate is available.
+ delegateless_delayed_work_ = true;
+ return false;
+ }
+
+ // The NSApplication-based run loop only drains the autorelease pool at each
+ // UI event (NSEvent). The autorelease pool is not drained for each
+ // CFRunLoopSource target that's run. Use a local pool for any autoreleased
+ // objects if the app is not currently handling a UI event to ensure they're
+ // released promptly even in the absence of UI events.
+ MessagePumpScopedAutoreleasePool autorelease_pool(this);
+
+ TimeTicks next_time;
+ delegate_->DoDelayedWork(&next_time);
+
+ bool more_work = !next_time.is_null();
+ if (more_work) {
+ TimeDelta delay = next_time - TimeTicks::Now();
+ if (delay > TimeDelta()) {
+ // There's more delayed work to be done in the future.
+ ScheduleDelayedWork(next_time);
+ } else {
+ // There's more delayed work to be done, and its time is in the past.
+ // Arrange to come back here directly as long as the loop is still
+ // running.
+ CFRunLoopSourceSignal(delayed_work_source_);
+ }
+ }
+
+ return more_work;
+}
+
+// Called from the run loop.
+// static
+void MessagePumpCFRunLoopBase::RunIdleWorkSource(void* info) {
+ MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
+ self->RunIdleWork();
+}
+
+// Called by MessagePumpCFRunLoopBase::RunIdleWorkSource.
+bool MessagePumpCFRunLoopBase::RunIdleWork() {
+ if (!delegate_) {
+ // This point can be reached with a NULL delegate_ if Run is not on the
+ // stack but foreign code is spinning the CFRunLoop. Arrange to come back
+ // here when a delegate is available.
+ delegateless_idle_work_ = true;
+ return false;
+ }
+
+ // The NSApplication-based run loop only drains the autorelease pool at each
+ // UI event (NSEvent). The autorelease pool is not drained for each
+ // CFRunLoopSource target that's run. Use a local pool for any autoreleased
+ // objects if the app is not currently handling a UI event to ensure they're
+ // released promptly even in the absence of UI events.
+ MessagePumpScopedAutoreleasePool autorelease_pool(this);
+
+ // Call DoIdleWork once, and if something was done, arrange to come back here
+ // again as long as the loop is still running.
+ bool did_work = delegate_->DoIdleWork();
+ if (did_work) {
+ CFRunLoopSourceSignal(idle_work_source_);
+ }
+
+ return did_work;
+}
+
+// Called from the run loop.
+// static
+void MessagePumpCFRunLoopBase::RunNestingDeferredWorkSource(void* info) {
+ MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
+ self->RunNestingDeferredWork();
+}
+
+// Called by MessagePumpCFRunLoopBase::RunNestingDeferredWorkSource.
+bool MessagePumpCFRunLoopBase::RunNestingDeferredWork() {
+ if (!delegate_) {
+ // This point can be reached with a NULL delegate_ if Run is not on the
+ // stack but foreign code is spinning the CFRunLoop. There's no sense in
+ // attempting to do any work or signalling the work sources because
+ // without a delegate, work is not possible.
+ return false;
+ }
+
+ // Immediately try work in priority order.
+ if (!RunWork()) {
+ if (!RunDelayedWork()) {
+ if (!RunIdleWork()) {
+ return false;
+ }
+ } else {
+ // There was no work, and delayed work was done. Arrange for the loop
+ // to try non-nestable idle work on a subsequent pass.
+ CFRunLoopSourceSignal(idle_work_source_);
+ }
+ } else {
+ // Work was done. Arrange for the loop to try non-nestable delayed and
+ // idle work on a subsequent pass.
+ CFRunLoopSourceSignal(delayed_work_source_);
+ CFRunLoopSourceSignal(idle_work_source_);
+ }
+
+ return true;
+}
+
+// Called before the run loop goes to sleep or exits, or processes sources.
+void MessagePumpCFRunLoopBase::MaybeScheduleNestingDeferredWork() {
+ // deepest_nesting_level_ is set as run loops are entered. If the deepest
+ // level encountered is deeper than the current level, a nested loop
+ // (relative to the current level) ran since the last time nesting-deferred
+ // work was scheduled. When that situation is encountered, schedule
+ // nesting-deferred work in case any work was deferred because nested work
+ // was disallowed.
+ if (deepest_nesting_level_ > nesting_level_) {
+ deepest_nesting_level_ = nesting_level_;
+ CFRunLoopSourceSignal(nesting_deferred_work_source_);
+ }
+}
+
+// Called from the run loop.
+// static
+void MessagePumpCFRunLoopBase::PreWaitObserver(CFRunLoopObserverRef observer,
+ CFRunLoopActivity activity,
+ void* info) {
+ MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
+
+ // Attempt to do some idle work before going to sleep.
+ self->RunIdleWork();
+
+ // The run loop is about to go to sleep. If any of the work done since it
+ // started or woke up resulted in a nested run loop running,
+ // nesting-deferred work may have accumulated. Schedule it for processing
+ // if appropriate.
+ self->MaybeScheduleNestingDeferredWork();
+}
+
+// Called from the run loop.
+// static
+void MessagePumpCFRunLoopBase::PreSourceObserver(CFRunLoopObserverRef observer,
+ CFRunLoopActivity activity,
+ void* info) {
+ MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
+
+ // The run loop has reached the top of the loop and is about to begin
+ // processing sources. If the last iteration of the loop at this nesting
+ // level did not sleep or exit, nesting-deferred work may have accumulated
+ // if a nested loop ran. Schedule nesting-deferred work for processing if
+ // appropriate.
+ self->MaybeScheduleNestingDeferredWork();
+}
+
+// Called from the run loop.
+// static
+void MessagePumpCFRunLoopBase::EnterExitObserver(CFRunLoopObserverRef observer,
+ CFRunLoopActivity activity,
+ void* info) {
+ MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
+
+ switch (activity) {
+ case kCFRunLoopEntry:
+ ++self->nesting_level_;
+ if (self->nesting_level_ > self->deepest_nesting_level_) {
+ self->deepest_nesting_level_ = self->nesting_level_;
+ }
+ break;
+
+ case kCFRunLoopExit:
+ // Not all run loops go to sleep. If a run loop is stopped before it
+ // goes to sleep due to a CFRunLoopStop call, or if the timeout passed
+ // to CFRunLoopRunInMode expires, the run loop may proceed directly from
+ // handling sources to exiting without any sleep. This most commonly
+ // occurs when CFRunLoopRunInMode is passed a timeout of 0, causing it
+ // to make a single pass through the loop and exit without sleep. Some
+ // native loops use CFRunLoop in this way. Because PreWaitObserver will
+ // not be called in these case, MaybeScheduleNestingDeferredWork needs
+ // to be called here, as the run loop exits.
+ //
+ // MaybeScheduleNestingDeferredWork consults self->nesting_level_
+ // to determine whether to schedule nesting-deferred work. It expects
+ // the nesting level to be set to the depth of the loop that is going
+ // to sleep or exiting. It must be called before decrementing the
+ // value so that the value still corresponds to the level of the exiting
+ // loop.
+ self->MaybeScheduleNestingDeferredWork();
+ --self->nesting_level_;
+ break;
+
+ default:
+ break;
+ }
+
+ self->EnterExitRunLoop(activity);
+}
+
+// Called from the run loop.
+// static
+void MessagePumpCFRunLoopBase::PowerStateNotification(void* info,
+ io_service_t service,
+ uint32_t message_type,
+ void* message_argument) {
+ // CFRunLoopTimer (NSTimer) is scheduled in terms of CFAbsoluteTime, which
+ // measures the number of seconds since 2001-01-01 00:00:00.0 Z. It is
+ // implemented in terms of kernel ticks, as in mach_absolute_time. While an
+ // offset and scale factor can be applied to convert between the two time
+ // bases at any time after boot, the kernel clock stops while the system is
+ // asleep, altering the offset. (The offset will also change when the
+ // real-time clock is adjusted.) CFRunLoopTimers are not readjusted to take
+ // this into account when the system wakes up, so any timers that were
+ // pending while the system was asleep will be delayed by the sleep
+ // duration.
+ //
+ // The MessagePump interface assumes that scheduled delayed work will be
+ // performed at the time ScheduleDelayedWork was asked to perform it. The
+ // delay caused by the CFRunLoopTimer not firing at the appropriate time
+ // results in a stall of queued delayed work when the system wakes up.
+ // With this limitation, scheduled work would not be performed until
+ // (system wake time + scheduled work time - system sleep time), while it
+ // would be expected to be performed at (scheduled work time).
+ //
+ // To work around this problem, when the system wakes up from sleep, if a
+ // delayed work timer is pending, it is rescheduled to fire at the original
+ // time that it was scheduled to fire.
+ //
+ // This mechanism is not resilient if the real-time clock does not maintain
+ // stable time while the system is sleeping, but it matches the behavior of
+ // the various other MessagePump implementations, and MessageLoop seems to
+ // be limited in the same way.
+ //
+ // References
+ // - Chris Kane, "NSTimer and deep sleep," cocoa-dev@lists.apple.com,
+ // http://lists.apple.com/archives/Cocoa-dev/2002/May/msg01547.html
+ // - Apple Technical Q&A QA1340, "Registering and unregistering for sleep
+ // and wake notifications,"
+ // http://developer.apple.com/mac/library/qa/qa2004/qa1340.html
+ // - Core Foundation source code, CF-550/CFRunLoop.c and CF-550/CFDate.c,
+ // http://www.opensource.apple.com/
+
+ MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
+
+ switch (message_type) {
+ case kIOMessageSystemWillPowerOn:
+ if (self->delayed_work_fire_time_ != kCFTimeIntervalMax) {
+ CFRunLoopTimerSetNextFireDate(self->delayed_work_timer_,
+ self->delayed_work_fire_time_);
+ }
+ break;
+
+ case kIOMessageSystemWillSleep:
+ case kIOMessageCanSystemSleep:
+ // The system will wait for 30 seconds before entering sleep if neither
+ // IOAllowPowerChange nor IOCancelPowerChange are called. That would be
+ // pretty antisocial.
+ IOAllowPowerChange(self->root_power_domain_,
+ reinterpret_cast<long>(message_argument));
+ break;
+
+ default:
+ break;
+ }
+}
+
+// Called by MessagePumpCFRunLoopBase::EnterExitRunLoop. The default
+// implementation is a no-op.
+void MessagePumpCFRunLoopBase::EnterExitRunLoop(CFRunLoopActivity activity) {}
+
+// Base version returns a standard NSAutoreleasePool.
+NSAutoreleasePool* MessagePumpCFRunLoopBase::CreateAutoreleasePool() {
+ return [[NSAutoreleasePool alloc] init];
+}
+
+MessagePumpCFRunLoop::MessagePumpCFRunLoop() : quit_pending_(false) {}
+
+// Called by MessagePumpCFRunLoopBase::DoRun. If other CFRunLoopRun loops were
+// running lower on the run loop thread's stack when this object was created,
+// the same number of CFRunLoopRun loops must be running for the outermost call
+// to Run. Run/DoRun are reentrant after that point.
+void MessagePumpCFRunLoop::DoRun(Delegate* delegate) {
+ // This is completely identical to calling CFRunLoopRun(), except autorelease
+ // pool management is introduced.
+ int result;
+ do {
+ MessagePumpScopedAutoreleasePool autorelease_pool(this);
+ result =
+ CFRunLoopRunInMode(kCFRunLoopDefaultMode, kCFTimeIntervalMax, false);
+ } while (result != kCFRunLoopRunStopped && result != kCFRunLoopRunFinished);
+}
+
+// Must be called on the run loop thread.
+void MessagePumpCFRunLoop::Quit() {
+ // Stop the innermost run loop managed by this MessagePumpCFRunLoop object.
+ if (nesting_level() == run_nesting_level()) {
+ // This object is running the innermost loop, just stop it.
+ CFRunLoopStop(run_loop());
+ } else {
+ // There's another loop running inside the loop managed by this object.
+ // In other words, someone else called CFRunLoopRunInMode on the same
+ // thread, deeper on the stack than the deepest Run call. Don't preempt
+ // other run loops, just mark this object to quit the innermost Run as
+ // soon as the other inner loops not managed by Run are done.
+ quit_pending_ = true;
+ }
+}
+
+// Called by MessagePumpCFRunLoopBase::EnterExitObserver.
+void MessagePumpCFRunLoop::EnterExitRunLoop(CFRunLoopActivity activity) {
+ if (activity == kCFRunLoopExit && nesting_level() == run_nesting_level() &&
+ quit_pending_) {
+ // Quit was called while loops other than those managed by this object
+ // were running further inside a run loop managed by this object. Now
+ // that all unmanaged inner run loops are gone, stop the loop running
+ // just inside Run.
+ CFRunLoopStop(run_loop());
+ quit_pending_ = false;
+ }
+}
+
+MessagePumpNSRunLoop::MessagePumpNSRunLoop() : keep_running_(true) {
+ CFRunLoopSourceContext source_context = CFRunLoopSourceContext();
+ source_context.perform = NoOp;
+ quit_source_ = CFRunLoopSourceCreate(NULL, // allocator
+ 0, // priority
+ &source_context);
+ CFRunLoopAddSource(run_loop(), quit_source_, kCFRunLoopCommonModes);
+}
+
+MessagePumpNSRunLoop::~MessagePumpNSRunLoop() {
+ CFRunLoopRemoveSource(run_loop(), quit_source_, kCFRunLoopCommonModes);
+ CFRelease(quit_source_);
+}
+
+void MessagePumpNSRunLoop::DoRun(Delegate* delegate) {
+ while (keep_running_) {
+ // NSRunLoop manages autorelease pools itself.
+ [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
+ beforeDate:[NSDate distantFuture]];
+ }
+
+ keep_running_ = true;
+}
+
+void MessagePumpNSRunLoop::Quit() {
+ keep_running_ = false;
+ CFRunLoopSourceSignal(quit_source_);
+ CFRunLoopWakeUp(run_loop());
+}
+
+MessagePumpNSApplication::MessagePumpNSApplication()
+ : keep_running_(true), running_own_loop_(false) {}
+
+void MessagePumpNSApplication::DoRun(Delegate* delegate) {
+ bool last_running_own_loop_ = running_own_loop_;
+
+ // TODO(dmaclach): Get rid of this gratuitous sharedApplication.
+ // Tests should be setting up their applications on their own.
+ [CrApplication sharedApplication];
+
+ if (![NSApp isRunning]) {
+ running_own_loop_ = false;
+ // NSApplication manages autorelease pools itself when run this way.
+ [NSApp run];
+ } else {
+ running_own_loop_ = true;
+ NSDate* distant_future = [NSDate distantFuture];
+ while (keep_running_) {
+ MessagePumpScopedAutoreleasePool autorelease_pool(this);
+ NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny
+ untilDate:distant_future
+ inMode:NSDefaultRunLoopMode
+ dequeue:YES];
+ if (event) {
+ [NSApp sendEvent:event];
+ }
+ }
+ keep_running_ = true;
+ }
+
+ running_own_loop_ = last_running_own_loop_;
+}
+
+void MessagePumpNSApplication::Quit() {
+ if (!running_own_loop_) {
+ [NSApp stop:nil];
+ } else {
+ keep_running_ = false;
+ }
+
+ // Send a fake event to wake the loop up.
+ [NSApp postEvent:[NSEvent otherEventWithType:NSEventTypeApplicationDefined
+ location:NSMakePoint(0, 0)
+ modifierFlags:0
+ timestamp:0
+ windowNumber:0
+ context:NULL
+ subtype:0
+ data1:0
+ data2:0]
+ atStart:NO];
+}
+
+// Prevents an autorelease pool from being created if the app is in the midst of
+// handling a UI event because various parts of AppKit depend on objects that
+// are created while handling a UI event to be autoreleased in the event loop.
+// An example of this is NSWindowController. When a window with a window
+// controller is closed it goes through a stack like this:
+// (Several stack frames elided for clarity)
+//
+// #0 [NSWindowController autorelease]
+// #1 DoAClose
+// #2 MessagePumpCFRunLoopBase::DoWork()
+// #3 [NSRunLoop run]
+// #4 [NSButton performClick:]
+// #5 [NSWindow sendEvent:]
+// #6 [NSApp sendEvent:]
+// #7 [NSApp run]
+//
+// -performClick: spins a nested run loop. If the pool created in DoWork was a
+// standard NSAutoreleasePool, it would release the objects that were
+// autoreleased into it once DoWork released it. This would cause the window
+// controller, which autoreleased itself in frame #0, to release itself, and
+// possibly free itself. Unfortunately this window controller controls the
+// window in frame #5. When the stack is unwound to frame #5, the window would
+// no longer exists and crashes may occur. Apple gets around this by never
+// releasing the pool it creates in frame #4, and letting frame #7 clean it up
+// when it cleans up the pool that wraps frame #7. When an autorelease pool is
+// released it releases all other pools that were created after it on the
+// autorelease pool stack.
+//
+// CrApplication is responsible for setting handlingSendEvent to true just
+// before it sends the event throught the event handling mechanism, and
+// returning it to its previous value once the event has been sent.
+NSAutoreleasePool* MessagePumpNSApplication::CreateAutoreleasePool() {
+ NSAutoreleasePool* pool = nil;
+ DCHECK([NSApp isKindOfClass:[CrApplication class]]);
+ if (![static_cast<CrApplication*>(NSApp) isHandlingSendEvent]) {
+ pool = MessagePumpCFRunLoopBase::CreateAutoreleasePool();
+ }
+ return pool;
+}
+
+// static
+MessagePump* MessagePumpMac::Create() {
+ if ([NSThread isMainThread]) {
+ return new MessagePumpNSApplication;
+ }
+
+ return new MessagePumpNSRunLoop;
+}
+
+} // namespace base
diff --git a/ipc/chromium/src/base/message_pump_qt.cc b/ipc/chromium/src/base/message_pump_qt.cc
new file mode 100644
index 0000000000..d96e2c5e62
--- /dev/null
+++ b/ipc/chromium/src/base/message_pump_qt.cc
@@ -0,0 +1,177 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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 <qabstracteventdispatcher.h>
+#include <qevent.h>
+#include <QCoreApplication>
+#include <QThread>
+#include <qtimer.h>
+
+#include "base/message_pump_qt.h"
+
+#include <fcntl.h>
+#include <limits>
+#include <math.h>
+
+#include "base/eintr_wrapper.h"
+#include "base/logging.h"
+#include "base/platform_thread.h"
+
+namespace {
+// Cached QEvent user type, registered for our event system
+static int sPokeEvent;
+} // namespace
+
+namespace base {
+
+MessagePumpForUI::MessagePumpForUI() : state_(NULL), qt_pump(*this) {}
+
+MessagePumpForUI::~MessagePumpForUI() {}
+
+MessagePumpQt::MessagePumpQt(MessagePumpForUI& aPump)
+ : pump(aPump), mTimer(new QTimer(this)) {
+ // Register our custom event type, to use in qApp event loop
+ sPokeEvent = QEvent::registerEventType();
+ connect(mTimer, SIGNAL(timeout()), this, SLOT(dispatchDelayed()));
+ mTimer->setSingleShot(true);
+}
+
+MessagePumpQt::~MessagePumpQt() {
+ mTimer->stop();
+ delete mTimer;
+}
+
+bool MessagePumpQt::event(QEvent* e) {
+ if (e->type() == sPokeEvent) {
+ pump.HandleDispatch();
+ return true;
+ }
+ return false;
+}
+
+void MessagePumpQt::scheduleDelayedIfNeeded(
+ const TimeTicks& delayed_work_time) {
+ if (delayed_work_time.is_null()) {
+ return;
+ }
+
+ if (mTimer->isActive()) {
+ mTimer->stop();
+ }
+
+ TimeDelta later = delayed_work_time - TimeTicks::Now();
+ // later.InMilliseconds() returns an int64_t, QTimer only accepts int's for
+ // start(), std::min only works on exact same types.
+ int laterMsecs = later.InMilliseconds() > std::numeric_limits<int>::max()
+ ? std::numeric_limits<int>::max()
+ : later.InMilliseconds();
+ mTimer->start(laterMsecs > 0 ? laterMsecs : 0);
+}
+
+void MessagePumpQt::dispatchDelayed() { pump.HandleDispatch(); }
+
+void MessagePumpForUI::Run(Delegate* delegate) {
+ RunState state;
+ state.delegate = delegate;
+ state.should_quit = false;
+ state.run_depth = state_ ? state_->run_depth + 1 : 1;
+ // We really only do a single task for each iteration of the loop. If we
+ // have done something, assume there is likely something more to do. This
+ // will mean that we don't block on the message pump until there was nothing
+ // more to do. We also set this to true to make sure not to block on the
+ // first iteration of the loop, so RunAllPending() works correctly.
+ bool more_work_is_plausible = true;
+
+ RunState* previous_state = state_;
+ state_ = &state;
+
+ for (;;) {
+ QEventLoop::ProcessEventsFlags block = QEventLoop::AllEvents;
+ if (!more_work_is_plausible) {
+ block |= QEventLoop::WaitForMoreEvents;
+ }
+
+ QAbstractEventDispatcher* dispatcher =
+ QAbstractEventDispatcher::instance(QThread::currentThread());
+ // An assertion seems too much here, as during startup,
+ // the dispatcher might not be ready yet.
+ if (!dispatcher) {
+ return;
+ }
+
+ // processEvent's returns true if an event has been processed.
+ more_work_is_plausible = dispatcher->processEvents(block);
+
+ if (state_->should_quit) {
+ break;
+ }
+
+ more_work_is_plausible |= state_->delegate->DoWork();
+ if (state_->should_quit) {
+ break;
+ }
+
+ more_work_is_plausible |=
+ state_->delegate->DoDelayedWork(&delayed_work_time_);
+ if (state_->should_quit) {
+ break;
+ }
+
+ qt_pump.scheduleDelayedIfNeeded(delayed_work_time_);
+
+ if (more_work_is_plausible) {
+ continue;
+ }
+
+ more_work_is_plausible = state_->delegate->DoIdleWork();
+ if (state_->should_quit) {
+ break;
+ }
+ }
+
+ state_ = previous_state;
+}
+
+void MessagePumpForUI::HandleDispatch() {
+ if (state_->should_quit) {
+ return;
+ }
+
+ if (state_->delegate->DoWork()) {
+ // there might be more, see more_work_is_plausible
+ // variable above, that's why we ScheduleWork() to keep going.
+ ScheduleWork();
+ }
+
+ if (state_->should_quit) {
+ return;
+ }
+
+ state_->delegate->DoDelayedWork(&delayed_work_time_);
+ qt_pump.scheduleDelayedIfNeeded(delayed_work_time_);
+}
+
+void MessagePumpForUI::Quit() {
+ if (state_) {
+ state_->should_quit = true;
+ } else {
+ NOTREACHED() << "Quit called outside Run!";
+ }
+}
+
+void MessagePumpForUI::ScheduleWork() {
+ QCoreApplication::postEvent(&qt_pump, new QEvent((QEvent::Type)sPokeEvent));
+}
+
+void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
+ // On GLib implementation, a work source is defined which explicitly checks
+ // the time that has passed. Here, on Qt we can use a QTimer that enqueues our
+ // event signal in an event queue.
+ delayed_work_time_ = delayed_work_time;
+ qt_pump.scheduleDelayedIfNeeded(delayed_work_time_);
+}
+
+} // namespace base
diff --git a/ipc/chromium/src/base/message_pump_qt.h b/ipc/chromium/src/base/message_pump_qt.h
new file mode 100644
index 0000000000..476c9757ac
--- /dev/null
+++ b/ipc/chromium/src/base/message_pump_qt.h
@@ -0,0 +1,84 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MESSAGE_PUMP_QT_H_
+#define BASE_MESSAGE_PUMP_QT_H_
+
+#include <qobject.h>
+
+#include "base/message_pump.h"
+#include "base/time.h"
+
+class QTimer;
+
+namespace base {
+
+class MessagePumpForUI;
+
+class MessagePumpQt : public QObject {
+ Q_OBJECT
+
+ public:
+ MessagePumpQt(MessagePumpForUI& pump);
+ ~MessagePumpQt();
+
+ virtual bool event(QEvent* e);
+ void scheduleDelayedIfNeeded(const TimeTicks& delayed_work_time);
+
+ public Q_SLOTS:
+ void dispatchDelayed();
+
+ private:
+ base::MessagePumpForUI& pump;
+ QTimer* mTimer;
+};
+
+// This class implements a MessagePump needed for TYPE_UI MessageLoops on
+// XP_LINUX platforms using QApplication event loop
+class MessagePumpForUI : public MessagePump {
+ public:
+ MessagePumpForUI();
+ ~MessagePumpForUI();
+
+ virtual void Run(Delegate* delegate);
+ virtual void Quit();
+ virtual void ScheduleWork();
+ virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time);
+
+ // Internal methods used for processing the pump callbacks. They are
+ // public for simplicity but should not be used directly.
+ // HandleDispatch is called after the poll has completed.
+ void HandleDispatch();
+
+ private:
+ // We may make recursive calls to Run, so we save state that needs to be
+ // separate between them in this structure type.
+ struct RunState {
+ Delegate* delegate;
+
+ // Used to flag that the current Run() invocation should return ASAP.
+ bool should_quit;
+
+ // Used to count how many Run() invocations are on the stack.
+ int run_depth;
+ };
+
+ RunState* state_;
+
+ // This is the time when we need to do delayed work.
+ TimeTicks delayed_work_time_;
+
+ // MessagePump implementation for Qt based on the GLib implement.
+ // On Qt we use a QObject base class and the
+ // default qApp in order to process events through QEventLoop.
+ MessagePumpQt qt_pump;
+
+ DISALLOW_COPY_AND_ASSIGN(MessagePumpForUI);
+};
+
+} // namespace base
+
+#endif // BASE_MESSAGE_PUMP_QT_H_
diff --git a/ipc/chromium/src/base/message_pump_win.cc b/ipc/chromium/src/base/message_pump_win.cc
new file mode 100644
index 0000000000..f0caa1db6c
--- /dev/null
+++ b/ipc/chromium/src/base/message_pump_win.cc
@@ -0,0 +1,553 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=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/message_pump_win.h"
+
+#include <math.h>
+
+#include "base/message_loop.h"
+#include "base/histogram.h"
+#include "base/win_util.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/ProfilerLabels.h"
+#include "mozilla/ProfilerThreadSleep.h"
+#include "WinUtils.h"
+
+using base::Time;
+
+namespace base {
+
+static const wchar_t kWndClass[] = L"Chrome_MessagePumpWindow";
+
+// Message sent to get an additional time slice for pumping (processing) another
+// task (a series of such messages creates a continuous task pump).
+static const int kMsgHaveWork = WM_USER + 1;
+
+//-----------------------------------------------------------------------------
+// MessagePumpWin public:
+
+void MessagePumpWin::AddObserver(Observer* observer) {
+ observers_.AddObserver(observer);
+}
+
+void MessagePumpWin::RemoveObserver(Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+void MessagePumpWin::WillProcessMessage(const MSG& msg) {
+ FOR_EACH_OBSERVER(Observer, observers_, WillProcessMessage(msg));
+}
+
+void MessagePumpWin::DidProcessMessage(const MSG& msg) {
+ FOR_EACH_OBSERVER(Observer, observers_, DidProcessMessage(msg));
+}
+
+void MessagePumpWin::RunWithDispatcher(Delegate* delegate,
+ Dispatcher* dispatcher) {
+ RunState s;
+ s.delegate = delegate;
+ s.dispatcher = dispatcher;
+ s.should_quit = false;
+ s.run_depth = state_ ? state_->run_depth + 1 : 1;
+
+ RunState* previous_state = state_;
+ state_ = &s;
+
+ DoRunLoop();
+
+ state_ = previous_state;
+}
+
+void MessagePumpWin::Quit() {
+ DCHECK(state_);
+ state_->should_quit = true;
+}
+
+//-----------------------------------------------------------------------------
+// MessagePumpWin protected:
+
+int MessagePumpWin::GetCurrentDelay() const {
+ if (delayed_work_time_.is_null()) return -1;
+
+ // Be careful here. TimeDelta has a precision of microseconds, but we want a
+ // value in milliseconds. If there are 5.5ms left, should the delay be 5 or
+ // 6? It should be 6 to avoid executing delayed work too early.
+ double timeout =
+ ceil((delayed_work_time_ - TimeTicks::Now()).InMillisecondsF());
+
+ // If this value is negative, then we need to run delayed work soon.
+ int delay = static_cast<int>(timeout);
+ if (delay < 0) delay = 0;
+
+ return delay;
+}
+
+//-----------------------------------------------------------------------------
+// MessagePumpForUI public:
+
+MessagePumpForUI::MessagePumpForUI() { InitMessageWnd(); }
+
+MessagePumpForUI::~MessagePumpForUI() {
+ DestroyWindow(message_hwnd_);
+ UnregisterClass(kWndClass, GetModuleHandle(NULL));
+}
+
+void MessagePumpForUI::ScheduleWork() {
+ if (InterlockedExchange(&have_work_, 1))
+ return; // Someone else continued the pumping.
+
+ // Make sure the MessagePump does some work for us.
+ PostMessage(message_hwnd_, kMsgHaveWork, reinterpret_cast<WPARAM>(this), 0);
+
+ // In order to wake up any cross-process COM calls which may currently be
+ // pending on the main thread, we also have to post a UI message.
+ PostMessage(message_hwnd_, WM_NULL, 0, 0);
+}
+
+void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
+ //
+ // We would *like* to provide high resolution timers. Windows timers using
+ // SetTimer() have a 10ms granularity. We have to use WM_TIMER as a wakeup
+ // mechanism because the application can enter modal windows loops where it
+ // is not running our MessageLoop; the only way to have our timers fire in
+ // these cases is to post messages there.
+ //
+ // To provide sub-10ms timers, we process timers directly from our run loop.
+ // For the common case, timers will be processed there as the run loop does
+ // its normal work. However, we *also* set the system timer so that WM_TIMER
+ // events fire. This mops up the case of timers not being able to work in
+ // modal message loops. It is possible for the SetTimer to pop and have no
+ // pending timers, because they could have already been processed by the
+ // run loop itself.
+ //
+ // We use a single SetTimer corresponding to the timer that will expire
+ // soonest. As new timers are created and destroyed, we update SetTimer.
+ // Getting a spurrious SetTimer event firing is benign, as we'll just be
+ // processing an empty timer queue.
+ //
+ delayed_work_time_ = delayed_work_time;
+
+ int delay_msec = GetCurrentDelay();
+ DCHECK(delay_msec >= 0);
+ if (delay_msec < USER_TIMER_MINIMUM) delay_msec = USER_TIMER_MINIMUM;
+
+ // Create a WM_TIMER event that will wake us up to check for any pending
+ // timers (in case we are running within a nested, external sub-pump).
+ SetTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this), delay_msec, NULL);
+}
+
+void MessagePumpForUI::PumpOutPendingPaintMessages() {
+ // If we are being called outside of the context of Run, then don't try to do
+ // any work.
+ if (!state_) return;
+
+ // Create a mini-message-pump to force immediate processing of only Windows
+ // WM_PAINT messages. Don't provide an infinite loop, but do enough peeking
+ // to get the job done. Actual common max is 4 peeks, but we'll be a little
+ // safe here.
+ const int kMaxPeekCount = 20;
+ int peek_count;
+ for (peek_count = 0; peek_count < kMaxPeekCount; ++peek_count) {
+ MSG msg;
+ if (!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE | PM_QS_PAINT)) break;
+ ProcessMessageHelper(msg);
+ if (state_->should_quit) break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// MessagePumpForUI private:
+
+// static
+LRESULT CALLBACK MessagePumpForUI::WndProcThunk(HWND hwnd, UINT message,
+ WPARAM wparam, LPARAM lparam) {
+ switch (message) {
+ case kMsgHaveWork:
+ reinterpret_cast<MessagePumpForUI*>(wparam)->HandleWorkMessage();
+ break;
+ case WM_TIMER:
+ reinterpret_cast<MessagePumpForUI*>(wparam)->HandleTimerMessage();
+ break;
+ }
+ return DefWindowProc(hwnd, message, wparam, lparam);
+}
+
+void MessagePumpForUI::DoRunLoop() {
+ // IF this was just a simple PeekMessage() loop (servicing all possible work
+ // queues), then Windows would try to achieve the following order according
+ // to MSDN documentation about PeekMessage with no filter):
+ // * Sent messages
+ // * Posted messages
+ // * Sent messages (again)
+ // * WM_PAINT messages
+ // * WM_TIMER messages
+ //
+ // Summary: none of the above classes is starved, and sent messages has twice
+ // the chance of being processed (i.e., reduced service time).
+
+ for (;;) {
+ // If we do any work, we may create more messages etc., and more work may
+ // possibly be waiting in another task group. When we (for example)
+ // ProcessNextWindowsMessage(), there is a good chance there are still more
+ // messages waiting. On the other hand, when any of these methods return
+ // having done no work, then it is pretty unlikely that calling them again
+ // quickly will find any work to do. Finally, if they all say they had no
+ // work, then it is a good time to consider sleeping (waiting) for more
+ // work.
+
+ bool more_work_is_plausible = ProcessNextWindowsMessage();
+ if (state_->should_quit) break;
+
+ more_work_is_plausible |= state_->delegate->DoWork();
+ if (state_->should_quit) break;
+
+ more_work_is_plausible |=
+ state_->delegate->DoDelayedWork(&delayed_work_time_);
+ // If we did not process any delayed work, then we can assume that our
+ // existing WM_TIMER if any will fire when delayed work should run. We
+ // don't want to disturb that timer if it is already in flight. However,
+ // if we did do all remaining delayed work, then lets kill the WM_TIMER.
+ if (more_work_is_plausible && delayed_work_time_.is_null())
+ KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this));
+ if (state_->should_quit) break;
+
+ if (more_work_is_plausible) continue;
+
+ more_work_is_plausible = state_->delegate->DoIdleWork();
+ if (state_->should_quit) break;
+
+ if (more_work_is_plausible) continue;
+
+ WaitForWork(); // Wait (sleep) until we have work to do again.
+ }
+}
+
+void MessagePumpForUI::InitMessageWnd() {
+ HINSTANCE hinst = GetModuleHandle(NULL);
+
+ WNDCLASSEX wc = {0};
+ wc.cbSize = sizeof(wc);
+ wc.lpfnWndProc = WndProcThunk;
+ wc.hInstance = hinst;
+ wc.lpszClassName = kWndClass;
+ RegisterClassEx(&wc);
+
+ message_hwnd_ =
+ CreateWindow(kWndClass, 0, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, hinst, 0);
+ DCHECK(message_hwnd_);
+}
+
+void MessagePumpForUI::WaitForWork() {
+ AUTO_PROFILER_LABEL("MessagePumpForUI::WaitForWork", IDLE);
+
+ // Wait until a message is available, up to the time needed by the timer
+ // manager to fire the next set of timers.
+ int delay = GetCurrentDelay();
+ if (delay < 0) // Negative value means no timers waiting.
+ delay = INFINITE;
+
+ mozilla::widget::WinUtils::WaitForMessage(delay);
+}
+
+void MessagePumpForUI::HandleWorkMessage() {
+ // If we are being called outside of the context of Run, then don't try to do
+ // any work. This could correspond to a MessageBox call or something of that
+ // sort.
+ if (!state_) {
+ // Since we handled a kMsgHaveWork message, we must still update this flag.
+ InterlockedExchange(&have_work_, 0);
+ return;
+ }
+
+ // Let whatever would have run had we not been putting messages in the queue
+ // run now. This is an attempt to make our dummy message not starve other
+ // messages that may be in the Windows message queue.
+ ProcessPumpReplacementMessage();
+
+ // Now give the delegate a chance to do some work. He'll let us know if he
+ // needs to do more work.
+ if (state_->delegate->DoWork()) ScheduleWork();
+}
+
+void MessagePumpForUI::HandleTimerMessage() {
+ KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this));
+
+ // If we are being called outside of the context of Run, then don't do
+ // anything. This could correspond to a MessageBox call or something of
+ // that sort.
+ if (!state_) return;
+
+ state_->delegate->DoDelayedWork(&delayed_work_time_);
+ if (!delayed_work_time_.is_null()) {
+ // A bit gratuitous to set delayed_work_time_ again, but oh well.
+ ScheduleDelayedWork(delayed_work_time_);
+ }
+}
+
+bool MessagePumpForUI::ProcessNextWindowsMessage() {
+ // If there are sent messages in the queue then PeekMessage internally
+ // dispatches the message and returns false. We return true in this
+ // case to ensure that the message loop peeks again instead of calling
+ // MsgWaitForMultipleObjectsEx again.
+ bool sent_messages_in_queue = false;
+ DWORD queue_status = ::GetQueueStatus(QS_SENDMESSAGE);
+ if (HIWORD(queue_status) & QS_SENDMESSAGE) sent_messages_in_queue = true;
+
+ MSG msg;
+ if (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
+ return ProcessMessageHelper(msg);
+
+ return sent_messages_in_queue;
+}
+
+bool MessagePumpForUI::ProcessMessageHelper(const MSG& msg) {
+ if (WM_QUIT == msg.message) {
+ // WM_QUIT is the standard way to exit a ::GetMessage() loop. Our
+ // MessageLoop has its own quit mechanism, so WM_QUIT is unexpected and
+ // should be ignored.
+ return true;
+ }
+
+ // While running our main message pump, we discard kMsgHaveWork messages.
+ if (msg.message == kMsgHaveWork && msg.hwnd == message_hwnd_)
+ return ProcessPumpReplacementMessage();
+
+ WillProcessMessage(msg);
+
+ if (state_->dispatcher) {
+ if (!state_->dispatcher->Dispatch(msg)) state_->should_quit = true;
+ } else {
+ ::TranslateMessage(&msg);
+ ::DispatchMessage(&msg);
+ }
+
+ DidProcessMessage(msg);
+ return true;
+}
+
+bool MessagePumpForUI::ProcessPumpReplacementMessage() {
+ // When we encounter a kMsgHaveWork message, this method is called to peek
+ // and process a replacement message, such as a WM_PAINT or WM_TIMER. The
+ // goal is to make the kMsgHaveWork as non-intrusive as possible, even though
+ // a continuous stream of such messages are posted. This method carefully
+ // peeks a message while there is no chance for a kMsgHaveWork to be pending,
+ // then resets the have_work_ flag (allowing a replacement kMsgHaveWork to
+ // possibly be posted), and finally dispatches that peeked replacement. Note
+ // that the re-post of kMsgHaveWork may be asynchronous to this thread!!
+
+ MSG msg;
+ bool have_message = false;
+ if (MessageLoop::current()->os_modal_loop()) {
+ // We only peek out WM_PAINT and WM_TIMER here for reasons mentioned above.
+ have_message = ::PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE) ||
+ ::PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE);
+ } else {
+ have_message = (0 != ::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE));
+
+ if (have_message && msg.message == WM_NULL)
+ have_message = (0 != ::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE));
+ }
+
+ DCHECK(!have_message || kMsgHaveWork != msg.message ||
+ msg.hwnd != message_hwnd_);
+
+ // Since we discarded a kMsgHaveWork message, we must update the flag.
+ int old_have_work = InterlockedExchange(&have_work_, 0);
+ DCHECK(old_have_work);
+
+ // We don't need a special time slice if we didn't have_message to process.
+ if (!have_message) return false;
+
+ if (WM_QUIT == msg.message) {
+ // If we're in a nested ::GetMessage() loop then we must let that loop see
+ // the WM_QUIT in order for it to exit. If we're in DoRunLoop then the re-
+ // posted WM_QUIT will be either ignored, or handled, by
+ // ProcessMessageHelper() called directly from ProcessNextWindowsMessage().
+ ::PostQuitMessage(static_cast<int>(msg.wParam));
+ // Note: we *must not* ScheduleWork() here as WM_QUIT is a low-priority
+ // message on Windows (it is only returned by ::PeekMessage() when idle) :
+ // https://blogs.msdn.microsoft.com/oldnewthing/20051104-33/?p=33453. As
+ // such posting a kMsgHaveWork message via ScheduleWork() would cause an
+ // infinite loop (kMsgHaveWork message handled first means we end up here
+ // again and repost WM_QUIT+ScheduleWork() again, etc.). Not leaving a
+ // kMsgHaveWork message behind however is also problematic as unwinding
+ // multiple layers of nested ::GetMessage() loops can result in starving
+ // application tasks. TODO(https://crbug.com/890016) : Fix this.
+
+ // The return value is mostly irrelevant but return true like we would after
+ // processing a QuitClosure() task.
+ return true;
+ }
+
+ // Guarantee we'll get another time slice in the case where we go into native
+ // windows code. This ScheduleWork() may hurt performance a tiny bit when
+ // tasks appear very infrequently, but when the event queue is busy, the
+ // kMsgHaveWork events get (percentage wise) rarer and rarer.
+ ScheduleWork();
+ return ProcessMessageHelper(msg);
+}
+
+//-----------------------------------------------------------------------------
+// MessagePumpForIO public:
+
+MessagePumpForIO::MessagePumpForIO() {
+ port_.Set(CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1));
+ DCHECK(port_.IsValid());
+}
+
+void MessagePumpForIO::ScheduleWork() {
+ if (InterlockedExchange(&have_work_, 1))
+ return; // Someone else continued the pumping.
+
+ // Make sure the MessagePump does some work for us.
+ BOOL ret =
+ PostQueuedCompletionStatus(port_, 0, reinterpret_cast<ULONG_PTR>(this),
+ reinterpret_cast<OVERLAPPED*>(this));
+ DCHECK(ret);
+}
+
+void MessagePumpForIO::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
+ // We know that we can't be blocked right now since this method can only be
+ // called on the same thread as Run, so we only need to update our record of
+ // how long to sleep when we do sleep.
+ delayed_work_time_ = delayed_work_time;
+}
+
+void MessagePumpForIO::RegisterIOHandler(HANDLE file_handle,
+ IOHandler* handler) {
+ ULONG_PTR key = reinterpret_cast<ULONG_PTR>(handler);
+ HANDLE port = CreateIoCompletionPort(file_handle, port_, key, 1);
+ DCHECK(port == port_.Get());
+}
+
+//-----------------------------------------------------------------------------
+// MessagePumpForIO private:
+
+void MessagePumpForIO::DoRunLoop() {
+ for (;;) {
+ // If we do any work, we may create more messages etc., and more work may
+ // possibly be waiting in another task group. When we (for example)
+ // WaitForIOCompletion(), there is a good chance there are still more
+ // messages waiting. On the other hand, when any of these methods return
+ // having done no work, then it is pretty unlikely that calling them
+ // again quickly will find any work to do. Finally, if they all say they
+ // had no work, then it is a good time to consider sleeping (waiting) for
+ // more work.
+
+ bool more_work_is_plausible = state_->delegate->DoWork();
+ if (state_->should_quit) break;
+
+ more_work_is_plausible |= WaitForIOCompletion(0, NULL);
+ if (state_->should_quit) break;
+
+ more_work_is_plausible |=
+ state_->delegate->DoDelayedWork(&delayed_work_time_);
+ if (state_->should_quit) break;
+
+ if (more_work_is_plausible) continue;
+
+ more_work_is_plausible = state_->delegate->DoIdleWork();
+ if (state_->should_quit) break;
+
+ if (more_work_is_plausible) continue;
+
+ WaitForWork(); // Wait (sleep) until we have work to do again.
+ }
+}
+
+// Wait until IO completes, up to the time needed by the timer manager to fire
+// the next set of timers.
+void MessagePumpForIO::WaitForWork() {
+ // We do not support nested IO message loops. This is to avoid messy
+ // recursion problems.
+ DCHECK(state_->run_depth == 1) << "Cannot nest an IO message loop!";
+
+ int timeout = GetCurrentDelay();
+ if (timeout < 0) // Negative value means no timers waiting.
+ timeout = INFINITE;
+
+ WaitForIOCompletion(timeout, NULL);
+}
+
+bool MessagePumpForIO::WaitForIOCompletion(DWORD timeout, IOHandler* filter) {
+ IOItem item;
+ if (completed_io_.empty() || !MatchCompletedIOItem(filter, &item)) {
+ // We have to ask the system for another IO completion.
+ if (!GetIOItem(timeout, &item)) return false;
+
+ if (ProcessInternalIOItem(item)) return true;
+ }
+
+ if (item.context->handler) {
+ if (filter && item.handler != filter) {
+ // Save this item for later
+ completed_io_.push_back(item);
+ } else {
+ DCHECK(item.context->handler == item.handler);
+ item.handler->OnIOCompleted(item.context, item.bytes_transfered,
+ item.error);
+ }
+ } else {
+ // The handler must be gone by now, just cleanup the mess.
+ delete item.context;
+ }
+ return true;
+}
+
+// Asks the OS for another IO completion result.
+bool MessagePumpForIO::GetIOItem(DWORD timeout, IOItem* item) {
+ memset(item, 0, sizeof(*item));
+ ULONG_PTR key = 0;
+ OVERLAPPED* overlapped = NULL;
+ BOOL success;
+ {
+ AUTO_PROFILER_LABEL("MessagePumpForIO::GetIOItem::Wait", IDLE);
+#ifdef MOZ_GECKO_PROFILER
+ mozilla::Maybe<mozilla::AutoProfilerThreadSleep> profilerThreadSleep;
+ if (timeout != 0) {
+ profilerThreadSleep.emplace();
+ }
+#endif
+ success = GetQueuedCompletionStatus(port_.Get(), &item->bytes_transfered,
+ &key, &overlapped, timeout);
+ }
+ if (!success) {
+ if (!overlapped) return false; // Nothing in the queue.
+ item->error = GetLastError();
+ item->bytes_transfered = 0;
+ }
+
+ item->handler = reinterpret_cast<IOHandler*>(key);
+ item->context = reinterpret_cast<IOContext*>(overlapped);
+ return true;
+}
+
+bool MessagePumpForIO::ProcessInternalIOItem(const IOItem& item) {
+ if (this == reinterpret_cast<MessagePumpForIO*>(item.context) &&
+ this == reinterpret_cast<MessagePumpForIO*>(item.handler)) {
+ // This is our internal completion.
+ DCHECK(!item.bytes_transfered);
+ InterlockedExchange(&have_work_, 0);
+ return true;
+ }
+ return false;
+}
+
+// Returns a completion item that was previously received.
+bool MessagePumpForIO::MatchCompletedIOItem(IOHandler* filter, IOItem* item) {
+ DCHECK(!completed_io_.empty());
+ for (std::list<IOItem>::iterator it = completed_io_.begin();
+ it != completed_io_.end(); ++it) {
+ if (!filter || it->handler == filter) {
+ *item = *it;
+ completed_io_.erase(it);
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace base
diff --git a/ipc/chromium/src/base/message_pump_win.h b/ipc/chromium/src/base/message_pump_win.h
new file mode 100644
index 0000000000..585a4d3ff5
--- /dev/null
+++ b/ipc/chromium/src/base/message_pump_win.h
@@ -0,0 +1,347 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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_MESSAGE_PUMP_WIN_H_
+#define BASE_MESSAGE_PUMP_WIN_H_
+
+#include <windows.h>
+
+#include <list>
+
+#include "base/message_pump.h"
+#include "base/observer_list.h"
+#include "base/scoped_handle.h"
+#include "base/time.h"
+
+namespace base {
+
+// MessagePumpWin serves as the base for specialized versions of the MessagePump
+// for Windows. It provides basic functionality like handling of observers and
+// controlling the lifetime of the message pump.
+class MessagePumpWin : public MessagePump {
+ public:
+ // An Observer is an object that receives global notifications from the
+ // MessageLoop.
+ //
+ // NOTE: An Observer implementation should be extremely fast!
+ //
+ class Observer {
+ public:
+ virtual ~Observer() {}
+
+ // This method is called before processing a message.
+ // The message may be undefined in which case msg.message is 0
+ virtual void WillProcessMessage(const MSG& msg) = 0;
+
+ // This method is called when control returns from processing a UI message.
+ // The message may be undefined in which case msg.message is 0
+ virtual void DidProcessMessage(const MSG& msg) = 0;
+ };
+
+ // Dispatcher is used during a nested invocation of Run to dispatch events.
+ // If Run is invoked with a non-NULL Dispatcher, MessageLoop does not
+ // dispatch events (or invoke TranslateMessage), rather every message is
+ // passed to Dispatcher's Dispatch method for dispatch. It is up to the
+ // Dispatcher to dispatch, or not, the event.
+ //
+ // The nested loop is exited by either posting a quit, or returning false
+ // from Dispatch.
+ class Dispatcher {
+ public:
+ virtual ~Dispatcher() {}
+ // Dispatches the event. If true is returned processing continues as
+ // normal. If false is returned, the nested loop exits immediately.
+ virtual bool Dispatch(const MSG& msg) = 0;
+ };
+
+ MessagePumpWin() : have_work_(0), state_(NULL) {}
+ virtual ~MessagePumpWin() {}
+
+ // Add an Observer, which will start receiving notifications immediately.
+ void AddObserver(Observer* observer);
+
+ // Remove an Observer. It is safe to call this method while an Observer is
+ // receiving a notification callback.
+ void RemoveObserver(Observer* observer);
+
+ // Give a chance to code processing additional messages to notify the
+ // message loop observers that another message has been processed.
+ void WillProcessMessage(const MSG& msg);
+ void DidProcessMessage(const MSG& msg);
+
+ // Like MessagePump::Run, but MSG objects are routed through dispatcher.
+ void RunWithDispatcher(Delegate* delegate, Dispatcher* dispatcher);
+
+ // MessagePump methods:
+ virtual void Run(Delegate* delegate) { RunWithDispatcher(delegate, NULL); }
+ virtual void Quit();
+
+ protected:
+ struct RunState {
+ Delegate* delegate;
+ Dispatcher* dispatcher;
+
+ // Used to flag that the current Run() invocation should return ASAP.
+ bool should_quit;
+
+ // Used to count how many Run() invocations are on the stack.
+ int run_depth;
+ };
+
+ virtual void DoRunLoop() = 0;
+ int GetCurrentDelay() const;
+
+ ObserverList<Observer> observers_;
+
+ // The time at which delayed work should run.
+ TimeTicks delayed_work_time_;
+
+ // A boolean value used to indicate if there is a kMsgDoWork message pending
+ // in the Windows Message queue. There is at most one such message, and it
+ // can drive execution of tasks when a native message pump is running.
+ LONG have_work_;
+
+ // State for the current invocation of Run.
+ RunState* state_;
+};
+
+//-----------------------------------------------------------------------------
+// MessagePumpForUI extends MessagePumpWin with methods that are particular to a
+// MessageLoop instantiated with TYPE_UI.
+//
+// MessagePumpForUI implements a "traditional" Windows message pump. It contains
+// a nearly infinite loop that peeks out messages, and then dispatches them.
+// Intermixed with those peeks are callouts to DoWork for pending tasks, and
+// DoDelayedWork for pending timers. When there are no events to be serviced,
+// this pump goes into a wait state. In most cases, this message pump handles
+// all processing.
+//
+// However, when a task, or windows event, invokes on the stack a native dialog
+// box or such, that window typically provides a bare bones (native?) message
+// pump. That bare-bones message pump generally supports little more than a
+// peek of the Windows message queue, followed by a dispatch of the peeked
+// message. MessageLoop extends that bare-bones message pump to also service
+// Tasks, at the cost of some complexity.
+//
+// The basic structure of the extension (refered to as a sub-pump) is that a
+// special message, kMsgHaveWork, is repeatedly injected into the Windows
+// Message queue. Each time the kMsgHaveWork message is peeked, checks are
+// made for an extended set of events, including the availability of Tasks to
+// run.
+//
+// After running a task, the special message kMsgHaveWork is again posted to
+// the Windows Message queue, ensuring a future time slice for processing a
+// future event. To prevent flooding the Windows Message queue, care is taken
+// to be sure that at most one kMsgHaveWork message is EVER pending in the
+// Window's Message queue.
+//
+// There are a few additional complexities in this system where, when there are
+// no Tasks to run, this otherwise infinite stream of messages which drives the
+// sub-pump is halted. The pump is automatically re-started when Tasks are
+// queued.
+//
+// A second complexity is that the presence of this stream of posted tasks may
+// prevent a bare-bones message pump from ever peeking a WM_PAINT or WM_TIMER.
+// Such paint and timer events always give priority to a posted message, such as
+// kMsgHaveWork messages. As a result, care is taken to do some peeking in
+// between the posting of each kMsgHaveWork message (i.e., after kMsgHaveWork
+// is peeked, and before a replacement kMsgHaveWork is posted).
+//
+// NOTE: Although it may seem odd that messages are used to start and stop this
+// flow (as opposed to signaling objects, etc.), it should be understood that
+// the native message pump will *only* respond to messages. As a result, it is
+// an excellent choice. It is also helpful that the starter messages that are
+// placed in the queue when new task arrive also awakens DoRunLoop.
+//
+class MessagePumpForUI : public MessagePumpWin {
+ public:
+ MessagePumpForUI();
+ virtual ~MessagePumpForUI();
+
+ // MessagePump methods:
+ virtual void ScheduleWork();
+ virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time);
+
+ // Applications can call this to encourage us to process all pending WM_PAINT
+ // messages. This method will process all paint messages the Windows Message
+ // queue can provide, up to some fixed number (to avoid any infinite loops).
+ void PumpOutPendingPaintMessages();
+
+ protected:
+ virtual void DoRunLoop();
+
+ bool ProcessNextWindowsMessage();
+ void InitMessageWnd();
+ void WaitForWork();
+ void HandleWorkMessage();
+ void HandleTimerMessage();
+ bool ProcessMessageHelper(const MSG& msg);
+ bool ProcessPumpReplacementMessage();
+
+ // A hidden message-only window.
+ HWND message_hwnd_;
+
+ private:
+ static LRESULT CALLBACK WndProcThunk(HWND hwnd, UINT message, WPARAM wparam,
+ LPARAM lparam);
+};
+
+//-----------------------------------------------------------------------------
+// MessagePumpForIO extends MessagePumpWin with methods that are particular to a
+// MessageLoop instantiated with TYPE_IO. This version of MessagePump does not
+// deal with Windows mesagges, and instead has a Run loop based on Completion
+// Ports so it is better suited for IO operations.
+//
+class MessagePumpForIO : public MessagePumpWin {
+ public:
+ struct IOContext;
+
+ // Clients interested in receiving OS notifications when asynchronous IO
+ // operations complete should implement this interface and register themselves
+ // with the message pump.
+ //
+ // Typical use #1:
+ // // Use only when there are no user's buffers involved on the actual IO,
+ // // so that all the cleanup can be done by the message pump.
+ // class MyFile : public IOHandler {
+ // MyFile() {
+ // ...
+ // context_ = new IOContext;
+ // context_->handler = this;
+ // message_pump->RegisterIOHandler(file_, this);
+ // }
+ // ~MyFile() {
+ // if (pending_) {
+ // // By setting the handler to NULL, we're asking for this context
+ // // to be deleted when received, without calling back to us.
+ // context_->handler = NULL;
+ // } else {
+ // delete context_;
+ // }
+ // }
+ // virtual void OnIOCompleted(IOContext* context, DWORD bytes_transfered,
+ // DWORD error) {
+ // pending_ = false;
+ // }
+ // void DoSomeIo() {
+ // ...
+ // // The only buffer required for this operation is the overlapped
+ // // structure.
+ // ConnectNamedPipe(file_, &context_->overlapped);
+ // pending_ = true;
+ // }
+ // bool pending_;
+ // IOContext* context_;
+ // HANDLE file_;
+ // };
+ //
+ // Typical use #2:
+ // class MyFile : public IOHandler {
+ // MyFile() {
+ // ...
+ // message_pump->RegisterIOHandler(file_, this);
+ // }
+ // // Plus some code to make sure that this destructor is not called
+ // // while there are pending IO operations.
+ // ~MyFile() {
+ // }
+ // virtual void OnIOCompleted(IOContext* context, DWORD bytes_transfered,
+ // DWORD error) {
+ // ...
+ // delete context;
+ // }
+ // void DoSomeIo() {
+ // ...
+ // IOContext* context = new IOContext;
+ // // This is not used for anything. It just prevents the context from
+ // // being considered "abandoned".
+ // context->handler = this;
+ // ReadFile(file_, buffer, num_bytes, &read, &context->overlapped);
+ // }
+ // HANDLE file_;
+ // };
+ //
+ // Typical use #3:
+ // Same as the previous example, except that in order to deal with the
+ // requirement stated for the destructor, the class calls WaitForIOCompletion
+ // from the destructor to block until all IO finishes.
+ // ~MyFile() {
+ // while(pending_)
+ // message_pump->WaitForIOCompletion(INFINITE, this);
+ // }
+ //
+ class IOHandler {
+ public:
+ virtual ~IOHandler() {}
+ // This will be called once the pending IO operation associated with
+ // |context| completes. |error| is the Win32 error code of the IO operation
+ // (ERROR_SUCCESS if there was no error). |bytes_transfered| will be zero
+ // on error.
+ virtual void OnIOCompleted(IOContext* context, DWORD bytes_transfered,
+ DWORD error) = 0;
+ };
+
+ // The extended context that should be used as the base structure on every
+ // overlapped IO operation. |handler| must be set to the registered IOHandler
+ // for the given file when the operation is started, and it can be set to NULL
+ // before the operation completes to indicate that the handler should not be
+ // called anymore, and instead, the IOContext should be deleted when the OS
+ // notifies the completion of this operation. Please remember that any buffers
+ // involved with an IO operation should be around until the callback is
+ // received, so this technique can only be used for IO that do not involve
+ // additional buffers (other than the overlapped structure itself).
+ struct IOContext {
+ OVERLAPPED overlapped;
+ IOHandler* handler;
+ };
+
+ MessagePumpForIO();
+ virtual ~MessagePumpForIO() {}
+
+ // MessagePump methods:
+ virtual void ScheduleWork();
+ virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time);
+
+ // Register the handler to be used when asynchronous IO for the given file
+ // completes. The registration persists as long as |file_handle| is valid, so
+ // |handler| must be valid as long as there is pending IO for the given file.
+ void RegisterIOHandler(HANDLE file_handle, IOHandler* handler);
+
+ // Waits for the next IO completion that should be processed by |filter|, for
+ // up to |timeout| milliseconds. Return true if any IO operation completed,
+ // regardless of the involved handler, and false if the timeout expired. If
+ // the completion port received any message and the involved IO handler
+ // matches |filter|, the callback is called before returning from this code;
+ // if the handler is not the one that we are looking for, the callback will
+ // be postponed for another time, so reentrancy problems can be avoided.
+ // External use of this method should be reserved for the rare case when the
+ // caller is willing to allow pausing regular task dispatching on this thread.
+ bool WaitForIOCompletion(DWORD timeout, IOHandler* filter);
+
+ private:
+ struct IOItem {
+ IOHandler* handler;
+ IOContext* context;
+ DWORD bytes_transfered;
+ DWORD error;
+ };
+
+ virtual void DoRunLoop();
+ void WaitForWork();
+ bool MatchCompletedIOItem(IOHandler* filter, IOItem* item);
+ bool GetIOItem(DWORD timeout, IOItem* item);
+ bool ProcessInternalIOItem(const IOItem& item);
+
+ // The completion port associated with this thread.
+ ScopedHandle port_;
+ // This list will be empty almost always. It stores IO completions that have
+ // not been delivered yet because somebody was doing cleanup.
+ std::list<IOItem> completed_io_;
+};
+
+} // namespace base
+
+#endif // BASE_MESSAGE_PUMP_WIN_H_
diff --git a/ipc/chromium/src/base/object_watcher.cc b/ipc/chromium/src/base/object_watcher.cc
new file mode 100644
index 0000000000..b749829a0e
--- /dev/null
+++ b/ipc/chromium/src/base/object_watcher.cc
@@ -0,0 +1,135 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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 "base/object_watcher.h"
+
+#include "base/logging.h"
+
+namespace base {
+
+//-----------------------------------------------------------------------------
+
+class ObjectWatcher::Watch : public mozilla::Runnable {
+ public:
+ ObjectWatcher* watcher; // The associated ObjectWatcher instance
+ HANDLE object; // The object being watched
+ HANDLE wait_object; // Returned by RegisterWaitForSingleObject
+ MessageLoop* origin_loop; // Used to get back to the origin thread
+ Delegate* delegate; // Delegate to notify when signaled
+ bool did_signal; // DoneWaiting was called
+
+ Watch() : mozilla::Runnable("ObjectWatcher::Watch") {}
+
+ NS_IMETHOD Run() override {
+ // The watcher may have already been torn down, in which case we need to
+ // just get out of dodge.
+ if (!watcher) return NS_OK;
+
+ DCHECK(did_signal);
+ watcher->StopWatching();
+
+ delegate->OnObjectSignaled(object);
+
+ return NS_OK;
+ }
+};
+
+//-----------------------------------------------------------------------------
+
+ObjectWatcher::ObjectWatcher() : watch_(nullptr) {}
+
+ObjectWatcher::~ObjectWatcher() { StopWatching(); }
+
+bool ObjectWatcher::StartWatching(HANDLE object, Delegate* delegate) {
+ if (watch_) {
+ NOTREACHED() << "Already watching an object";
+ return false;
+ }
+
+ RefPtr<Watch> watch = new Watch;
+ watch->watcher = this;
+ watch->object = object;
+ watch->origin_loop = MessageLoop::current();
+ watch->delegate = delegate;
+ watch->did_signal = false;
+
+ // Since our job is to just notice when an object is signaled and report the
+ // result back to this thread, we can just run on a Windows wait thread.
+ DWORD wait_flags = WT_EXECUTEDEFAULT | WT_EXECUTEONLYONCE;
+
+ if (!RegisterWaitForSingleObject(&watch->wait_object, object, DoneWaiting,
+ watch.get(), INFINITE, wait_flags)) {
+ NOTREACHED() << "RegisterWaitForSingleObject failed: " << GetLastError();
+ return false;
+ }
+
+ watch_ = watch.forget();
+
+ // We need to know if the current message loop is going away so we can
+ // prevent the wait thread from trying to access a dead message loop.
+ MessageLoop::current()->AddDestructionObserver(this);
+ return true;
+}
+
+bool ObjectWatcher::StopWatching() {
+ if (!watch_) return false;
+
+ // Make sure ObjectWatcher is used in a single-threaded fashion.
+ DCHECK(watch_->origin_loop == MessageLoop::current());
+
+ // If DoneWaiting is in progress, we wait for it to finish. We know whether
+ // DoneWaiting happened or not by inspecting the did_signal flag.
+ if (!UnregisterWaitEx(watch_->wait_object, INVALID_HANDLE_VALUE)) {
+ NOTREACHED() << "UnregisterWaitEx failed: " << GetLastError();
+ return false;
+ }
+
+ // Make sure that we see any mutation to did_signal. This should be a no-op
+ // since we expect that UnregisterWaitEx resulted in a memory barrier, but
+ // just to be sure, we're going to be explicit.
+ MemoryBarrier();
+
+ // If the watch has been posted, then we need to make sure it knows not to do
+ // anything once it is run.
+ watch_->watcher = NULL;
+
+ watch_ = nullptr;
+
+ MessageLoop::current()->RemoveDestructionObserver(this);
+ return true;
+}
+
+HANDLE ObjectWatcher::GetWatchedObject() {
+ if (!watch_) return NULL;
+
+ return watch_->object;
+}
+
+// static
+void CALLBACK ObjectWatcher::DoneWaiting(void* param, BOOLEAN timed_out) {
+ DCHECK(!timed_out);
+
+ Watch* watch = static_cast<Watch*>(param);
+ RefPtr<Watch> addrefedWatch = watch;
+
+ // Record that we ran this function.
+ watch->did_signal = true;
+
+ // We rely on the locking in PostTask() to ensure that a memory barrier is
+ // provided, which in turn ensures our change to did_signal can be observed
+ // on the target thread.
+ if (watch->origin_loop->IsAcceptingTasks()) {
+ watch->origin_loop->PostTask(addrefedWatch.forget());
+ }
+}
+
+void ObjectWatcher::WillDestroyCurrentMessageLoop() {
+ // Need to shutdown the watch so that we don't try to access the MessageLoop
+ // after this point.
+ StopWatching();
+}
+
+} // namespace base
diff --git a/ipc/chromium/src/base/object_watcher.h b/ipc/chromium/src/base/object_watcher.h
new file mode 100644
index 0000000000..1e1b27aa46
--- /dev/null
+++ b/ipc/chromium/src/base/object_watcher.h
@@ -0,0 +1,115 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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_OBJECT_WATCHER_H_
+#define BASE_OBJECT_WATCHER_H_
+
+#include <windows.h>
+#ifdef GetClassName
+# undef GetClassName
+#endif
+
+#include "base/message_loop.h"
+
+namespace base {
+
+// A class that provides a means to asynchronously wait for a Windows object to
+// become signaled. It is an abstraction around RegisterWaitForSingleObject
+// that provides a notification callback, OnObjectSignaled, that runs back on
+// the origin thread (i.e., the thread that called StartWatching).
+//
+// This class acts like a smart pointer such that when it goes out-of-scope,
+// UnregisterWaitEx is automatically called, and any in-flight notification is
+// suppressed.
+//
+// Typical usage:
+//
+// ```
+// class MyClass : public base::ObjectWatcher::Delegate {
+// public:
+// void DoStuffWhenSignaled(HANDLE object) {
+// watcher_.StartWatching(object, this);
+// }
+// virtual void OnObjectSignaled(HANDLE object) {
+// // OK, time to do stuff!
+// }
+// private:
+// base::ObjectWatcher watcher_;
+// };
+// ```
+//
+// In the above example, MyClass wants to "do stuff" when object becomes
+// signaled. ObjectWatcher makes this task easy. When MyClass goes out of
+// scope, the watcher_ will be destroyed, and there is no need to worry about
+// OnObjectSignaled being called on a deleted MyClass pointer. Easy!
+//
+//////
+//
+// Mozilla/Gecko addendum:
+//
+// An undocumented (but runtime-asserted) requirement for the above is that
+// `MyClass` must be strictly thread-affine. In particular, `StartWatching()`
+// and `StopWatching()` -- including the implicit `StopWatching()` call in
+// `~ObjectWatcher()` -- must always be called on the same thread and from
+// within the same `MessageLoop`.
+//
+// (If this did not hold, `OnObjectSignaled()` might be called on one thread
+// while `MyClass` is in the middle of being destroyed on another.)
+//
+// This condition cannot be guaranteed for potentially-asynchronously-destroyed
+// classes, nor for their owned or shared subobjects, nor for anything which
+// might be sent to a non-thread-affine task queue.
+//
+class ObjectWatcher : public MessageLoop::DestructionObserver {
+ public:
+ class Delegate {
+ public:
+ virtual ~Delegate() {}
+ // Called from the MessageLoop when a signaled object is detected. To
+ // continue watching the object, AddWatch must be called again.
+ virtual void OnObjectSignaled(HANDLE object) = 0;
+ };
+
+ ObjectWatcher();
+ ~ObjectWatcher();
+
+ // When the object is signaled, the given delegate is notified on the thread
+ // where StartWatching is called. The ObjectWatcher is not responsible for
+ // deleting the delegate.
+ //
+ // Returns true if the watch was started. Otherwise, false is returned.
+ //
+ bool StartWatching(HANDLE object, Delegate* delegate);
+
+ // Stops watching. Does nothing if the watch has already completed. If the
+ // watch is still active, then it is canceled, and the associated delegate is
+ // not notified.
+ //
+ // Returns true if the watch was canceled. Otherwise, false is returned.
+ //
+ bool StopWatching();
+
+ // Returns the handle of the object being watched, or NULL if the object
+ // watcher is stopped.
+ HANDLE GetWatchedObject();
+
+ private:
+ // Called on a background thread when done waiting.
+ static void CALLBACK DoneWaiting(void* param, BOOLEAN timed_out);
+
+ // MessageLoop::DestructionObserver implementation:
+ virtual void WillDestroyCurrentMessageLoop();
+
+ // Internal state.
+ class Watch;
+ RefPtr<Watch> watch_;
+
+ DISALLOW_COPY_AND_ASSIGN(ObjectWatcher);
+};
+
+} // namespace base
+
+#endif // BASE_OBJECT_WATCHER_H_
diff --git a/ipc/chromium/src/base/observer_list.h b/ipc/chromium/src/base/observer_list.h
new file mode 100644
index 0000000000..52b88329eb
--- /dev/null
+++ b/ipc/chromium/src/base/observer_list.h
@@ -0,0 +1,180 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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_OBSERVER_LIST_H__
+#define BASE_OBSERVER_LIST_H__
+
+#include <algorithm>
+#include <limits>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+#if defined(ANDROID) && defined(_STLP_STD_NAME)
+using _STLP_STD_NAME::find;
+#endif
+
+namespace base {
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// OVERVIEW:
+//
+// A container for a list of observers. Unlike a normal STL vector or list,
+// this container can be modified during iteration without invalidating the
+// iterator. So, it safely handles the case of an observer removing itself
+// or other observers from the list while observers are being notified.
+//
+// TYPICAL USAGE:
+//
+// class MyWidget {
+// public:
+// ...
+//
+// class Observer {
+// public:
+// virtual void OnFoo(MyWidget* w) = 0;
+// virtual void OnBar(MyWidget* w, int x, int y) = 0;
+// };
+//
+// void AddObserver(Observer* obs) {
+// observer_list_.AddObserver(obs);
+// }
+//
+// void RemoveObserver(Observer* obs) {
+// observer_list_.RemoveObserver(obs);
+// }
+//
+// void NotifyFoo() {
+// FOR_EACH_OBSERVER(Observer, observer_list_, OnFoo(this));
+// }
+//
+// void NotifyBar(int x, int y) {
+// FOR_EACH_OBSERVER(Observer, observer_list_, OnBar(this, x, y));
+// }
+//
+// private:
+// ObserverList<Observer> observer_list_;
+// };
+//
+//
+///////////////////////////////////////////////////////////////////////////////
+
+template <class ObserverType, bool check_empty = false>
+class ObserverList {
+ public:
+ // Enumeration of which observers are notified.
+ enum NotificationType {
+ // Specifies that any observers added during notification are notified.
+ // This is the default type if non type is provided to the constructor.
+ NOTIFY_ALL,
+
+ // Specifies that observers added while sending out notification are not
+ // notified.
+ NOTIFY_EXISTING_ONLY
+ };
+
+ ObserverList() : notify_depth_(0), type_(NOTIFY_ALL) {}
+ explicit ObserverList(NotificationType type)
+ : notify_depth_(0), type_(type) {}
+ ~ObserverList() {
+ // When check_empty is true, assert that the list is empty on destruction.
+ if (check_empty) {
+ Compact();
+ DCHECK_EQ(observers_.size(), 0U);
+ }
+ }
+
+ // Add an observer to the list.
+ void AddObserver(ObserverType* obs) {
+ DCHECK(find(observers_.begin(), observers_.end(), obs) == observers_.end())
+ << "Observers can only be added once!";
+ observers_.push_back(obs);
+ }
+
+ // Remove an observer from the list.
+ void RemoveObserver(ObserverType* obs) {
+ typename ListType::iterator it =
+ std::find(observers_.begin(), observers_.end(), obs);
+ if (it != observers_.end()) {
+ if (notify_depth_) {
+ *it = 0;
+ } else {
+ observers_.erase(it);
+ }
+ }
+ }
+
+ size_t size() const { return observers_.size(); }
+
+ ObserverType* GetElementAt(int index) const { return observers_[index]; }
+
+ // An iterator class that can be used to access the list of observers. See
+ // also the FOREACH_OBSERVER macro defined below.
+ class Iterator {
+ public:
+ explicit Iterator(const ObserverList<ObserverType>& list)
+ : list_(list),
+ index_(0),
+ max_index_(list.type_ == NOTIFY_ALL
+ ? std::numeric_limits<size_t>::max()
+ : list.observers_.size()) {
+ ++list_.notify_depth_;
+ }
+
+ ~Iterator() {
+ if (--list_.notify_depth_ == 0) list_.Compact();
+ }
+
+ ObserverType* GetNext() {
+ ListType& observers = list_.observers_;
+ // Advance if the current element is null
+ size_t max_index = std::min(max_index_, observers.size());
+ while (index_ < max_index && !observers[index_]) ++index_;
+ return index_ < max_index ? observers[index_++] : NULL;
+ }
+
+ private:
+ const ObserverList<ObserverType>& list_;
+ size_t index_;
+ size_t max_index_;
+ };
+
+ private:
+ typedef std::vector<ObserverType*> ListType;
+
+ void Compact() const {
+ typename ListType::iterator it = observers_.begin();
+ while (it != observers_.end()) {
+ if (*it) {
+ ++it;
+ } else {
+ it = observers_.erase(it);
+ }
+ }
+ }
+
+ // These are marked mutable to facilitate having NotifyAll be const.
+ mutable ListType observers_;
+ mutable int notify_depth_;
+ NotificationType type_;
+
+ friend class ObserverList::Iterator;
+
+ DISALLOW_EVIL_CONSTRUCTORS(ObserverList);
+};
+
+} // namespace base
+
+#define FOR_EACH_OBSERVER(ObserverType, observer_list, func) \
+ do { \
+ base::ObserverList<ObserverType>::Iterator it(observer_list); \
+ ObserverType* obs; \
+ while ((obs = it.GetNext()) != NULL) obs->func; \
+ } while (0)
+
+#endif // BASE_OBSERVER_LIST_H__
diff --git a/ipc/chromium/src/base/pickle.cc b/ipc/chromium/src/base/pickle.cc
new file mode 100644
index 0000000000..fa72edca20
--- /dev/null
+++ b/ipc/chromium/src/base/pickle.cc
@@ -0,0 +1,525 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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 "base/pickle.h"
+
+#include "mozilla/Alignment.h"
+#include "mozilla/CheckedInt.h"
+#include "mozilla/EndianUtils.h"
+#include "mozilla/Telemetry.h"
+#include "mozilla/ipc/ProtocolUtils.h"
+
+#include <stdlib.h>
+
+#include <limits>
+#include <string>
+#include <algorithm>
+#include <type_traits>
+
+#include "nsDebug.h"
+
+//------------------------------------------------------------------------------
+
+static_assert(MOZ_ALIGNOF(Pickle::memberAlignmentType) >= MOZ_ALIGNOF(uint32_t),
+ "Insufficient alignment");
+
+static const uint32_t kHeaderSegmentCapacity = 64;
+
+static const uint32_t kDefaultSegmentCapacity = 4096;
+
+static const char kBytePaddingMarker = char(0xbf);
+
+namespace {
+
+// We want to copy data to our payload as efficiently as possible.
+// memcpy fits the bill for copying, but not all compilers or
+// architectures support inlining memcpy from void*, which has unknown
+// static alignment. However, we know that all the members of our
+// payload will be aligned on memberAlignmentType boundaries. We
+// therefore use that knowledge to construct a copier that will copy
+// efficiently (via standard C++ assignment mechanisms) if the datatype
+// needs that alignment or less, and memcpy otherwise. (The compiler
+// may still inline memcpy, of course.)
+
+template <typename T, size_t size, bool hasSufficientAlignment>
+struct Copier {
+ static void Copy(T* dest, const char* iter) { memcpy(dest, iter, sizeof(T)); }
+};
+
+// Copying 64-bit quantities happens often enough and can easily be made
+// worthwhile on 32-bit platforms, so handle it specially. Only do it
+// if 64-bit types aren't sufficiently aligned; the alignment
+// requirements for them vary between 32-bit platforms.
+#ifndef HAVE_64BIT_BUILD
+template <typename T>
+struct Copier<T, sizeof(uint64_t), false> {
+ static void Copy(T* dest, const char* iter) {
+# if MOZ_LITTLE_ENDIAN
+ static const int loIndex = 0, hiIndex = 1;
+# else
+ static const int loIndex = 1, hiIndex = 0;
+# endif
+ static_assert(MOZ_ALIGNOF(uint32_t*) == MOZ_ALIGNOF(void*),
+ "Pointers have different alignments");
+ const uint32_t* src = reinterpret_cast<const uint32_t*>(iter);
+ uint32_t* uint32dest = reinterpret_cast<uint32_t*>(dest);
+ uint32dest[loIndex] = src[loIndex];
+ uint32dest[hiIndex] = src[hiIndex];
+ }
+};
+#endif
+
+template <typename T, size_t size>
+struct Copier<T, size, true> {
+ static void Copy(T* dest, const char* iter) {
+ // The pointer ought to be properly aligned.
+ DCHECK_EQ((((uintptr_t)iter) & (MOZ_ALIGNOF(T) - 1)), 0);
+ *dest = *reinterpret_cast<const T*>(iter);
+ }
+};
+
+} // anonymous namespace
+
+PickleIterator::PickleIterator(const Pickle& pickle)
+ : iter_(pickle.buffers_.Iter()) {
+ iter_.Advance(pickle.buffers_, pickle.header_size_);
+}
+
+template <typename T>
+void PickleIterator::CopyInto(T* dest) {
+ static_assert(std::is_trivially_copyable<T>::value,
+ "Copied type must be a POD type");
+ Copier<T, sizeof(T),
+ (MOZ_ALIGNOF(T) <=
+ sizeof(Pickle::memberAlignmentType))>::Copy(dest, iter_.Data());
+}
+
+bool Pickle::IteratorHasRoomFor(const PickleIterator& iter,
+ uint32_t len) const {
+ // Make sure we don't get into trouble where AlignInt(len) == 0.
+ MOZ_RELEASE_ASSERT(len < 64);
+
+ return iter.iter_.HasRoomFor(AlignInt(len));
+}
+
+bool Pickle::HasBytesAvailable(const PickleIterator* iter, uint32_t len) const {
+ return iter->iter_.HasBytesAvailable(buffers_, len);
+}
+
+void Pickle::UpdateIter(PickleIterator* iter, uint32_t bytes) const {
+ // Make sure we don't get into trouble where AlignInt(bytes) == 0.
+ MOZ_RELEASE_ASSERT(bytes < 64);
+
+ iter->iter_.Advance(buffers_, AlignInt(bytes));
+}
+
+// Payload is sizeof(Pickle::memberAlignmentType) aligned.
+
+Pickle::Pickle(uint32_t header_size, size_t segment_capacity)
+ : buffers_(AlignInt(header_size),
+ segment_capacity ? segment_capacity : kHeaderSegmentCapacity,
+ segment_capacity ? segment_capacity : kDefaultSegmentCapacity),
+ header_(nullptr),
+ header_size_(AlignInt(header_size)) {
+ DCHECK(static_cast<memberAlignmentType>(header_size) >= sizeof(Header));
+ DCHECK(header_size_ <= kHeaderSegmentCapacity);
+ header_ = reinterpret_cast<Header*>(buffers_.Start());
+ header_->payload_size = 0;
+}
+
+Pickle::Pickle(uint32_t header_size, const char* data, uint32_t length)
+ : buffers_(length, AlignCapacity(length), kDefaultSegmentCapacity),
+ header_(nullptr),
+ header_size_(AlignInt(header_size)) {
+ DCHECK(static_cast<memberAlignmentType>(header_size) >= sizeof(Header));
+ DCHECK(header_size <= kHeaderSegmentCapacity);
+ MOZ_RELEASE_ASSERT(header_size <= length);
+
+ header_ = reinterpret_cast<Header*>(buffers_.Start());
+ memcpy(header_, data, length);
+}
+
+Pickle::Pickle(Pickle&& other)
+ : buffers_(std::move(other.buffers_)),
+ header_(other.header_),
+ header_size_(other.header_size_) {
+ other.header_ = nullptr;
+}
+
+Pickle::~Pickle() {}
+
+Pickle& Pickle::operator=(Pickle&& other) {
+ BufferList tmp = std::move(other.buffers_);
+ other.buffers_ = std::move(buffers_);
+ buffers_ = std::move(tmp);
+
+ // std::swap(buffers_, other.buffers_);
+ std::swap(header_, other.header_);
+ std::swap(header_size_, other.header_size_);
+ return *this;
+}
+
+void Pickle::CopyFrom(const Pickle& other) {
+ MOZ_ALWAYS_TRUE(buffers_.CopyFrom(other.buffers_));
+ MOZ_ASSERT(other.header_ ==
+ reinterpret_cast<const Header*>(other.buffers_.Start()));
+
+ header_ = reinterpret_cast<Header*>(buffers_.Start());
+ header_size_ = other.header_size_;
+}
+
+bool Pickle::ReadBool(PickleIterator* iter, bool* result) const {
+ int tmp;
+ if (!ReadScalar(iter, &tmp)) return false;
+
+ DCHECK(0 == tmp || 1 == tmp);
+ *result = tmp ? true : false;
+
+ return true;
+}
+
+bool Pickle::ReadInt16(PickleIterator* iter, int16_t* result) const {
+ return ReadScalar(iter, result);
+}
+
+bool Pickle::ReadUInt16(PickleIterator* iter, uint16_t* result) const {
+ return ReadScalar(iter, result);
+}
+
+bool Pickle::ReadInt(PickleIterator* iter, int* result) const {
+ return ReadScalar(iter, result);
+}
+
+// Always written as a 64-bit value since the size for this type can
+// differ between architectures.
+bool Pickle::ReadLong(PickleIterator* iter, long* result) const {
+ int64_t big_result;
+ if (!ReadScalar(iter, &big_result)) return false;
+
+ DCHECK(big_result <= LONG_MAX && big_result >= LONG_MIN);
+ *result = static_cast<long>(big_result);
+
+ return true;
+}
+
+// Always written as a 64-bit value since the size for this type can
+// differ between architectures.
+bool Pickle::ReadULong(PickleIterator* iter, unsigned long* result) const {
+ uint64_t big_result;
+ if (!ReadScalar(iter, &big_result)) return false;
+ DCHECK(big_result <= ULONG_MAX);
+ *result = static_cast<unsigned long>(big_result);
+
+ return true;
+}
+
+bool Pickle::ReadLength(PickleIterator* iter, int* result) const {
+ if (!ReadScalar(iter, result)) return false;
+ return ((*result) >= 0);
+}
+
+bool Pickle::ReadInt32(PickleIterator* iter, int32_t* result) const {
+ return ReadScalar(iter, result);
+}
+
+bool Pickle::ReadUInt32(PickleIterator* iter, uint32_t* result) const {
+ return ReadScalar(iter, result);
+}
+
+bool Pickle::ReadInt64(PickleIterator* iter, int64_t* result) const {
+ return ReadScalar(iter, result);
+}
+
+bool Pickle::ReadUInt64(PickleIterator* iter, uint64_t* result) const {
+ return ReadScalar(iter, result);
+}
+
+bool Pickle::ReadDouble(PickleIterator* iter, double* result) const {
+ return ReadScalar(iter, result);
+}
+
+// Always written as a 64-bit value since the size for this type can
+// differ between architectures.
+bool Pickle::ReadIntPtr(PickleIterator* iter, intptr_t* result) const {
+ DCHECK(iter);
+
+ int64_t big_result;
+ if (!ReadScalar(iter, &big_result)) return false;
+
+ DCHECK(big_result <= std::numeric_limits<intptr_t>::max() &&
+ big_result >= std::numeric_limits<intptr_t>::min());
+ *result = static_cast<intptr_t>(big_result);
+
+ return true;
+}
+
+bool Pickle::ReadUnsignedChar(PickleIterator* iter,
+ unsigned char* result) const {
+ return ReadScalar(iter, result);
+}
+
+bool Pickle::ReadString(PickleIterator* iter, std::string* result) const {
+ DCHECK(iter);
+
+ int len;
+ if (!ReadLength(iter, &len)) return false;
+
+ auto chars = mozilla::MakeUnique<char[]>(len);
+ if (!ReadBytesInto(iter, chars.get(), len)) {
+ return false;
+ }
+ result->assign(chars.get(), len);
+
+ return true;
+}
+
+bool Pickle::ReadWString(PickleIterator* iter, std::wstring* result) const {
+ DCHECK(iter);
+
+ int len;
+ if (!ReadLength(iter, &len)) return false;
+ // Avoid integer multiplication overflow.
+ if (len > INT_MAX / static_cast<int>(sizeof(wchar_t))) return false;
+
+ auto chars = mozilla::MakeUnique<wchar_t[]>(len);
+ if (!ReadBytesInto(iter, chars.get(), len * sizeof(wchar_t))) {
+ return false;
+ }
+ result->assign(chars.get(), len);
+
+ return true;
+}
+
+bool Pickle::ReadBytesInto(PickleIterator* iter, void* data,
+ uint32_t length) const {
+ if (AlignInt(length) < length) {
+ return false;
+ }
+
+ if (!buffers_.ReadBytes(iter->iter_, reinterpret_cast<char*>(data), length)) {
+ return false;
+ }
+
+ return iter->iter_.AdvanceAcrossSegments(buffers_, AlignInt(length) - length);
+}
+
+bool Pickle::IgnoreBytes(PickleIterator* iter, uint32_t length) const {
+ if (AlignInt(length) < length) {
+ return false;
+ }
+
+ return iter->iter_.AdvanceAcrossSegments(buffers_, AlignInt(length));
+}
+
+#ifdef MOZ_PICKLE_SENTINEL_CHECKING
+MOZ_NEVER_INLINE
+bool Pickle::ReadSentinel(PickleIterator* iter, uint32_t sentinel) const {
+ uint32_t found;
+ if (!ReadScalar(iter, &found)) {
+ return false;
+ }
+ return found == sentinel;
+}
+
+bool Pickle::IgnoreSentinel(PickleIterator* iter) const {
+ uint32_t found;
+ return ReadUInt32(iter, &found);
+}
+
+bool Pickle::WriteSentinel(uint32_t sentinel) { return WriteUInt32(sentinel); }
+#endif
+
+void Pickle::EndRead(PickleIterator& iter, uint32_t ipcMsgType) const {
+ // FIXME: Deal with the footer somehow...
+ // DCHECK(iter.iter_.Done());
+}
+
+void Pickle::Truncate(PickleIterator* iter) {
+ size_t dropped = buffers_.Truncate(iter->iter_);
+ header_->payload_size -= dropped;
+}
+
+static const char kBytePaddingData[4] = {
+ kBytePaddingMarker,
+ kBytePaddingMarker,
+ kBytePaddingMarker,
+ kBytePaddingMarker,
+};
+
+static void WritePadding(Pickle::BufferList& buffers, uint32_t padding) {
+ MOZ_RELEASE_ASSERT(padding <= 4);
+ if (padding) {
+ MOZ_ALWAYS_TRUE(buffers.WriteBytes(kBytePaddingData, padding));
+ }
+}
+
+void Pickle::BeginWrite(uint32_t length) {
+ // write at an alignment-aligned offset from the beginning of the header
+ uint32_t offset = AlignInt(header_->payload_size);
+ uint32_t padding = (header_size_ + offset) % sizeof(memberAlignmentType);
+ uint32_t new_size = offset + padding + AlignInt(length);
+ MOZ_RELEASE_ASSERT(new_size >= header_->payload_size);
+
+ DCHECK(intptr_t(header_) % sizeof(memberAlignmentType) == 0);
+
+#ifdef HAVE_64BIT_BUILD
+ DCHECK_LE(length, std::numeric_limits<uint32_t>::max());
+#endif
+
+ WritePadding(buffers_, padding);
+
+ DCHECK((header_size_ + header_->payload_size + padding) %
+ sizeof(memberAlignmentType) ==
+ 0);
+
+ header_->payload_size = new_size;
+}
+
+void Pickle::EndWrite(uint32_t length) {
+ uint32_t padding = AlignInt(length) - length;
+ WritePadding(buffers_, padding);
+}
+
+bool Pickle::WriteBool(bool value) { return WriteInt(value ? 1 : 0); }
+
+bool Pickle::WriteInt16(int16_t value) {
+ return WriteBytes(&value, sizeof(value));
+}
+
+bool Pickle::WriteUInt16(uint16_t value) {
+ return WriteBytes(&value, sizeof(value));
+}
+
+bool Pickle::WriteInt(int value) { return WriteBytes(&value, sizeof(value)); }
+
+bool Pickle::WriteLong(long value) {
+ // Always written as a 64-bit value since the size for this type can
+ // differ between architectures.
+ return WriteInt64(int64_t(value));
+}
+
+bool Pickle::WriteULong(unsigned long value) {
+ // Always written as a 64-bit value since the size for this type can
+ // differ between architectures.
+ return WriteUInt64(uint64_t(value));
+}
+
+bool Pickle::WriteInt32(int32_t value) {
+ return WriteBytes(&value, sizeof(value));
+}
+
+bool Pickle::WriteUInt32(uint32_t value) {
+ return WriteBytes(&value, sizeof(value));
+}
+
+bool Pickle::WriteInt64(int64_t value) {
+ return WriteBytes(&value, sizeof(value));
+}
+
+bool Pickle::WriteUInt64(uint64_t value) {
+ return WriteBytes(&value, sizeof(value));
+}
+
+bool Pickle::WriteDouble(double value) {
+ return WriteBytes(&value, sizeof(value));
+}
+
+bool Pickle::WriteIntPtr(intptr_t value) {
+ // Always written as a 64-bit value since the size for this type can
+ // differ between architectures.
+ return WriteInt64(int64_t(value));
+}
+
+bool Pickle::WriteUnsignedChar(unsigned char value) {
+ return WriteBytes(&value, sizeof(value));
+}
+
+bool Pickle::WriteBytesZeroCopy(void* data, uint32_t data_len,
+ uint32_t capacity) {
+ BeginWrite(data_len);
+
+ uint32_t new_capacity = AlignInt(capacity);
+#ifndef MOZ_MEMORY
+ if (new_capacity > capacity) {
+ // If the buffer we were given is not large enough to contain padding
+ // after the data, reallocate it to make it so. When using jemalloc,
+ // we're guaranteed the buffer size is going to be at least 4-bytes
+ // aligned, so we skip realloc altogether. Even with other allocators,
+ // the realloc is likely not necessary, but we don't take chances.
+ // At least with ASan, it does matter to realloc to inform ASan we're
+ // going to use more data from the buffer (and let it actually realloc
+ // if it needs to).
+ data = realloc(data, new_capacity);
+ }
+#endif
+
+ // Shouldn't fail, because we're using InfallibleAllocPolicy.
+ MOZ_ALWAYS_TRUE(buffers_.WriteBytesZeroCopy(reinterpret_cast<char*>(data),
+ data_len, new_capacity));
+
+ EndWrite(data_len);
+ return true;
+}
+
+bool Pickle::WriteBytes(const void* data, uint32_t data_len) {
+ BeginWrite(data_len);
+
+ MOZ_ALWAYS_TRUE(
+ buffers_.WriteBytes(reinterpret_cast<const char*>(data), data_len));
+
+ EndWrite(data_len);
+ return true;
+}
+
+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::WriteData(const char* data, uint32_t length) {
+ return WriteInt(length) && WriteBytes(data, length);
+}
+
+void Pickle::InputBytes(const char* data, uint32_t length) {
+ MOZ_ALWAYS_TRUE(buffers_.WriteBytes(data, length));
+}
+
+int32_t* Pickle::GetInt32PtrForTest(uint32_t offset) {
+ size_t pos = buffers_.Size() - offset;
+ BufferList::IterImpl iter(buffers_);
+ MOZ_RELEASE_ASSERT(iter.AdvanceAcrossSegments(buffers_, pos));
+ return reinterpret_cast<int32_t*>(iter.Data());
+}
+
+// static
+uint32_t Pickle::MessageSize(uint32_t header_size, const char* start,
+ const char* end) {
+ DCHECK(header_size == AlignInt(header_size));
+ DCHECK(header_size <=
+ static_cast<memberAlignmentType>(kHeaderSegmentCapacity));
+
+ if (end < start) return 0;
+ size_t length = static_cast<size_t>(end - start);
+ if (length < sizeof(Header)) return 0;
+
+ const Header* hdr = reinterpret_cast<const Header*>(start);
+ if (length < header_size) return 0;
+
+ mozilla::CheckedInt<uint32_t> sum(header_size);
+ sum += hdr->payload_size;
+
+ if (!sum.isValid()) return 0;
+
+ return sum.value();
+}
diff --git a/ipc/chromium/src/base/pickle.h b/ipc/chromium/src/base/pickle.h
new file mode 100644
index 0000000000..5f64880848
--- /dev/null
+++ b/ipc/chromium/src/base/pickle.h
@@ -0,0 +1,284 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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_PICKLE_H__
+#define BASE_PICKLE_H__
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/string16.h"
+
+#include "mozilla/Attributes.h"
+#include "mozilla/BufferList.h"
+#include "mozilla/mozalloc.h"
+#include "mozilla/TimeStamp.h"
+#if !defined(FUZZING) && (!defined(RELEASE_OR_BETA) || defined(DEBUG))
+# define MOZ_PICKLE_SENTINEL_CHECKING
+#endif
+class Pickle;
+class PickleIterator {
+ public:
+ explicit PickleIterator(const Pickle& pickle);
+
+ private:
+ friend class Pickle;
+
+ mozilla::BufferList<InfallibleAllocPolicy>::IterImpl iter_;
+
+ template <typename T>
+ void CopyInto(T* dest);
+};
+
+// 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 Pickle {
+ public:
+ ~Pickle();
+
+ Pickle() = delete;
+
+ // 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(uint32_t header_size, size_t segment_capacity = 0);
+
+ Pickle(uint32_t header_size, const char* data, uint32_t length);
+
+ Pickle(const Pickle& other) = delete;
+
+ Pickle(Pickle&& other);
+
+ // Performs a deep copy.
+ Pickle& operator=(const Pickle& other) = delete;
+
+ Pickle& operator=(Pickle&& other);
+
+ void CopyFrom(const Pickle& other);
+
+ // Returns the size of the Pickle's data.
+ uint32_t size() const { return header_size_ + header_->payload_size; }
+
+ typedef mozilla::BufferList<InfallibleAllocPolicy> BufferList;
+
+ const BufferList& Buffers() const { return buffers_; }
+
+ uint32_t CurrentSize() const { return buffers_.Size(); }
+
+ // 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.
+ [[nodiscard]] bool ReadBool(PickleIterator* iter, bool* result) const;
+ [[nodiscard]] bool ReadInt16(PickleIterator* iter, int16_t* result) const;
+ [[nodiscard]] bool ReadUInt16(PickleIterator* iter, uint16_t* result) const;
+ [[nodiscard]] bool ReadShort(PickleIterator* iter, short* result) const;
+ [[nodiscard]] bool ReadInt(PickleIterator* iter, int* result) const;
+ [[nodiscard]] bool ReadLong(PickleIterator* iter, long* result) const;
+ [[nodiscard]] bool ReadULong(PickleIterator* iter,
+ unsigned long* result) const;
+ [[nodiscard]] bool ReadInt32(PickleIterator* iter, int32_t* result) const;
+ [[nodiscard]] bool ReadUInt32(PickleIterator* iter, uint32_t* result) const;
+ [[nodiscard]] bool ReadInt64(PickleIterator* iter, int64_t* result) const;
+ [[nodiscard]] bool ReadUInt64(PickleIterator* iter, uint64_t* result) const;
+ [[nodiscard]] bool ReadDouble(PickleIterator* iter, double* result) const;
+ [[nodiscard]] bool ReadIntPtr(PickleIterator* iter, intptr_t* result) const;
+ [[nodiscard]] bool ReadUnsignedChar(PickleIterator* iter,
+ unsigned char* result) const;
+ [[nodiscard]] bool ReadString(PickleIterator* iter,
+ std::string* result) const;
+ [[nodiscard]] bool ReadWString(PickleIterator* iter,
+ std::wstring* result) const;
+ [[nodiscard]] bool ReadBytesInto(PickleIterator* iter, void* data,
+ uint32_t length) const;
+
+ // Safer version of ReadInt() checks for the result not being negative.
+ // Use it for reading the object sizes.
+ [[nodiscard]] bool ReadLength(PickleIterator* iter, int* result) const;
+
+ [[nodiscard]] bool IgnoreBytes(PickleIterator* iter, uint32_t length) const;
+
+ [[nodiscard]] bool ReadSentinel(PickleIterator* iter, uint32_t sentinel) const
+#ifdef MOZ_PICKLE_SENTINEL_CHECKING
+ ;
+#else
+ {
+ return true;
+ }
+#endif
+
+ template <class T>
+ [[nodiscard]] bool ReadScalar(PickleIterator* iter, T* result) const {
+ DCHECK(iter);
+
+ if (!IteratorHasRoomFor(*iter, sizeof(*result)))
+ return ReadBytesInto(iter, result, sizeof(*result));
+
+ iter->CopyInto(result);
+
+ UpdateIter(iter, sizeof(*result));
+ return true;
+ }
+
+ bool IgnoreSentinel(PickleIterator* iter) const
+#ifdef MOZ_PICKLE_SENTINEL_CHECKING
+ ;
+#else
+ {
+ return true;
+ }
+#endif
+
+ // NOTE: The message type optional parameter should _only_ be called from
+ // generated IPDL code, as it is used to trigger the IPC_READ_LATENCY_MS
+ // telemetry probe.
+ void EndRead(PickleIterator& iter, uint32_t ipcMessageType = 0) const;
+
+ // Returns true if the given iterator has at least |len| bytes remaining it,
+ // across all segments. If there is not that much data available, returns
+ // false. Generally used when reading a (len, data) pair from the message,
+ // before allocating |len| bytes of space, to ensure that reading |len| bytes
+ // will succeed.
+ bool HasBytesAvailable(const PickleIterator* iter, uint32_t len) const;
+
+ // Truncate the message at the current point, discarding any data after this
+ // point in the message.
+ void Truncate(PickleIterator* iter);
+
+ // 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);
+ bool WriteInt16(int16_t value);
+ bool WriteUInt16(uint16_t value);
+ bool WriteInt(int value);
+ bool WriteLong(long value);
+ bool WriteULong(unsigned long value);
+ bool WriteInt32(int32_t value);
+ bool WriteUInt32(uint32_t value);
+ bool WriteInt64(int64_t value);
+ bool WriteUInt64(uint64_t value);
+ bool WriteDouble(double value);
+ bool WriteIntPtr(intptr_t value);
+ bool WriteUnsignedChar(unsigned char value);
+ bool WriteString(const std::string& value);
+ bool WriteWString(const std::wstring& value);
+ bool WriteData(const char* data, uint32_t length);
+ bool WriteBytes(const void* data, uint32_t data_len);
+ // Takes ownership of data
+ bool WriteBytesZeroCopy(void* data, uint32_t data_len, uint32_t capacity);
+
+ bool WriteSentinel(uint32_t sentinel)
+#ifdef MOZ_PICKLE_SENTINEL_CHECKING
+ ;
+#else
+ {
+ return true;
+ }
+#endif
+
+ int32_t* GetInt32PtrForTest(uint32_t offset);
+
+ void InputBytes(const char* data, uint32_t length);
+
+ // Payload follows after allocation of Header (header size is customizable).
+ struct Header {
+ uint32_t payload_size; // Specifies the size of the payload.
+ };
+
+ // Returns the header, cast to a user-specified type T. The type T must be a
+ // subclass of Header and its size must correspond to the header_size passed
+ // to the Pickle constructor.
+ template <class T>
+ T* headerT() {
+ DCHECK(sizeof(T) == header_size_);
+ return static_cast<T*>(header_);
+ }
+ template <class T>
+ const T* headerT() const {
+ DCHECK(sizeof(T) == header_size_);
+ return static_cast<const T*>(header_);
+ }
+
+ typedef uint32_t memberAlignmentType;
+
+ protected:
+ uint32_t payload_size() const { return header_->payload_size; }
+
+ // Resizes the buffer for use when writing the specified amount of data. Call
+ // EndWrite with the given length to pad out for the next write.
+ void BeginWrite(uint32_t length);
+
+ // Completes the write operation by padding the data with poison bytes. Should
+ // be paired with BeginWrite, but it does not necessarily have to be called
+ // after the data is written.
+ void EndWrite(uint32_t length);
+
+ // Round 'bytes' up to the next multiple of 'alignment'. 'alignment' must be
+ // a power of 2.
+ template <uint32_t alignment>
+ struct ConstantAligner {
+ static uint32_t align(int bytes) {
+ static_assert((alignment & (alignment - 1)) == 0,
+ "alignment must be a power of two");
+ return (bytes + (alignment - 1)) & ~static_cast<uint32_t>(alignment - 1);
+ }
+ };
+
+ static uint32_t AlignInt(int bytes) {
+ return ConstantAligner<sizeof(memberAlignmentType)>::align(bytes);
+ }
+
+ static uint32_t AlignCapacity(int bytes) {
+ return ConstantAligner<kSegmentAlignment>::align(bytes);
+ }
+
+ // 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 PickleIterator& iter, uint32_t len) const;
+
+ // 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(memberAlignmentType).
+ void UpdateIter(PickleIterator* iter, uint32_t bytes) const;
+
+ // Figure out how big the message starting at range_start is. Returns 0 if
+ // there's no enough data to determine (i.e., if [range_start, range_end) does
+ // not contain enough of the message header to know the size).
+ static uint32_t MessageSize(uint32_t header_size, const char* range_start,
+ const char* range_end);
+
+ // Segments capacities are aligned to 8 bytes to ensure that all reads/writes
+ // at 8-byte aligned offsets will be on 8-byte aligned pointers.
+ static const uint32_t kSegmentAlignment = 8;
+
+ private:
+ friend class PickleIterator;
+
+ BufferList buffers_;
+ Header* header_;
+ uint32_t header_size_;
+};
+
+#endif // BASE_PICKLE_H__
diff --git a/ipc/chromium/src/base/platform_file.h b/ipc/chromium/src/base/platform_file.h
new file mode 100644
index 0000000000..2c03821539
--- /dev/null
+++ b/ipc/chromium/src/base/platform_file.h
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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_PLATFORM_FILE_H_
+#define BASE_PLATFORM_FILE_H_
+
+#if defined(XP_WIN)
+# include <windows.h>
+#endif
+
+#include <string>
+
+namespace base {
+
+#if defined(XP_WIN)
+typedef HANDLE PlatformFile;
+const PlatformFile kInvalidPlatformFileValue = INVALID_HANDLE_VALUE;
+#else
+typedef int PlatformFile;
+const PlatformFile kInvalidPlatformFileValue = -1;
+#endif
+
+enum PlatformFileFlags {
+ PLATFORM_FILE_OPEN = 1,
+ PLATFORM_FILE_CREATE = 2,
+ PLATFORM_FILE_OPEN_ALWAYS = 4, // May create a new file.
+ PLATFORM_FILE_CREATE_ALWAYS = 8, // May overwrite an old file.
+ PLATFORM_FILE_READ = 16,
+ PLATFORM_FILE_WRITE = 32,
+ PLATFORM_FILE_EXCLUSIVE_READ = 64, // EXCLUSIVE is opposite of Windows SHARE
+ PLATFORM_FILE_EXCLUSIVE_WRITE = 128,
+ PLATFORM_FILE_ASYNC = 256
+};
+
+// Creates or open the given file. If PLATFORM_FILE_OPEN_ALWAYS is used, and
+// |created| is provided, |created| will be set to true if the file was created
+// or to false in case the file was just opened.
+PlatformFile CreatePlatformFile(const std::wstring& name, int flags,
+ bool* created);
+
+} // namespace base
+
+#endif // BASE_PLATFORM_FILE_H_
diff --git a/ipc/chromium/src/base/platform_thread.h b/ipc/chromium/src/base/platform_thread.h
new file mode 100644
index 0000000000..f3a65e8797
--- /dev/null
+++ b/ipc/chromium/src/base/platform_thread.h
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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.
+
+// 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_PLATFORM_THREAD_H_
+#define BASE_PLATFORM_THREAD_H_
+
+#include "base/basictypes.h"
+
+// 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(XP_WIN)
+# include <windows.h>
+typedef DWORD PlatformThreadId;
+typedef void* PlatformThreadHandle; // HANDLE
+#else
+# include <pthread.h>
+typedef pthread_t PlatformThreadHandle;
+# if defined(XP_LINUX) || defined(XP_OPENBSD) || defined(XP_SOLARIS) || \
+ defined(__GLIBC__)
+# include <unistd.h>
+typedef pid_t PlatformThreadId;
+# elif defined(__DragonFly__) || defined(XP_FREEBSD) || defined(XP_NETBSD)
+# include <sys/types.h>
+typedef lwpid_t PlatformThreadId;
+# elif defined(XP_DARWIN)
+# include <mach/mach.h>
+typedef mach_port_t PlatformThreadId;
+# endif
+#endif
+
+// A namespace for low-level thread functions.
+class PlatformThread {
+ public:
+ // 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 a debugger. This has no effect otherwise.
+ static void SetName(const char* name);
+
+ // Implement this interface to run code on a background thread. Your
+ // ThreadMain method will be called on the newly created thread.
+ class Delegate {
+ public:
+ virtual ~Delegate() {}
+ virtual void ThreadMain() = 0;
+ };
+
+ // 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);
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(PlatformThread);
+};
+
+#endif // BASE_PLATFORM_THREAD_H_
diff --git a/ipc/chromium/src/base/platform_thread_mac.mm b/ipc/chromium/src/base/platform_thread_mac.mm
new file mode 100644
index 0000000000..32917ff11e
--- /dev/null
+++ b/ipc/chromium/src/base/platform_thread_mac.mm
@@ -0,0 +1,75 @@
+// 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 "base/platform_thread.h"
+
+#import <Foundation/Foundation.h>
+#include <dlfcn.h>
+
+#include "base/logging.h"
+#include "base/scoped_nsautorelease_pool.h"
+
+// A simple class that demonstrates our impressive ability to do nothing.
+@interface NoOp : NSObject
+
+// Does the deed. Or does it?
++ (void)noOp;
+
+@end
+
+@implementation NoOp
+
++ (void)noOp {
+}
+
+@end
+
+namespace base {
+
+// If Cocoa is to be used on more than one thread, it must know that the
+// application is multithreaded. Since it's possible to enter Cocoa code
+// from threads created by pthread_thread_create, Cocoa won't necessarily
+// be aware that the application is multithreaded. Spawning an NSThread is
+// enough to get Cocoa to set up for multithreaded operation, so this is done
+// if necessary before pthread_thread_create spawns any threads.
+//
+// http://developer.apple.com/documentation/Cocoa/Conceptual/Multithreading/CreatingThreads/chapter_4_section_4.html
+void InitThreading() {
+ // this is called early in startup, before the event loop, so provide
+ // an autorelease pool to prevent leaks here
+ ScopedNSAutoreleasePool pool;
+
+ static BOOL multithreaded = [NSThread isMultiThreaded];
+ if (!multithreaded) {
+ [NSThread detachNewThreadSelector:@selector(noOp)
+ toTarget:[NoOp class]
+ withObject:nil];
+ multithreaded = YES;
+
+ DCHECK([NSThread isMultiThreaded]);
+ }
+}
+
+} // namespace base
+
+// static
+void PlatformThread::SetName(const char* name) {
+ // pthread_setname_np is only available in 10.6 or later, so test
+ // for it at runtime.
+ int (*dynamic_pthread_setname_np)(const char*);
+ *reinterpret_cast<void**>(&dynamic_pthread_setname_np) =
+ dlsym(RTLD_DEFAULT, "pthread_setname_np");
+ if (!dynamic_pthread_setname_np) return;
+
+ // Mac OS X does not expose the length limit of the name, so
+ // hardcode it.
+ const int kMaxNameLength = 63;
+ std::string shortened_name = std::string(name).substr(0, kMaxNameLength);
+ // pthread_setname() fails (harmlessly) in the sandbox, ignore when it does.
+ // See http://crbug.com/47058
+
+ // The name parameter is copied thus it's safe to release it after calling.
+ // Checked against the bionic implementation in bionic/libc/bionic/pthread.c
+ dynamic_pthread_setname_np(shortened_name.c_str());
+}
diff --git a/ipc/chromium/src/base/platform_thread_posix.cc b/ipc/chromium/src/base/platform_thread_posix.cc
new file mode 100644
index 0000000000..d28abbc91f
--- /dev/null
+++ b/ipc/chromium/src/base/platform_thread_posix.cc
@@ -0,0 +1,151 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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 "base/platform_thread.h"
+
+#include <errno.h>
+#include <sched.h>
+
+#if defined(XP_DARWIN)
+# include <mach/mach.h>
+#elif defined(XP_NETBSD)
+# include <lwp.h>
+#elif defined(XP_LINUX)
+# include <sys/syscall.h>
+# include <sys/prctl.h>
+#endif
+
+#if !defined(XP_DARWIN)
+# include <unistd.h>
+#endif
+
+#if (defined(__DragonFly__) || defined(XP_FREEBSD) || defined(XP_OPENBSD)) && \
+ !defined(__GLIBC__)
+# include <pthread_np.h>
+#endif
+
+#include "nsThreadUtils.h"
+
+#if defined(XP_DARWIN)
+namespace base {
+void InitThreading();
+} // namespace base
+#endif
+
+static void* ThreadFunc(void* closure) {
+ PlatformThread::Delegate* delegate =
+ static_cast<PlatformThread::Delegate*>(closure);
+ delegate->ThreadMain();
+ return NULL;
+}
+
+// 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(XP_DARWIN)
+ mach_port_t port = mach_thread_self();
+ mach_port_deallocate(mach_task_self(), port);
+ return port;
+#elif defined(XP_LINUX)
+ return syscall(__NR_gettid);
+#elif defined(XP_OPENBSD) || defined(XP_SOLARIS) || defined(__GLIBC__)
+ return (intptr_t)(pthread_self());
+#elif defined(XP_NETBSD)
+ return _lwp_self();
+#elif defined(__DragonFly__)
+ return lwp_gettid();
+#elif defined(XP_FREEBSD)
+ return pthread_getthreadid_np();
+#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;
+}
+
+#ifndef XP_DARWIN
+// Mac is implemented in platform_thread_mac.mm.
+
+// static
+void PlatformThread::SetName(const char* name) {
+ // On linux we can get the thread names to show up in the debugger by setting
+ // the process name for the LWP. We don't want to do this for the main
+ // thread because that would rename the process, causing tools like killall
+ // to stop working.
+ if (PlatformThread::CurrentId() == getpid()) return;
+
+ // Using NS_SetCurrentThreadName, as opposed to using platform APIs directly,
+ // also sets the thread name on the PRThread wrapper, and allows us to
+ // retrieve it using PR_GetThreadName.
+ NS_SetCurrentThreadName(name);
+}
+#endif // !XP_DARWIN
+
+namespace {
+
+bool CreateThread(size_t stack_size, bool joinable,
+ PlatformThread::Delegate* delegate,
+ PlatformThreadHandle* thread_handle) {
+#if defined(XP_DARWIN)
+ base::InitThreading();
+#endif // XP_DARWIN
+
+ 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 (stack_size == 0) stack_size = nsIThreadManager::DEFAULT_STACK_SIZE;
+ pthread_attr_setstacksize(&attributes, stack_size);
+
+ success = !pthread_create(thread_handle, &attributes, ThreadFunc, delegate);
+
+ pthread_attr_destroy(&attributes);
+ return success;
+}
+
+} // anonymous namespace
+
+// 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) {
+ pthread_join(thread_handle, NULL);
+}
diff --git a/ipc/chromium/src/base/platform_thread_win.cc b/ipc/chromium/src/base/platform_thread_win.cc
new file mode 100644
index 0000000000..59eb45aff6
--- /dev/null
+++ b/ipc/chromium/src/base/platform_thread_win.cc
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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 "base/platform_thread.h"
+
+#include "base/logging.h"
+#include "base/win_util.h"
+
+#include "nsThreadUtils.h"
+
+namespace {
+
+DWORD __stdcall ThreadFunc(void* closure) {
+ PlatformThread::Delegate* delegate =
+ static_cast<PlatformThread::Delegate*>(closure);
+ delegate->ThreadMain();
+ return 0;
+}
+
+} // namespace
+
+// static
+PlatformThreadId PlatformThread::CurrentId() { return GetCurrentThreadId(); }
+
+// static
+void PlatformThread::YieldCurrentThread() { ::Sleep(0); }
+
+// static
+void PlatformThread::Sleep(int duration_ms) { ::Sleep(duration_ms); }
+
+// static
+void PlatformThread::SetName(const char* name) {
+ // Using NS_SetCurrentThreadName, as opposed to using platform APIs directly,
+ // also sets the thread name on the PRThread wrapper, and allows us to
+ // retrieve it using PR_GetThreadName.
+ NS_SetCurrentThreadName(name);
+}
+
+// static
+bool PlatformThread::Create(size_t stack_size, Delegate* delegate,
+ PlatformThreadHandle* thread_handle) {
+ unsigned int flags = 0;
+ if (stack_size > 0) {
+ flags = STACK_SIZE_PARAM_IS_A_RESERVATION;
+ } else {
+ stack_size = 0;
+ }
+
+ // Using CreateThread here vs _beginthreadex makes thread creation a bit
+ // faster and doesn't require the loader lock to be available. Our code will
+ // have to work running on CreateThread() threads anyway, since we run code
+ // on the Windows thread pool, etc. For some background on the difference:
+ // http://www.microsoft.com/msj/1099/win32/win321099.aspx
+ *thread_handle =
+ CreateThread(NULL, stack_size, ThreadFunc, delegate, flags, NULL);
+ return *thread_handle != NULL;
+}
+
+// static
+bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) {
+ PlatformThreadHandle thread_handle;
+ bool result = Create(stack_size, delegate, &thread_handle);
+ CloseHandle(thread_handle);
+ return result;
+}
+
+// static
+void PlatformThread::Join(PlatformThreadHandle thread_handle) {
+ DCHECK(thread_handle);
+
+ // Wait for the thread to exit. It should already have terminated but make
+ // sure this assumption is valid.
+ DWORD result = WaitForSingleObject(thread_handle, INFINITE);
+ DCHECK_EQ(WAIT_OBJECT_0, result);
+
+ CloseHandle(thread_handle);
+}
diff --git a/ipc/chromium/src/base/port.h b/ipc/chromium/src/base/port.h
new file mode 100644
index 0000000000..6006b56792
--- /dev/null
+++ b/ipc/chromium/src/base/port.h
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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_
+
+#include <stdarg.h>
+
+#ifdef _MSC_VER
+# 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)
+
+namespace base {
+
+// 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.
+
+// The C standard says that va_copy is a "macro", not a function. Trying to
+// use va_list as ref args to a function, as above, breaks some machines.
+#if defined(__GNUC__)
+# define base_va_copy(_a, _b) ::va_copy(_a, _b)
+#elif defined(_MSC_VER)
+# define base_va_copy(_a, _b) (_a = _b)
+#else
+# error No va_copy for your compiler
+#endif
+
+} // namespace base
+
+// Define an OS-neutral wrapper for shared library entry points
+#if defined(XP_WIN)
+# define API_CALL __stdcall
+#elif defined(XP_LINUX) || defined(XP_DARWIN)
+# define API_CALL
+#endif
+
+#endif // BASE_PORT_H_
diff --git a/ipc/chromium/src/base/process.h b/ipc/chromium/src/base/process.h
new file mode 100644
index 0000000000..006afc1d3f
--- /dev/null
+++ b/ipc/chromium/src/base/process.h
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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_PROCESS_H_
+#define BASE_PROCESS_H_
+
+#include "base/basictypes.h"
+
+#include <sys/types.h>
+#ifdef XP_WIN
+# include <windows.h>
+#endif
+
+namespace base {
+
+// ProcessHandle is a platform specific type which represents the underlying OS
+// handle to a process.
+// ProcessId is a number which identifies the process in the OS.
+#if defined(XP_WIN)
+typedef HANDLE ProcessHandle;
+typedef DWORD ProcessId;
+// inttypes.h-like macro for ProcessId formatting.
+# define PRIPID "lu"
+
+const ProcessHandle kInvalidProcessHandle = INVALID_HANDLE_VALUE;
+
+// In theory, on Windows, this is a valid process ID, but in practice they are
+// currently divisible by four. Process IDs share the kernel handle allocation
+// code and they are guaranteed to be divisible by four.
+// As this could change for process IDs we shouldn't generally rely on this
+// property, however even if that were to change, it seems safe to rely on this
+// particular value never being used.
+const ProcessId kInvalidProcessId = kuint32max;
+#else
+// On POSIX, our ProcessHandle will just be the PID.
+typedef pid_t ProcessHandle;
+typedef pid_t ProcessId;
+// inttypes.h-like macro for ProcessId formatting.
+# define PRIPID "d"
+
+const ProcessHandle kInvalidProcessHandle = -1;
+const ProcessId kInvalidProcessId = -1;
+#endif
+
+} // namespace base
+
+#endif // BASE_PROCESS_H_
diff --git a/ipc/chromium/src/base/process_util.h b/ipc/chromium/src/base/process_util.h
new file mode 100644
index 0000000000..45426d616e
--- /dev/null
+++ b/ipc/chromium/src/base/process_util.h
@@ -0,0 +1,342 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=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.
+
+// This file/namespace contains utility functions for enumerating, ending and
+// computing statistics of processes.
+
+#ifndef BASE_PROCESS_UTIL_H_
+#define BASE_PROCESS_UTIL_H_
+
+#include "base/basictypes.h"
+
+#if defined(XP_WIN)
+# include "mozilla/ipc/EnvironmentMap.h"
+# include <windows.h>
+# include <tlhelp32.h>
+#elif defined(XP_LINUX) || defined(__GLIBC__)
+# include <dirent.h>
+# include <limits.h>
+# include <sys/types.h>
+#elif defined(XP_DARWIN)
+# include <mach/mach.h>
+#endif
+
+#include <cstddef>
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/process.h"
+
+#include "mozilla/UniquePtr.h"
+#include "mozilla/Result.h"
+#include "mozilla/ResultVariant.h"
+
+#include "mozilla/ipc/LaunchError.h"
+
+#if defined(MOZ_ENABLE_FORKSERVER)
+# include "nsStringFwd.h"
+# include "mozilla/ipc/FileDescriptorShuffle.h"
+
+namespace mozilla {
+namespace ipc {
+class FileDescriptor;
+}
+} // namespace mozilla
+#endif
+
+#if defined(XP_DARWIN)
+struct kinfo_proc;
+#endif
+
+class CommandLine;
+
+namespace base {
+
+using mozilla::Err;
+using mozilla::Ok;
+using mozilla::Result;
+using mozilla::ipc::LaunchError;
+
+enum ProcessArchitecture {
+ PROCESS_ARCH_INVALID = 0x0,
+ PROCESS_ARCH_I386 = 0x1,
+ PROCESS_ARCH_X86_64 = 0x2,
+ PROCESS_ARCH_PPC = 0x4,
+ PROCESS_ARCH_PPC_64 = 0x8,
+ PROCESS_ARCH_ARM = 0x10,
+ PROCESS_ARCH_ARM_64 = 0x20
+};
+
+// A minimalistic but hopefully cross-platform set of exit codes.
+// Do not change the enumeration values or you will break third-party
+// installers.
+enum {
+ PROCESS_END_NORMAL_TERMINATON = 0,
+ PROCESS_END_KILLED_BY_USER = 1,
+ PROCESS_END_PROCESS_WAS_HUNG = 2
+};
+
+// Returns the id of the current process.
+ProcessId GetCurrentProcId();
+
+// Returns the ProcessHandle of the current process.
+ProcessHandle GetCurrentProcessHandle();
+
+// Converts a PID to a process handle. This handle must be closed by
+// CloseProcessHandle when you are done with it. Returns true on success.
+bool OpenProcessHandle(ProcessId pid, ProcessHandle* handle);
+
+// Converts a PID to a process handle. On Windows the handle is opened
+// with more access rights and must only be used by trusted code.
+// You have to close returned handle using CloseProcessHandle. Returns true
+// on success.
+bool OpenPrivilegedProcessHandle(ProcessId pid, ProcessHandle* handle);
+
+// Closes the process handle opened by OpenProcessHandle.
+void CloseProcessHandle(ProcessHandle process);
+
+// Returns the unique ID for the specified process. This is functionally the
+// same as Windows' GetProcessId(), but works on versions of Windows before
+// Win XP SP1 as well.
+ProcessId GetProcId(ProcessHandle process);
+
+#if defined(XP_UNIX)
+// Close all file descriptors, except for std{in,out,err} and those
+// for which the given function returns true. Only call this function
+// in a child process where you know that there aren't any other
+// threads.
+void CloseSuperfluousFds(void* aCtx, bool (*aShouldPreserve)(void*, int));
+
+typedef std::vector<std::pair<int, int> > file_handle_mapping_vector;
+typedef std::map<std::string, std::string> environment_map;
+
+// Deleter for the array of strings allocated within BuildEnvironmentArray.
+struct FreeEnvVarsArray {
+ void operator()(char** array);
+};
+
+typedef mozilla::UniquePtr<char*[], FreeEnvVarsArray> EnvironmentArray;
+#endif
+
+struct LaunchOptions {
+ // If true, wait for the process to terminate. Otherwise, return
+ // immediately.
+ bool wait = false;
+
+#if defined(XP_WIN)
+ bool start_hidden = false;
+
+ // Start as an independent process rather than a process that is closed by the
+ // parent job. This will pass the flag CREATE_BREAKAWAY_FROM_JOB.
+ bool start_independent = false;
+
+ // Environment variables to be applied in addition to the current
+ // process's environment, replacing them where necessary.
+ EnvironmentMap env_map;
+
+ std::vector<HANDLE> handles_to_inherit;
+#endif
+#if defined(XP_UNIX)
+ environment_map env_map;
+
+ // If non-null, specifies the entire environment to use for the
+ // child process, instead of inheriting from the parent; env_map is
+ // ignored in that case. Note that the strings are allocated using
+ // malloc (e.g., with strdup), but the array of pointers is
+ // allocated with new[] and is terminated with a null pointer.
+ EnvironmentArray full_env;
+
+ // If non-empty, set the child process's current working directory.
+ std::string workdir;
+
+ // A mapping of (src fd -> dest fd) to propagate into the child
+ // process. All other fds will be closed, except std{in,out,err}.
+ file_handle_mapping_vector fds_to_remap;
+#endif
+
+#if defined(MOZ_ENABLE_FORKSERVER)
+ bool use_forkserver = false;
+#endif
+
+#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
+ // These fields are used by the sandboxing code in SandboxLaunch.cpp.
+ // It's not ideal to have them here, but trying to abstract them makes
+ // it harder to serialize LaunchOptions for the fork server.
+ //
+ // (fork_flags holds extra flags for the clone() syscall, and
+ // sandbox_chroot indicates whether the child process will be given
+ // the ability to chroot() itself to an empty directory.)
+ int fork_flags = 0;
+ bool sandbox_chroot = false;
+#endif
+
+#ifdef XP_DARWIN
+ // On macOS 10.14+, disclaims responsibility for the child process
+ // with respect to privacy/security permission prompts and
+ // decisions. Ignored if not supported by the OS.
+ bool disclaim = false;
+# ifdef __aarch64__
+ // The architecture to launch when launching a "universal" binary.
+ // Note: the implementation only supports launching x64 child
+ // processes from arm64 parent processes.
+ uint32_t arch = PROCESS_ARCH_INVALID;
+# endif // __aarch64__
+#endif // XP_DARWIN
+};
+
+#if defined(XP_WIN)
+// Runs the given application name with the given command line. Normally, the
+// first command line argument should be the path to the process, and don't
+// forget to quote it.
+//
+// Example (including literal quotes)
+// cmdline = "c:\windows\explorer.exe" -foo "c:\bar\"
+//
+// If process_handle is non-NULL, the process handle of the launched app will be
+// stored there on a successful launch.
+// NOTE: In this case, the caller is responsible for closing the handle so
+// that it doesn't leak!
+Result<Ok, LaunchError> LaunchApp(const std::wstring& cmdline,
+ const LaunchOptions& options,
+ ProcessHandle* process_handle);
+
+Result<Ok, LaunchError> LaunchApp(const CommandLine& cl, const LaunchOptions&,
+ ProcessHandle* process_handle);
+#else
+// Runs the application specified in argv[0] with the command line argv.
+//
+// The pid will be stored in process_handle if that pointer is
+// non-null.
+//
+// Note that the first argument in argv must point to the filename,
+// and must be fully specified (i.e., this will not search $PATH).
+Result<Ok, LaunchError> LaunchApp(const std::vector<std::string>& argv,
+ LaunchOptions&& options,
+ ProcessHandle* process_handle);
+
+// Merge an environment map with the current environment.
+// Existing variables are overwritten by env_vars_to_set.
+EnvironmentArray BuildEnvironmentArray(const environment_map& env_vars_to_set);
+#endif
+
+#if defined(MOZ_ENABLE_FORKSERVER)
+/**
+ * Create and initialize a new process as a content process.
+ *
+ * This class is used only by the fork server.
+ * To create a new content process, two steps are
+ * - calling |ForkProcess()| to create a new process, and
+ * - calling |InitAppProcess()| in the new process, the child
+ * process, to initialize it for running WEB content later.
+ *
+ * The fork server can clean up it's resources in-between the first
+ * and second step, that is why two steps.
+ */
+class AppProcessBuilder {
+ public:
+ AppProcessBuilder();
+ // This function will fork a new process for use as a
+ // content processes.
+ bool ForkProcess(const std::vector<std::string>& argv,
+ LaunchOptions&& options, ProcessHandle* process_handle);
+ // This function will be called in the child process to initializes
+ // the environment of the content process. It should be called
+ // after the message loop of the main thread, to make sure the fork
+ // server is destroyed properly in the child process.
+ //
+ // The message loop may allocate resources like file descriptors.
+ // If this function is called before the end of the loop, the
+ // reosurces may be destroyed while the loop is still alive.
+ void InitAppProcess(int* argcp, char*** argvp);
+
+ private:
+ void ReplaceArguments(int* argcp, char*** argvp);
+
+ mozilla::ipc::FileDescriptorShuffle shuffle_;
+ std::vector<std::string> argv_;
+};
+
+void InitForkServerProcess();
+
+/**
+ * Make a FD not being closed when create a new content process.
+ *
+ * AppProcessBuilder would close most unrelated FDs for new content
+ * processes. You may want to reserve some of FDs to keep using them
+ * in content processes.
+ */
+void RegisterForkServerNoCloseFD(int aFd);
+#endif
+
+// Attempts to kill the process identified by the given process
+// entry structure, giving it the specified exit code.
+// Returns true if this is successful, false otherwise.
+bool KillProcess(ProcessHandle process, int exit_code);
+
+#ifdef XP_UNIX
+// Returns whether the given process has exited. If it returns true,
+// the process status has been consumed and `IsProcessDead` should not
+// be called again on the same process (like `waitpid`).
+//
+// In various error cases (e.g., the process doesn't exist or isn't a
+// child of this process) it will also return true to indicate that
+// the caller should give up and not try again.
+//
+// If the `blocking` parameter is set to true, this function will try
+// to block the calling thread indefinitely until the process exits.
+// This may not be possible (if the child is also being debugged by
+// the parent process, e.g. due to the crash reporter), in which case
+// it will return false and the caller will need to wait and retry.
+bool IsProcessDead(ProcessHandle handle, bool blocking = false);
+#endif
+
+} // namespace base
+
+namespace mozilla {
+
+class EnvironmentLog {
+ public:
+ template <size_t N>
+ explicit EnvironmentLog(const char (&varname)[N])
+ : EnvironmentLog(varname, N) {}
+
+ ~EnvironmentLog() {}
+
+ void print(const char* format, ...);
+
+ private:
+ explicit EnvironmentLog(const char* varname, size_t len);
+
+#if defined(XP_WIN)
+ std::wstring fname_;
+#else
+ std::string fname_;
+#endif
+
+ DISALLOW_EVIL_CONSTRUCTORS(EnvironmentLog);
+};
+
+#if defined(MOZ_ENABLE_FORKSERVER)
+typedef std::tuple<nsCString, nsCString> EnvVar;
+typedef std::tuple<mozilla::ipc::FileDescriptor, int> FdMapping;
+#endif
+
+} // namespace mozilla
+
+#if defined(XP_WIN)
+// Undo the windows.h damage
+# undef GetMessage
+# undef CreateEvent
+# undef GetClassName
+# undef GetBinaryType
+# undef RemoveDirectory
+# undef LoadImage
+# undef LoadIcon
+#endif
+
+#endif // BASE_PROCESS_UTIL_H_
diff --git a/ipc/chromium/src/base/process_util_linux.cc b/ipc/chromium/src/base/process_util_linux.cc
new file mode 100644
index 0000000000..4ea71906f2
--- /dev/null
+++ b/ipc/chromium/src/base/process_util_linux.cc
@@ -0,0 +1,368 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process_util.h"
+
+#include <string>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#if defined(MOZ_CODE_COVERAGE)
+# include "nsString.h"
+#endif
+
+#include "mozilla/ipc/LaunchError.h"
+
+#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
+# include "mozilla/SandboxLaunch.h"
+#endif
+
+#if defined(MOZ_ENABLE_FORKSERVER)
+# include <stdlib.h>
+# include <fcntl.h>
+# if defined(DEBUG)
+# include "base/message_loop.h"
+# endif
+# include "mozilla/ipc/ForkServiceChild.h"
+
+# include "mozilla/Unused.h"
+# include "mozilla/ScopeExit.h"
+# include "mozilla/ipc/ProcessUtils.h"
+# include "mozilla/ipc/SetProcessTitle.h"
+
+using namespace mozilla::ipc;
+#endif
+
+#if defined(MOZ_CODE_COVERAGE)
+# include "prenv.h"
+# include "mozilla/ipc/EnvironmentMap.h"
+#endif
+
+#include "base/command_line.h"
+#include "base/eintr_wrapper.h"
+#include "base/logging.h"
+#include "mozilla/ipc/FileDescriptor.h"
+#include "mozilla/ipc/FileDescriptorShuffle.h"
+#include "mozilla/UniquePtr.h"
+#include "mozilla/StaticPtr.h"
+#include "mozilla/Result.h"
+
+// WARNING: despite the name, this file is also used on the BSDs and
+// Solaris (basically, Unixes that aren't Mac OS), not just Linux.
+
+namespace {
+
+static mozilla::EnvironmentLog gProcessLog("MOZ_PROCESS_LOG");
+
+} // namespace
+
+namespace base {
+
+#if defined(MOZ_ENABLE_FORKSERVER)
+static mozilla::StaticAutoPtr<std::vector<int> > sNoCloseFDs;
+
+void RegisterForkServerNoCloseFD(int fd) {
+ if (!sNoCloseFDs) {
+ sNoCloseFDs = new std::vector<int>();
+ }
+ sNoCloseFDs->push_back(fd);
+}
+
+static bool IsNoCloseFd(int fd) {
+ if (!sNoCloseFDs) {
+ return false;
+ }
+ return std::any_of(sNoCloseFDs->begin(), sNoCloseFDs->end(),
+ [fd](int regfd) -> bool { return regfd == fd; });
+}
+
+AppProcessBuilder::AppProcessBuilder() {}
+
+static void ReplaceEnviroment(const LaunchOptions& options) {
+ for (auto& elt : options.env_map) {
+ setenv(elt.first.c_str(), elt.second.c_str(), 1);
+ }
+}
+
+bool AppProcessBuilder::ForkProcess(const std::vector<std::string>& argv,
+ LaunchOptions&& options,
+ ProcessHandle* process_handle) {
+ auto cleanFDs = mozilla::MakeScopeExit([&] {
+ for (auto& elt : options.fds_to_remap) {
+ auto fd = std::get<0>(elt);
+ close(fd);
+ }
+ });
+
+# if defined(XP_LINUX) && defined(MOZ_SANDBOX)
+ mozilla::SandboxLaunch launcher;
+ if (!launcher.Prepare(&options)) {
+ return false;
+ }
+# else
+ struct {
+ pid_t Fork() { return fork(); }
+ } launcher;
+# endif
+
+ argv_ = argv;
+ if (!shuffle_.Init(options.fds_to_remap)) {
+ return false;
+ }
+
+ // Avoid the content of the buffer being sent out by child processes
+ // repeatly.
+ fflush(stdout);
+ fflush(stderr);
+
+ pid_t pid = launcher.Fork();
+ // WARNING: if pid == 0, only async signal safe operations are permitted from
+ // here until exec or _exit.
+ //
+ // Specifically, heap allocation is not safe: the sandbox's fork substitute
+ // won't run the pthread_atfork handlers that fix up the malloc locks.
+
+ if (pid < 0) {
+ return false;
+ }
+
+ if (pid == 0) {
+ cleanFDs.release();
+ ReplaceEnviroment(options);
+ } else {
+ gProcessLog.print("==> process %d launched child process %d\n",
+ GetCurrentProcId(), pid);
+ if (options.wait) HANDLE_EINTR(waitpid(pid, 0, 0));
+ }
+
+ if (process_handle) *process_handle = pid;
+
+ return true;
+}
+
+void AppProcessBuilder::ReplaceArguments(int* argcp, char*** argvp) {
+ // Change argc & argv of main() with the arguments passing
+ // through IPC.
+ char** argv = new char*[argv_.size() + 1];
+ char** p = argv;
+ for (auto& elt : argv_) {
+ *p++ = strdup(elt.c_str());
+ }
+ *p = nullptr;
+ *argvp = argv;
+ *argcp = argv_.size();
+ mozilla::SetProcessTitle(argv_);
+}
+
+void AppProcessBuilder::InitAppProcess(int* argcp, char*** argvp) {
+ MOZ_ASSERT(MessageLoop::current() == nullptr,
+ "The message loop of the main thread should have been destroyed");
+
+ // The fork server handle SIGCHLD to read status of content
+ // processes to handle Zombies. But, it is not necessary for
+ // content processes.
+ signal(SIGCHLD, SIG_DFL);
+
+ for (const auto& fds : shuffle_.Dup2Sequence()) {
+ int fd = HANDLE_EINTR(dup2(fds.first, fds.second));
+ MOZ_RELEASE_ASSERT(fd == fds.second, "dup2 failed");
+ }
+
+ CloseSuperfluousFds(&shuffle_, [](void* ctx, int fd) {
+ return static_cast<decltype(&shuffle_)>(ctx)->MapsTo(fd) || IsNoCloseFd(fd);
+ });
+ // Without this, the destructor of |shuffle_| would try to close FDs
+ // created by it, but they have been closed by
+ // |CloseSuperfluousFds()|.
+ shuffle_.Forget();
+
+ ReplaceArguments(argcp, argvp);
+}
+
+static void InstallChildSignalHandler() {
+ // Eventually (bug 1752638) we'll want a real SIGCHLD handler, but
+ // for now, cause child processes to be automatically collected.
+ signal(SIGCHLD, SIG_IGN);
+}
+
+static void ReserveFileDescriptors() {
+ // Reserve the lower positions of the file descriptors to make sure
+ // debug files and other files don't take these positions. So we
+ // can keep their file descriptors during CloseSuperfluousFds() with
+ // out any confliction with mapping passing from the parent process.
+ int fd = open("/dev/null", O_RDONLY);
+ for (int i = 1; i < 10; i++) {
+ mozilla::Unused << dup(fd);
+ }
+}
+
+void InitForkServerProcess() {
+ InstallChildSignalHandler();
+ ReserveFileDescriptors();
+ SetThisProcessName("forkserver");
+}
+
+static Result<Ok, LaunchError> LaunchAppWithForkServer(
+ const std::vector<std::string>& argv, const LaunchOptions& options,
+ ProcessHandle* process_handle) {
+ MOZ_ASSERT(ForkServiceChild::Get());
+
+ // Check for unsupported options
+ MOZ_ASSERT(options.workdir.empty());
+ MOZ_ASSERT(!options.full_env);
+ MOZ_ASSERT(!options.wait);
+
+ ForkServiceChild::Args forkArgs;
+
+# if defined(XP_LINUX) && defined(MOZ_SANDBOX)
+ forkArgs.mForkFlags = options.fork_flags;
+ forkArgs.mChroot = options.sandbox_chroot;
+# endif
+
+ for (auto& arg : argv) {
+ forkArgs.mArgv.AppendElement(arg.c_str());
+ }
+ for (auto& vv : options.env_map) {
+ forkArgs.mEnv.AppendElement(mozilla::EnvVar(nsCString(vv.first.c_str()),
+ nsCString(vv.second.c_str())));
+ }
+ for (auto& fdmapping : options.fds_to_remap) {
+ forkArgs.mFdsRemap.AppendElement(mozilla::FdMapping(
+ mozilla::ipc::FileDescriptor(fdmapping.first), fdmapping.second));
+ }
+
+ return ForkServiceChild::Get()->SendForkNewSubprocess(forkArgs,
+ process_handle);
+}
+#endif // MOZ_ENABLE_FORKSERVER
+
+Result<Ok, LaunchError> LaunchApp(const std::vector<std::string>& argv,
+ LaunchOptions&& options,
+ ProcessHandle* process_handle) {
+#if defined(MOZ_ENABLE_FORKSERVER)
+ if (options.use_forkserver && ForkServiceChild::Get()) {
+ return LaunchAppWithForkServer(argv, options, process_handle);
+ }
+#endif
+
+ mozilla::UniquePtr<char*[]> argv_cstr(new char*[argv.size() + 1]);
+
+#if defined(XP_LINUX) && defined(MOZ_SANDBOX)
+ mozilla::SandboxLaunch launcher;
+ if (!launcher.Prepare(&options)) {
+ return Err(LaunchError("SL::Prepare", errno));
+ }
+#else
+ struct {
+ pid_t Fork() { return fork(); }
+ } launcher;
+#endif
+
+ EnvironmentArray env_storage;
+ const EnvironmentArray& envp =
+ options.full_env ? options.full_env
+ : (env_storage = BuildEnvironmentArray(options.env_map));
+
+ // Init() there will call fcntl(F_DUPFD/F_DUPFD_CLOEXEC) under the hood in
+ // https://searchfox.org/mozilla-central/rev/55d5c4b9dffe5e59eb6b019c1a930ec9ada47e10/ipc/glue/FileDescriptorShuffle.cpp#72
+ // so it will set errno.
+ mozilla::ipc::FileDescriptorShuffle shuffle;
+ if (!shuffle.Init(options.fds_to_remap)) {
+ CHROMIUM_LOG(WARNING) << "FileDescriptorShuffle::Init failed";
+ return Err(LaunchError("FileDescriptorShuffle", errno));
+ }
+
+#ifdef MOZ_CODE_COVERAGE
+ // Before gcc/clang 10 there is a gcda dump before the fork.
+ // This dump mustn't be interrupted by a SIGUSR1 else we may
+ // have a dead lock (see bug 1637377).
+ // So we just remove the handler and restore it after the fork
+ // It's up the child process to set it up.
+ // Once we switch to gcc/clang 10, we could just remove it in the child
+ // process
+ void (*ccovSigHandler)(int) = signal(SIGUSR1, SIG_IGN);
+ const char* gcov_child_prefix = PR_GetEnv("GCOV_CHILD_PREFIX");
+#endif
+
+ pid_t pid = launcher.Fork();
+ // WARNING: if pid == 0, only async signal safe operations are permitted from
+ // here until exec or _exit.
+ //
+ // Specifically, heap allocation is not safe: the sandbox's fork substitute
+ // won't run the pthread_atfork handlers that fix up the malloc locks.
+
+ if (pid < 0) {
+ CHROMIUM_LOG(WARNING) << "fork() failed: " << strerror(errno);
+ return Err(LaunchError("fork", errno));
+ }
+
+ if (pid == 0) {
+ // In the child:
+ if (!options.workdir.empty()) {
+ if (chdir(options.workdir.c_str()) != 0) {
+ // See under execve about logging unsafety.
+ DLOG(ERROR) << "chdir failed " << options.workdir;
+ _exit(127);
+ }
+ }
+
+ for (const auto& fds : shuffle.Dup2Sequence()) {
+ if (HANDLE_EINTR(dup2(fds.first, fds.second)) != fds.second) {
+ // This shouldn't happen, but check for it. And see below
+ // about logging being unsafe here, so this is debug only.
+ DLOG(ERROR) << "dup2 failed";
+ _exit(127);
+ }
+ }
+
+ CloseSuperfluousFds(&shuffle, [](void* aCtx, int aFd) {
+ return static_cast<decltype(&shuffle)>(aCtx)->MapsTo(aFd);
+ });
+
+ for (size_t i = 0; i < argv.size(); i++)
+ argv_cstr[i] = const_cast<char*>(argv[i].c_str());
+ argv_cstr[argv.size()] = NULL;
+
+#ifdef MOZ_CODE_COVERAGE
+ if (gcov_child_prefix && !options.full_env) {
+ const pid_t child_pid = getpid();
+ nsAutoCString new_gcov_prefix(gcov_child_prefix);
+ new_gcov_prefix.Append(std::to_string((size_t)child_pid));
+ EnvironmentMap new_map = options.env_map;
+ new_map[ENVIRONMENT_LITERAL("GCOV_PREFIX")] =
+ ENVIRONMENT_STRING(new_gcov_prefix.get());
+ // FIXME(bug 1783305): this won't work if full_env is set, and
+ // in general this block of code is doing things it shouldn't
+ // be (async signal unsafety).
+ env_storage = BuildEnvironmentArray(new_map);
+ }
+#endif
+
+ execve(argv_cstr[0], argv_cstr.get(), envp.get());
+ // if we get here, we're in serious trouble and should complain loudly
+ // NOTE: This is async signal unsafe; it could deadlock instead. (But
+ // only on debug builds; otherwise it's a signal-safe no-op.)
+ DLOG(ERROR) << "FAILED TO exec() CHILD PROCESS, path: " << argv_cstr[0];
+ _exit(127);
+ }
+
+ // In the parent:
+
+#ifdef MOZ_CODE_COVERAGE
+ // Restore the handler for SIGUSR1
+ signal(SIGUSR1, ccovSigHandler);
+#endif
+
+ gProcessLog.print("==> process %d launched child process %d\n",
+ GetCurrentProcId(), pid);
+ if (options.wait) HANDLE_EINTR(waitpid(pid, 0, 0));
+
+ if (process_handle) *process_handle = pid;
+
+ return Ok();
+}
+
+} // namespace base
diff --git a/ipc/chromium/src/base/process_util_mac.mm b/ipc/chromium/src/base/process_util_mac.mm
new file mode 100644
index 0000000000..d3c91ee362
--- /dev/null
+++ b/ipc/chromium/src/base/process_util_mac.mm
@@ -0,0 +1,167 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/process_util.h"
+
+#include <fcntl.h>
+#include <os/availability.h>
+#include <spawn.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <string>
+
+#include "base/command_line.h"
+#include "base/eintr_wrapper.h"
+#include "base/logging.h"
+#include "mozilla/ipc/FileDescriptorShuffle.h"
+#include "mozilla/ScopeExit.h"
+#include "mozilla/Result.h"
+
+#include "mozilla/ipc/LaunchError.h"
+
+extern "C" {
+// N.B. the syscalls are available back to 10.5, but the C wrappers
+// only in 10.12. Fortunately, 10.15 is our current baseline.
+int pthread_fchdir_np(int fd) API_AVAILABLE(macosx(10.12));
+
+int responsibility_spawnattrs_setdisclaim(posix_spawnattr_t attrs, int disclaim)
+ API_AVAILABLE(macosx(10.14));
+}
+
+namespace {
+
+static mozilla::EnvironmentLog gProcessLog("MOZ_PROCESS_LOG");
+
+} // namespace
+
+namespace base {
+
+Result<Ok, LaunchError> LaunchApp(const std::vector<std::string>& argv,
+ LaunchOptions&& options,
+ ProcessHandle* process_handle) {
+ Result<Ok, LaunchError> retval = Ok();
+
+ char* argv_copy[argv.size() + 1];
+ for (size_t i = 0; i < argv.size(); i++) {
+ argv_copy[i] = const_cast<char*>(argv[i].c_str());
+ }
+ argv_copy[argv.size()] = NULL;
+
+ EnvironmentArray env_storage;
+ const EnvironmentArray& vars =
+ options.full_env ? options.full_env
+ : (env_storage = BuildEnvironmentArray(options.env_map));
+
+ posix_spawn_file_actions_t file_actions;
+ int err = posix_spawn_file_actions_init(&file_actions);
+ if (err != 0) {
+ DLOG(WARNING) << "posix_spawn_file_actions_init failed";
+ return Err(LaunchError("posix_spawn_file_actions_init", err));
+ }
+ auto file_actions_guard = mozilla::MakeScopeExit(
+ [&file_actions] { posix_spawn_file_actions_destroy(&file_actions); });
+
+ // Turn fds_to_remap array into a set of dup2 calls.
+ //
+ // Init() there will call fcntl(F_DUPFD/F_DUPFD_CLOEXEC) under the hood in
+ // https://searchfox.org/mozilla-central/rev/55d5c4b9dffe5e59eb6b019c1a930ec9ada47e10/ipc/glue/FileDescriptorShuffle.cpp#72
+ // so it will set errno.
+ mozilla::ipc::FileDescriptorShuffle shuffle;
+ if (!shuffle.Init(options.fds_to_remap)) {
+ DLOG(WARNING) << "FileDescriptorShuffle::Init failed";
+ return Err(LaunchError("FileDescriptorShuffle", errno));
+ }
+ for (const auto& fd_map : shuffle.Dup2Sequence()) {
+ int src_fd = fd_map.first;
+ int dest_fd = fd_map.second;
+
+ int rv = posix_spawn_file_actions_adddup2(&file_actions, src_fd, dest_fd);
+ if (rv != 0) {
+ DLOG(WARNING) << "posix_spawn_file_actions_adddup2 failed";
+ return Err(LaunchError("posix_spawn_file_actions_adddup2", rv));
+ }
+ }
+
+ if (!options.workdir.empty()) {
+ int rv = posix_spawn_file_actions_addchdir_np(&file_actions,
+ options.workdir.c_str());
+ if (rv != 0) {
+ DLOG(WARNING) << "posix_spawn_file_actions_addchdir_np failed";
+ return Err(LaunchError("posix_spawn_file_actions_addchdir", rv));
+ }
+ }
+
+ // Initialize spawn attributes.
+ posix_spawnattr_t spawnattr;
+ err = posix_spawnattr_init(&spawnattr);
+ if (err != 0) {
+ DLOG(WARNING) << "posix_spawnattr_init failed";
+ return Err(LaunchError("posix_spawnattr_init", err));
+ }
+ auto spawnattr_guard = mozilla::MakeScopeExit(
+ [&spawnattr] { posix_spawnattr_destroy(&spawnattr); });
+
+#if defined(XP_MACOSX) && defined(__aarch64__)
+ if (options.arch == PROCESS_ARCH_X86_64) {
+ cpu_type_t cpu_pref = CPU_TYPE_X86_64;
+ size_t count = 1;
+ size_t ocount = 0;
+ int rv =
+ posix_spawnattr_setbinpref_np(&spawnattr, count, &cpu_pref, &ocount);
+ if ((rv != 0) || (ocount != count)) {
+ DLOG(WARNING) << "posix_spawnattr_setbinpref_np failed";
+ return Err(LaunchError("posix_spawnattr_setbinpref_np", rv));
+ }
+ }
+#endif
+
+ if (options.disclaim) {
+ int err = responsibility_spawnattrs_setdisclaim(&spawnattr, 1);
+ if (err != 0) {
+ DLOG(WARNING) << "responsibility_spawnattrs_setdisclaim failed";
+ return Err(LaunchError("responsibility_spawnattrs_setdisclaim", err));
+ }
+ }
+
+ // Prevent the child process from inheriting any file descriptors
+ // that aren't named in `file_actions`. (This is an Apple-specific
+ // extension to posix_spawn.)
+ err = posix_spawnattr_setflags(&spawnattr, POSIX_SPAWN_CLOEXEC_DEFAULT);
+ if (err != 0) {
+ DLOG(WARNING) << "posix_spawnattr_setflags failed";
+ return Err(LaunchError("posix_spawnattr_setflags", err));
+ }
+
+ // Exempt std{in,out,err} from being closed by POSIX_SPAWN_CLOEXEC_DEFAULT.
+ for (int fd = 0; fd <= STDERR_FILENO; ++fd) {
+ err = posix_spawn_file_actions_addinherit_np(&file_actions, fd);
+ if (err != 0) {
+ DLOG(WARNING) << "posix_spawn_file_actions_addinherit_np failed";
+ return Err(LaunchError("posix_spawn_file_actions_addinherit_np", err));
+ }
+ }
+
+ int pid = 0;
+ int spawn_succeeded = (posix_spawnp(&pid, argv_copy[0], &file_actions,
+ &spawnattr, argv_copy, vars.get()) == 0);
+
+ bool process_handle_valid = pid > 0;
+ if (!spawn_succeeded || !process_handle_valid) {
+ DLOG(WARNING) << "posix_spawnp failed";
+ retval = Err(LaunchError("posix_spawnp", spawn_succeeded));
+ } else {
+ gProcessLog.print("==> process %d launched child process %d\n",
+ GetCurrentProcId(), pid);
+ if (options.wait) HANDLE_EINTR(waitpid(pid, 0, 0));
+
+ if (process_handle) *process_handle = pid;
+ }
+
+ return retval;
+}
+
+} // namespace base
diff --git a/ipc/chromium/src/base/process_util_posix.cc b/ipc/chromium/src/base/process_util_posix.cc
new file mode 100644
index 0000000000..3229570ad8
--- /dev/null
+++ b/ipc/chromium/src/base/process_util_posix.cc
@@ -0,0 +1,388 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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 <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <limits>
+#include <set>
+
+#include "base/basictypes.h"
+#include "base/command_line.h"
+#include "base/eintr_wrapper.h"
+#include "base/logging.h"
+#include "base/platform_thread.h"
+#include "base/process_util.h"
+#include "base/time.h"
+#include "base/waitable_event.h"
+#include "base/dir_reader_posix.h"
+
+#include "mozilla/UniquePtr.h"
+#include "mozilla/Unused.h"
+// For PR_DuplicateEnvironment:
+#include "prenv.h"
+#include "prmem.h"
+
+#ifdef MOZ_ENABLE_FORKSERVER
+# include "mozilla/ipc/ForkServiceChild.h"
+#endif
+
+// We could configure-test for `waitid`, but it's been in POSIX for a
+// long time and OpenBSD seems to be the only Unix we target that
+// doesn't have it. Note that `waitid` is used to resolve a conflict
+// with the crash reporter, which isn't available on OpenBSD.
+#ifndef __OpenBSD__
+# define HAVE_WAITID
+#endif
+
+namespace base {
+
+ProcessId GetCurrentProcId() { return getpid(); }
+
+ProcessHandle GetCurrentProcessHandle() { return GetCurrentProcId(); }
+
+bool OpenProcessHandle(ProcessId pid, ProcessHandle* handle) {
+ // On Posix platforms, process handles are the same as PIDs, so we
+ // don't need to do anything.
+ *handle = pid;
+ return true;
+}
+
+bool OpenPrivilegedProcessHandle(ProcessId pid, ProcessHandle* handle) {
+ // On POSIX permissions are checked for each operation on process,
+ // not when opening a "handle".
+ return OpenProcessHandle(pid, handle);
+}
+
+void CloseProcessHandle(ProcessHandle process) {
+ // See OpenProcessHandle, nothing to do.
+ return;
+}
+
+ProcessId GetProcId(ProcessHandle process) { return process; }
+
+// Attempts to kill the process identified by the given process
+// entry structure. Ignores specified exit_code; posix can't force that.
+// Returns true if this is successful, false otherwise.
+bool KillProcess(ProcessHandle process_id, int exit_code) {
+ // It's too easy to accidentally kill pid 0 (meaning the caller's
+ // process group) or pid -1 (all other processes killable by this
+ // user), and neither they nor other negative numbers (process
+ // groups) are legitimately used by this function's callers, so
+ // reject them all.
+ if (process_id <= 0) {
+ CHROMIUM_LOG(WARNING) << "base::KillProcess refusing to kill pid "
+ << process_id;
+ return false;
+ }
+
+ bool result = kill(process_id, SIGTERM) == 0;
+
+ if (!result && (errno == ESRCH)) {
+ result = true;
+ }
+
+ if (!result) DLOG(ERROR) << "Unable to terminate process.";
+
+ return result;
+}
+
+#ifdef ANDROID
+typedef unsigned long int rlim_t;
+#endif
+
+// A class to handle auto-closing of DIR*'s.
+class ScopedDIRClose {
+ public:
+ inline void operator()(DIR* x) const {
+ if (x) {
+ closedir(x);
+ }
+ }
+};
+typedef mozilla::UniquePtr<DIR, ScopedDIRClose> ScopedDIR;
+
+void CloseSuperfluousFds(void* aCtx, bool (*aShouldPreserve)(void*, int)) {
+ // DANGER: no calls to malloc (or locks, etc.) are allowed from now on:
+ // https://crbug.com/36678
+ // Also, beware of STL iterators: https://crbug.com/331459
+#if defined(ANDROID)
+ static const rlim_t kSystemDefaultMaxFds = 1024;
+ static const char kFDDir[] = "/proc/self/fd";
+#elif defined(XP_LINUX) || defined(XP_SOLARIS)
+ static const rlim_t kSystemDefaultMaxFds = 8192;
+ static const char kFDDir[] = "/proc/self/fd";
+#elif defined(XP_DARWIN)
+ static const rlim_t kSystemDefaultMaxFds = 256;
+ static const char kFDDir[] = "/dev/fd";
+#elif defined(__DragonFly__) || defined(XP_FREEBSD) || defined(XP_NETBSD) || \
+ defined(XP_OPENBSD)
+ // the getrlimit below should never fail, so whatever ..
+ static const rlim_t kSystemDefaultMaxFds = 1024;
+ // at least /dev/fd will exist
+ static const char kFDDir[] = "/dev/fd";
+#endif
+
+ // Get the maximum number of FDs possible.
+ struct rlimit nofile;
+ rlim_t max_fds;
+ if (getrlimit(RLIMIT_NOFILE, &nofile)) {
+ // getrlimit failed. Take a best guess.
+ max_fds = kSystemDefaultMaxFds;
+ DLOG(ERROR) << "getrlimit(RLIMIT_NOFILE) failed: " << errno;
+ } else {
+ max_fds = nofile.rlim_cur;
+ }
+
+ if (max_fds > INT_MAX) max_fds = INT_MAX;
+
+ DirReaderPosix fd_dir(kFDDir);
+
+ if (!fd_dir.IsValid()) {
+ // Fallback case: Try every possible fd.
+ for (rlim_t i = 0; i < max_fds; ++i) {
+ const int fd = static_cast<int>(i);
+ if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO ||
+ aShouldPreserve(aCtx, fd)) {
+ continue;
+ }
+
+ // Since we're just trying to close anything we can find,
+ // ignore any error return values of close().
+ close(fd);
+ }
+ return;
+ }
+
+ const int dir_fd = fd_dir.fd();
+
+ for (; fd_dir.Next();) {
+ // Skip . and .. entries.
+ if (fd_dir.name()[0] == '.') continue;
+
+ char* endptr;
+ errno = 0;
+ const long int fd = strtol(fd_dir.name(), &endptr, 10);
+ if (fd_dir.name()[0] == 0 || *endptr || fd < 0 || errno) continue;
+ if (fd == dir_fd) continue;
+ if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO ||
+ aShouldPreserve(aCtx, fd)) {
+ continue;
+ }
+
+ // When running under Valgrind, Valgrind opens several FDs for its
+ // own use and will complain if we try to close them. All of
+ // these FDs are >= |max_fds|, so we can check against that here
+ // before closing. See https://bugs.kde.org/show_bug.cgi?id=191758
+ if (fd < static_cast<int>(max_fds)) {
+ int ret = IGNORE_EINTR(close(fd));
+ if (ret != 0) {
+ DLOG(ERROR) << "Problem closing fd";
+ }
+ }
+ }
+}
+
+bool IsProcessDead(ProcessHandle handle, bool blocking) {
+ auto handleForkServer = [handle]() -> mozilla::Maybe<bool> {
+#ifdef MOZ_ENABLE_FORKSERVER
+ if (errno == ECHILD && mozilla::ipc::ForkServiceChild::Get()) {
+ // We only know if a process exists, but not if it has crashed.
+ //
+ // Since content processes are not direct children of the chrome
+ // process any more, it is impossible to use |waitpid()| to wait for
+ // them.
+ const int r = kill(handle, 0);
+ // FIXME: for unexpected errors we should probably log a warning
+ // and return true, so that the caller doesn't loop / hang /
+ // try to kill the process. (Bug 1658072 will rewrite this code.)
+ return mozilla::Some(r < 0 && errno == ESRCH);
+ }
+#else
+ mozilla::Unused << handle;
+#endif
+ return mozilla::Nothing();
+ };
+
+#ifdef HAVE_WAITID
+
+ // We use `WNOWAIT` to read the process status without
+ // side-effecting it, in case it's something unexpected like a
+ // ptrace-stop for the crash reporter. If is an exit, the call is
+ // reissued (see the end of this function) without that flag in
+ // order to collect the process.
+ siginfo_t si{};
+ const int wflags = WEXITED | WNOWAIT | (blocking ? 0 : WNOHANG);
+ int result = HANDLE_EINTR(waitid(P_PID, handle, &si, wflags));
+ if (result == -1) {
+ if (auto forkServerReturn = handleForkServer()) {
+ return *forkServerReturn;
+ }
+
+ // This shouldn't happen, but sometimes it does. The error is
+ // probably ECHILD and the reason is probably that a pid was
+ // waited on again after a previous wait reclaimed its zombie.
+ // (It could also occur if the process isn't a direct child, but
+ // don't do that.) This is bad, because it risks interfering with
+ // an unrelated child process if the pid is reused.
+ //
+ // So, lacking reliable information, we indicate that the process
+ // is dead, in the hope that the caller will give up and stop
+ // calling us. See also bug 943174 and bug 933680.
+ CHROMIUM_LOG(ERROR) << "waitid failed pid:" << handle << " errno:" << errno;
+ return true;
+ }
+
+ if (si.si_pid == 0) {
+ // the child hasn't exited yet.
+ return false;
+ }
+
+ DCHECK(si.si_pid == handle);
+ switch (si.si_code) {
+ case CLD_STOPPED:
+ case CLD_CONTINUED:
+ DCHECK(false) << "waitid returned an event type that it shouldn't have";
+ [[fallthrough]];
+ case CLD_TRAPPED:
+ CHROMIUM_LOG(WARNING) << "ignoring non-exit event for process " << handle;
+ return false;
+
+ case CLD_KILLED:
+ case CLD_DUMPED:
+ CHROMIUM_LOG(WARNING)
+ << "process " << handle << " exited on signal " << si.si_status;
+ break;
+
+ case CLD_EXITED:
+ if (si.si_status != 0) {
+ CHROMIUM_LOG(WARNING)
+ << "process " << handle << " exited with status " << si.si_status;
+ }
+ break;
+
+ default:
+ CHROMIUM_LOG(ERROR) << "unexpected waitid si_code value: " << si.si_code;
+ DCHECK(false);
+ // This shouldn't happen, but assume that the process exited to
+ // avoid the caller possibly ending up in a loop.
+ }
+
+ // Now consume the status / collect the dead process
+ const int old_si_code = si.si_code;
+ si.si_pid = 0;
+ // In theory it shouldn't matter either way if we use `WNOHANG` at
+ // this point, but just in case, avoid unexpected blocking.
+ result = HANDLE_EINTR(waitid(P_PID, handle, &si, WEXITED | WNOHANG));
+ DCHECK(result == 0);
+ DCHECK(si.si_pid == handle);
+ DCHECK(si.si_code == old_si_code);
+ return true;
+
+#else // no waitid
+
+ int status;
+ const int result = waitpid(handle, &status, blocking ? 0 : WNOHANG);
+ if (result == -1) {
+ if (auto forkServerReturn = handleForkServer()) {
+ return *forkServerReturn;
+ }
+
+ CHROMIUM_LOG(ERROR) << "waitpid failed pid:" << handle
+ << " errno:" << errno;
+ return true;
+ }
+ if (result == 0) {
+ return false;
+ }
+
+ if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
+ CHROMIUM_LOG(WARNING) << "process " << handle << " exited with status "
+ << WEXITSTATUS(status);
+ } else if (WIFSIGNALED(status)) {
+ CHROMIUM_LOG(WARNING) << "process " << handle << " exited on signal "
+ << WTERMSIG(status);
+ }
+ return true;
+
+#endif // waitid
+}
+
+void FreeEnvVarsArray::operator()(char** array) {
+ for (char** varPtr = array; *varPtr != nullptr; ++varPtr) {
+ free(*varPtr);
+ }
+ delete[] array;
+}
+
+EnvironmentArray BuildEnvironmentArray(const environment_map& env_vars_to_set) {
+ base::environment_map combined_env_vars = env_vars_to_set;
+ char** environ = PR_DuplicateEnvironment();
+ for (char** varPtr = environ; *varPtr != nullptr; ++varPtr) {
+ std::string varString = *varPtr;
+ size_t equalPos = varString.find_first_of('=');
+ std::string varName = varString.substr(0, equalPos);
+ std::string varValue = varString.substr(equalPos + 1);
+ if (combined_env_vars.find(varName) == combined_env_vars.end()) {
+ combined_env_vars[varName] = varValue;
+ }
+ PR_Free(*varPtr); // PR_DuplicateEnvironment() uses PR_Malloc().
+ }
+ PR_Free(environ); // PR_DuplicateEnvironment() uses PR_Malloc().
+
+ EnvironmentArray array(new char*[combined_env_vars.size() + 1]);
+ size_t i = 0;
+ for (const auto& key_val : combined_env_vars) {
+ std::string entry(key_val.first);
+ entry += "=";
+ entry += key_val.second;
+ array[i] = strdup(entry.c_str());
+ i++;
+ }
+ array[i] = nullptr;
+ return array;
+}
+
+} // namespace base
+
+namespace mozilla {
+
+EnvironmentLog::EnvironmentLog(const char* varname, size_t len) {
+ const char* e = getenv(varname);
+ if (e && *e) {
+ fname_ = e;
+ }
+}
+
+void EnvironmentLog::print(const char* format, ...) {
+ if (!fname_.size()) return;
+
+ FILE* f;
+ if (fname_.compare("-") == 0) {
+ f = fdopen(dup(STDOUT_FILENO), "a");
+ } else {
+ f = fopen(fname_.c_str(), "a");
+ }
+
+ if (!f) return;
+
+ va_list a;
+ va_start(a, format);
+ vfprintf(f, format, a);
+ va_end(a);
+ fclose(f);
+}
+
+} // namespace mozilla
diff --git a/ipc/chromium/src/base/process_util_win.cc b/ipc/chromium/src/base/process_util_win.cc
new file mode 100644
index 0000000000..338917ef98
--- /dev/null
+++ b/ipc/chromium/src/base/process_util_win.cc
@@ -0,0 +1,392 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=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/process_util.h"
+
+#include <windows.h>
+#include <winternl.h>
+#include <psapi.h>
+#include <io.h>
+#ifndef STDOUT_FILENO
+# define STDOUT_FILENO 1
+#endif
+
+#include "base/command_line.h"
+#include "base/histogram.h"
+#include "base/logging.h"
+#include "base/win_util.h"
+
+#include "mozilla/ipc/LaunchError.h"
+#include "mozilla/Result.h"
+
+#include <algorithm>
+#include <stdio.h>
+#include <stdlib.h>
+
+namespace {
+
+typedef BOOL(WINAPI* InitializeProcThreadAttributeListFn)(
+ LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList, DWORD dwAttributeCount,
+ DWORD dwFlags, PSIZE_T lpSize);
+
+typedef BOOL(WINAPI* DeleteProcThreadAttributeListFn)(
+ LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList);
+
+typedef BOOL(WINAPI* UpdateProcThreadAttributeFn)(
+ LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList, DWORD dwFlags,
+ DWORD_PTR Attribute, PVOID lpValue, SIZE_T cbSize, PVOID lpPreviousValue,
+ PSIZE_T lpReturnSize);
+
+static InitializeProcThreadAttributeListFn InitializeProcThreadAttributeListPtr;
+static DeleteProcThreadAttributeListFn DeleteProcThreadAttributeListPtr;
+static UpdateProcThreadAttributeFn UpdateProcThreadAttributePtr;
+
+static mozilla::EnvironmentLog gProcessLog("MOZ_PROCESS_LOG");
+
+} // namespace
+
+namespace base {
+
+ProcessId GetCurrentProcId() { return ::GetCurrentProcessId(); }
+
+ProcessHandle GetCurrentProcessHandle() { return ::GetCurrentProcess(); }
+
+bool OpenProcessHandle(ProcessId pid, ProcessHandle* handle) {
+ // TODO(phajdan.jr): Take even more permissions out of this list.
+ ProcessHandle result =
+ OpenProcess(PROCESS_DUP_HANDLE | PROCESS_TERMINATE |
+ PROCESS_QUERY_INFORMATION | SYNCHRONIZE,
+ FALSE, pid);
+
+ if (result == NULL) {
+ return false;
+ }
+
+ *handle = result;
+ return true;
+}
+
+bool OpenPrivilegedProcessHandle(ProcessId pid, ProcessHandle* handle) {
+ ProcessHandle result =
+ OpenProcess(PROCESS_DUP_HANDLE | PROCESS_TERMINATE |
+ PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | SYNCHRONIZE,
+ FALSE, pid);
+
+ if (result == NULL) {
+ return false;
+ }
+
+ *handle = result;
+ return true;
+}
+
+void CloseProcessHandle(ProcessHandle process) {
+ // closing a handle twice on Windows can be catastrophic - after the first
+ // close the handle value may be reused, so the second close will kill that
+ // other new handle.
+ BOOL ok = CloseHandle(process);
+ DCHECK(ok);
+}
+
+ProcessId GetProcId(ProcessHandle process) {
+ if (process == base::kInvalidProcessHandle || process == nullptr) {
+ return 0;
+ }
+ // This returns 0 if we have insufficient rights to query the process handle.
+ // Invalid handles or non-process handles will cause a diagnostic assert.
+ ProcessId result = GetProcessId(process);
+#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
+ CHECK(result != 0 || GetLastError() != ERROR_INVALID_HANDLE)
+ << "process handle = " << process;
+#endif
+ return result;
+}
+
+// from sandbox_policy_base.cc in a later version of the chromium ipc code...
+bool IsInheritableHandle(HANDLE handle) {
+ if (!handle) return false;
+ if (handle == INVALID_HANDLE_VALUE) return false;
+ // File handles (FILE_TYPE_DISK) and pipe handles are known to be
+ // inheritable. Console handles (FILE_TYPE_CHAR) are not
+ // inheritable via PROC_THREAD_ATTRIBUTE_HANDLE_LIST.
+ DWORD handle_type = GetFileType(handle);
+ return handle_type == FILE_TYPE_DISK || handle_type == FILE_TYPE_PIPE;
+}
+
+void LoadThreadAttributeFunctions() {
+ HMODULE kernel32 = GetModuleHandle(L"kernel32.dll");
+ InitializeProcThreadAttributeListPtr =
+ reinterpret_cast<InitializeProcThreadAttributeListFn>(
+ GetProcAddress(kernel32, "InitializeProcThreadAttributeList"));
+ DeleteProcThreadAttributeListPtr =
+ reinterpret_cast<DeleteProcThreadAttributeListFn>(
+ GetProcAddress(kernel32, "DeleteProcThreadAttributeList"));
+ UpdateProcThreadAttributePtr = reinterpret_cast<UpdateProcThreadAttributeFn>(
+ GetProcAddress(kernel32, "UpdateProcThreadAttribute"));
+}
+
+// Creates and returns a "thread attribute list" to pass to the child process.
+// On return, is a pointer to a THREAD_ATTRIBUTE_LIST or NULL if either the
+// functions we need aren't available (eg, XP or earlier) or the functions we
+// need failed.
+// The result of this function must be passed to FreeThreadAttributeList.
+// Note that the pointer to the HANDLE array ends up embedded in the result of
+// this function and must stay alive until FreeThreadAttributeList is called,
+// hence it is passed in so the owner is the caller of this function.
+LPPROC_THREAD_ATTRIBUTE_LIST CreateThreadAttributeList(HANDLE* handlesToInherit,
+ int handleCount) {
+ if (!InitializeProcThreadAttributeListPtr ||
+ !DeleteProcThreadAttributeListPtr || !UpdateProcThreadAttributePtr)
+ LoadThreadAttributeFunctions();
+ // shouldn't happen as we are only called for Vista+, but better safe than
+ // sorry...
+ if (!InitializeProcThreadAttributeListPtr ||
+ !DeleteProcThreadAttributeListPtr || !UpdateProcThreadAttributePtr)
+ return NULL;
+
+ SIZE_T threadAttrSize;
+ LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList = NULL;
+
+ if (!(*InitializeProcThreadAttributeListPtr)(NULL, 1, 0, &threadAttrSize) &&
+ GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ goto fail;
+ lpAttributeList =
+ reinterpret_cast<LPPROC_THREAD_ATTRIBUTE_LIST>(malloc(threadAttrSize));
+ if (!lpAttributeList || !(*InitializeProcThreadAttributeListPtr)(
+ lpAttributeList, 1, 0, &threadAttrSize))
+ goto fail;
+
+ if (!(*UpdateProcThreadAttributePtr)(
+ lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
+ handlesToInherit, sizeof(handlesToInherit[0]) * handleCount, NULL,
+ NULL)) {
+ (*DeleteProcThreadAttributeListPtr)(lpAttributeList);
+ goto fail;
+ }
+ return lpAttributeList;
+
+fail:
+ if (lpAttributeList) free(lpAttributeList);
+ return NULL;
+}
+
+// Frees the data returned by CreateThreadAttributeList.
+void FreeThreadAttributeList(LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList) {
+ // must be impossible to get a NULL DeleteProcThreadAttributeListPtr, as
+ // we already checked it existed when creating the data we are now freeing.
+ (*DeleteProcThreadAttributeListPtr)(lpAttributeList);
+ free(lpAttributeList);
+}
+
+// The next two functions are from chromium/base/environment.cc
+//
+// Parses a null-terminated input string of an environment block. The key is
+// placed into the given string, and the total length of the line, including
+// the terminating null, is returned.
+static size_t ParseEnvLine(const NativeEnvironmentString::value_type* input,
+ NativeEnvironmentString* key) {
+ // Skip to the equals or end of the string, this is the key.
+ size_t cur = 0;
+ while (input[cur] && input[cur] != '=') cur++;
+ *key = NativeEnvironmentString(&input[0], cur);
+
+ // Now just skip to the end of the string.
+ while (input[cur]) cur++;
+ return cur + 1;
+}
+
+std::wstring AlterEnvironment(const wchar_t* env,
+ const EnvironmentMap& changes) {
+ std::wstring result;
+
+ // First copy all unmodified values to the output.
+ size_t cur_env = 0;
+ std::wstring key;
+ while (env[cur_env]) {
+ const wchar_t* line = &env[cur_env];
+ size_t line_length = ParseEnvLine(line, &key);
+
+ // Keep only values not specified in the change vector.
+ EnvironmentMap::const_iterator found_change = changes.find(key);
+ if (found_change == changes.end()) result.append(line, line_length);
+
+ cur_env += line_length;
+ }
+
+ // Now append all modified and new values.
+ for (EnvironmentMap::const_iterator i = changes.begin(); i != changes.end();
+ ++i) {
+ if (!i->second.empty()) {
+ result.append(i->first);
+ result.push_back('=');
+ result.append(i->second);
+ result.push_back(0);
+ }
+ }
+
+ // An additional null marks the end of the list. We always need a double-null
+ // in case nothing was added above.
+ if (result.empty()) result.push_back(0);
+ result.push_back(0);
+ return result;
+}
+
+Result<Ok, LaunchError> LaunchApp(const std::wstring& cmdline,
+ const LaunchOptions& options,
+ ProcessHandle* process_handle) {
+ // We want to inherit the std handles so dump() statements and assertion
+ // messages in the child process can be seen - but we *do not* want to
+ // blindly have all handles inherited. Vista and later has a technique
+ // where only specified handles are inherited - so we use this technique.
+ // If that fails we just don't inherit anything.
+ DWORD dwCreationFlags = 0;
+ BOOL bInheritHandles = FALSE;
+
+ // We use a STARTUPINFOEX, but if we can't do the thread attribute thing, we
+ // just pass the size of a STARTUPINFO.
+ STARTUPINFOEX startup_info_ex;
+ ZeroMemory(&startup_info_ex, sizeof(startup_info_ex));
+ STARTUPINFO& startup_info = startup_info_ex.StartupInfo;
+ startup_info.cb = sizeof(startup_info);
+ startup_info.dwFlags = STARTF_USESHOWWINDOW | STARTF_FORCEOFFFEEDBACK;
+ startup_info.wShowWindow = options.start_hidden ? SW_HIDE : SW_SHOW;
+
+ // Per the comment in CreateThreadAttributeList, lpAttributeList will contain
+ // a pointer to handlesToInherit, so make sure they have the same lifetime.
+ LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList = NULL;
+ std::vector<HANDLE> handlesToInherit;
+ for (HANDLE h : options.handles_to_inherit) {
+ if (SetHandleInformation(h, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT) ==
+ 0) {
+ MOZ_DIAGNOSTIC_ASSERT(false, "SetHandleInformation failed");
+ return Err(LaunchError("SetHandleInformation", GetLastError()));
+ }
+ handlesToInherit.push_back(h);
+ }
+
+ // setup our handle array first - if we end up with no handles that can
+ // be inherited we can avoid trying to do the ThreadAttributeList dance...
+ HANDLE stdOut = ::GetStdHandle(STD_OUTPUT_HANDLE);
+ HANDLE stdErr = ::GetStdHandle(STD_ERROR_HANDLE);
+
+ if (IsInheritableHandle(stdOut)) handlesToInherit.push_back(stdOut);
+ if (stdErr != stdOut && IsInheritableHandle(stdErr))
+ handlesToInherit.push_back(stdErr);
+
+ if (!handlesToInherit.empty()) {
+ lpAttributeList = CreateThreadAttributeList(handlesToInherit.data(),
+ handlesToInherit.size());
+ if (lpAttributeList) {
+ // it's safe to inherit handles, so arrange for that...
+ startup_info.cb = sizeof(startup_info_ex);
+ startup_info.dwFlags |= STARTF_USESTDHANDLES;
+ startup_info.hStdOutput = stdOut;
+ startup_info.hStdError = stdErr;
+ startup_info.hStdInput = INVALID_HANDLE_VALUE;
+ startup_info_ex.lpAttributeList = lpAttributeList;
+ dwCreationFlags |= EXTENDED_STARTUPINFO_PRESENT;
+ bInheritHandles = TRUE;
+ }
+ }
+
+ dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
+ if (options.start_independent) {
+ dwCreationFlags |= CREATE_BREAKAWAY_FROM_JOB;
+ }
+
+ LPTCH original_environment = GetEnvironmentStrings();
+ base::NativeEnvironmentString new_environment =
+ AlterEnvironment(original_environment, options.env_map);
+ // Ignore return value? What can we do?
+ FreeEnvironmentStrings(original_environment);
+ LPVOID new_env_ptr = (void*)new_environment.data();
+
+ PROCESS_INFORMATION process_info;
+
+ BOOL createdOK = CreateProcess(
+ NULL, const_cast<wchar_t*>(cmdline.c_str()), NULL, NULL, bInheritHandles,
+ dwCreationFlags, new_env_ptr, NULL, &startup_info, &process_info);
+ if (lpAttributeList) FreeThreadAttributeList(lpAttributeList);
+ if (!createdOK) {
+ DLOG(WARNING) << "CreateProcess Failed: " << GetLastError();
+ return Err(LaunchError("CreateProcess", GetLastError()));
+ }
+
+ gProcessLog.print("==> process %d launched child process %d (%S)\n",
+ GetCurrentProcId(), process_info.dwProcessId,
+ cmdline.c_str());
+
+ // Handles must be closed or they will leak
+ CloseHandle(process_info.hThread);
+
+ if (options.wait) WaitForSingleObject(process_info.hProcess, INFINITE);
+
+ // If the caller wants the process handle, we won't close it.
+ if (process_handle) {
+ *process_handle = process_info.hProcess;
+ } else {
+ CloseHandle(process_info.hProcess);
+ }
+ return Ok();
+}
+
+Result<Ok, LaunchError> LaunchApp(const CommandLine& cl,
+ const LaunchOptions& options,
+ ProcessHandle* process_handle) {
+ return LaunchApp(cl.command_line_string(), options, process_handle);
+}
+
+bool KillProcess(ProcessHandle process, int exit_code) {
+ // INVALID_HANDLE_VALUE is not actually an invalid handle value, but
+ // instead is the value returned by GetCurrentProcess(). nullptr,
+ // in contrast, *is* an invalid handle value. Both values are too
+ // easy to accidentally try to kill, and neither is legitimately
+ // used by this function's callers, so reject them.
+ if (!process || process == INVALID_HANDLE_VALUE) {
+ CHROMIUM_LOG(WARNING)
+ << "base::KillProcess refusing to terminate process handle " << process;
+ return false;
+ }
+ bool result = (TerminateProcess(process, exit_code) != FALSE);
+ if (!result) {
+ DLOG(ERROR) << "Unable to terminate process: " << GetLastError();
+ }
+ return result;
+}
+
+} // namespace base
+
+namespace mozilla {
+
+EnvironmentLog::EnvironmentLog(const char* varname, size_t len) {
+ wchar_t wvarname[len];
+ std::copy(varname, varname + len, wvarname);
+ const wchar_t* e = _wgetenv(wvarname);
+ if (e && *e) {
+ fname_ = e;
+ }
+}
+
+void EnvironmentLog::print(const char* format, ...) {
+ if (!fname_.size()) return;
+
+ FILE* f;
+ if (fname_.compare(L"-") == 0) {
+ f = fdopen(dup(STDOUT_FILENO), "a");
+ } else {
+ f = _wfopen(fname_.c_str(), L"a");
+ }
+
+ if (!f) return;
+
+ va_list a;
+ va_start(a, format);
+ vfprintf(f, format, a);
+ va_end(a);
+ fclose(f);
+}
+
+} // namespace mozilla
diff --git a/ipc/chromium/src/base/rand_util.cc b/ipc/chromium/src/base/rand_util.cc
new file mode 100644
index 0000000000..bf14baa5d4
--- /dev/null
+++ b/ipc/chromium/src/base/rand_util.cc
@@ -0,0 +1,30 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/rand_util.h"
+
+#include <math.h>
+
+#include <limits>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "mozilla/RandomNum.h"
+
+namespace base {
+
+int RandInt(int min, int max) {
+ DCHECK(min <= max);
+
+ uint64_t range = static_cast<int64_t>(max) - min + 1;
+ mozilla::Maybe<uint64_t> number = mozilla::RandomUint64();
+ MOZ_RELEASE_ASSERT(number.isSome());
+ int result = min + static_cast<int>(number.value() % range);
+ DCHECK(result >= min && result <= max);
+ return result;
+}
+
+} // namespace base
diff --git a/ipc/chromium/src/base/rand_util.h b/ipc/chromium/src/base/rand_util.h
new file mode 100644
index 0000000000..963fc69599
--- /dev/null
+++ b/ipc/chromium/src/base/rand_util.h
@@ -0,0 +1,19 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_RAND_UTIL_H_
+#define BASE_RAND_UTIL_H_
+
+#include "base/basictypes.h"
+
+namespace base {
+
+// Returns a random number between min and max (inclusive). Thread-safe.
+int RandInt(int min, int max);
+
+} // namespace base
+
+#endif // BASE_RAND_UTIL_H_
diff --git a/ipc/chromium/src/base/revocable_store.cc b/ipc/chromium/src/base/revocable_store.cc
new file mode 100644
index 0000000000..b3d7414ee2
--- /dev/null
+++ b/ipc/chromium/src/base/revocable_store.cc
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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 "base/revocable_store.h"
+
+#include "base/logging.h"
+
+RevocableStore::Revocable::Revocable(RevocableStore* store)
+ : store_reference_(store->owning_reference_) {
+ // We AddRef() the owning reference.
+ DCHECK(store_reference_->store());
+ store_reference_->store()->Add(this);
+}
+
+RevocableStore::RevocableStore() {
+ // Create a new owning reference.
+ owning_reference_ = new StoreRef(this);
+}
+
+RevocableStore::~RevocableStore() {
+ // Revoke all the items in the store.
+ owning_reference_->set_store(NULL);
+}
+
+void RevocableStore::Add(Revocable* item) {
+ DCHECK(!item->revoked());
+}
+
+void RevocableStore::RevokeAll() {
+ // We revoke all the existing items in the store and reset our count.
+ owning_reference_->set_store(NULL);
+
+ // Then we create a new owning reference for new items that get added.
+ // This Release()s the old owning reference, allowing it to be freed after
+ // all the items that were in the store are eventually destroyed.
+ owning_reference_ = new StoreRef(this);
+}
diff --git a/ipc/chromium/src/base/revocable_store.h b/ipc/chromium/src/base/revocable_store.h
new file mode 100644
index 0000000000..789c011cde
--- /dev/null
+++ b/ipc/chromium/src/base/revocable_store.h
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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_REVOCABLE_STORE_H_
+#define BASE_REVOCABLE_STORE_H_
+
+#include "base/basictypes.h"
+#include "nsISupportsImpl.h"
+
+// |RevocableStore| is a container of items that can be removed from the store.
+class RevocableStore {
+ public:
+ // A |StoreRef| is used to link the |RevocableStore| to its items. There is
+ // one StoreRef per store, and each item holds a reference to it. If the
+ // store wishes to revoke its items, it sets |store_| to null. Items are
+ // permitted to release their reference to the |StoreRef| when they no longer
+ // require the store.
+ class StoreRef final {
+ public:
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(StoreRef)
+ explicit StoreRef(RevocableStore* aStore) : store_(aStore) {}
+
+ void set_store(RevocableStore* aStore) { store_ = aStore; }
+ RevocableStore* store() const { return store_; }
+
+ protected:
+ ~StoreRef() {}
+
+ private:
+ RevocableStore* store_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(StoreRef);
+ };
+
+ // An item in the store. On construction, the object adds itself to the
+ // store.
+ class Revocable {
+ public:
+ explicit Revocable(RevocableStore* store);
+ ~Revocable() = default;
+
+ // This item has been revoked if it no longer has a pointer to the store.
+ bool revoked() const { return !store_reference_->store(); }
+
+ private:
+ // We hold a reference to the store through this ref pointer. We release
+ // this reference on destruction.
+ RefPtr<StoreRef> store_reference_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(Revocable);
+ };
+
+ RevocableStore();
+ ~RevocableStore();
+
+ // Revokes all the items in the store.
+ void RevokeAll();
+
+ private:
+ friend class Revocable;
+
+ // Adds an item to the store. To add an item to the store, construct it
+ // with a pointer to the store.
+ void Add(Revocable* item);
+
+ // This is the reference the unrevoked items in the store hold.
+ RefPtr<StoreRef> owning_reference_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(RevocableStore);
+};
+
+#endif // BASE_REVOCABLE_STORE_H_
diff --git a/ipc/chromium/src/base/scoped_bstr_win.h b/ipc/chromium/src/base/scoped_bstr_win.h
new file mode 100644
index 0000000000..4e7e133421
--- /dev/null
+++ b/ipc/chromium/src/base/scoped_bstr_win.h
@@ -0,0 +1,138 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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_SCOPED_BSTR_WIN_H_
+#define BASE_SCOPED_BSTR_WIN_H_
+
+#include "base/basictypes.h" // needed to pick up XP_WIN
+
+#include "base/logging.h"
+
+#include <windows.h>
+#include <oleauto.h>
+
+// Manages a BSTR string pointer.
+// The class interface is based on scoped_ptr.
+class ScopedBstr {
+ public:
+ ScopedBstr() : bstr_(NULL) {}
+
+ // Constructor to create a new BSTR.
+ // NOTE: Do not pass a BSTR to this constructor expecting ownership to
+ // be transferred - even though it compiles! ;-)
+ explicit ScopedBstr(const wchar_t* non_bstr);
+ ~ScopedBstr();
+
+ // Give ScopedBstr ownership over an already allocated BSTR or NULL.
+ // If you need to allocate a new BSTR instance, use |allocate| instead.
+ void Reset(BSTR bstr = NULL);
+
+ // Releases ownership of the BSTR to the caller.
+ BSTR Release();
+
+ // Creates a new BSTR from a wide string.
+ // If you already have a BSTR and want to transfer ownership to the
+ // ScopedBstr instance, call |reset| instead.
+ // Returns a pointer to the new BSTR, or NULL if allocation failed.
+ BSTR Allocate(const wchar_t* wide_str);
+
+ // Allocates a new BSTR with the specified number of bytes.
+ // Returns a pointer to the new BSTR, or NULL if allocation failed.
+ BSTR AllocateBytes(int bytes);
+
+ // Sets the allocated length field of the already-allocated BSTR to be
+ // |bytes|. This is useful when the BSTR was preallocated with e.g.
+ // SysAllocStringLen or SysAllocStringByteLen (call |AllocateBytes|) and
+ // then not all the bytes are being used.
+ // Note that if you want to set the length to a specific number of characters,
+ // you need to multiply by sizeof(wchar_t). Oddly, there's no public API to
+ // set the length, so we do this ourselves by hand.
+ //
+ // NOTE: The actual allocated size of the BSTR MUST be >= bytes.
+ // That responsibility is with the caller.
+ void SetByteLen(uint32_t bytes);
+
+ // Swap values of two ScopedBstr's.
+ void Swap(ScopedBstr& bstr2);
+
+ // Retrieves the pointer address.
+ // Used to receive BSTRs as out arguments (and take ownership).
+ // The function DCHECKs on the current value being NULL.
+ // Usage: GetBstr(bstr.Receive());
+ BSTR* Receive();
+
+ // Returns number of chars in the BSTR.
+ uint32_t Length() const;
+
+ // Returns the number of bytes allocated for the BSTR.
+ uint32_t ByteLength() const;
+
+ operator BSTR() const { return bstr_; }
+
+ protected:
+ BSTR bstr_;
+
+ private:
+ // Forbid comparison of ScopedBstr types. You should never have the same
+ // BSTR owned by two different scoped_ptrs.
+ bool operator==(const ScopedBstr& bstr2) const;
+ bool operator!=(const ScopedBstr& bstr2) const;
+ DISALLOW_COPY_AND_ASSIGN(ScopedBstr);
+};
+
+// Template class to generate a BSTR from a static wide string
+// without touching the heap. Use this class via the StackBstrVar and
+// StackBstr macros.
+template <uint32_t string_bytes>
+class StackBstrT {
+ public:
+ // Try to stay as const as we can in an attempt to avoid someone
+ // using the class incorrectly (e.g. by supplying a variable instead
+ // of a verbatim string. We also have an assert in the constructor
+ // as an extra runtime check since the const-ness only catches one case.
+ explicit StackBstrT(const wchar_t* const str) {
+ // The BSTR API uses UINT, but we prefer uint32_t.
+ // Make sure we'll know about it if these types don't match.
+ COMPILE_ASSERT(sizeof(uint32_t) == sizeof(UINT), UintToUint32);
+ COMPILE_ASSERT(sizeof(wchar_t) == sizeof(OLECHAR), WcharToOlechar);
+
+ // You shouldn't pass string pointers to this constructor since
+ // there's no way for the compiler to calculate the length of the
+ // string (string_bytes will be equal to pointer size in those cases).
+ DCHECK(lstrlenW(str) == (string_bytes / sizeof(bstr_.str_[0])) - 1)
+ << "not expecting a string pointer";
+ memcpy(bstr_.str_, str, string_bytes);
+ bstr_.len_ = string_bytes - sizeof(wchar_t);
+ }
+
+ operator BSTR() { return bstr_.str_; }
+
+ protected:
+ struct BstrInternal {
+ uint32_t len_;
+ wchar_t str_[string_bytes / sizeof(wchar_t)];
+ } bstr_;
+};
+
+// Use this macro to generate an inline BSTR from a wide string.
+// This is about 6 times faster than using the SysAllocXxx functions to
+// allocate a BSTR and helps with keeping heap fragmentation down.
+// Example:
+// DoBstrStuff(StackBstr(L"This is my BSTR"));
+// Where DoBstrStuff is:
+// HRESULT DoBstrStuff(BSTR bstr) { ... }
+#define StackBstr(str) static_cast<BSTR>(StackBstrT<sizeof(str)>(str))
+
+// If you need a named BSTR variable that's based on a fixed string
+// (e.g. if the BSTR is used inside a loop or more than one place),
+// use StackBstrVar to declare a variable.
+// Example:
+// StackBstrVar(L"my_property", myprop);
+// for (int i = 0; i < objects.length(); ++i)
+// ProcessValue(objects[i].GetProp(myprop)); // GetProp accepts BSTR
+#define StackBstrVar(str, var) StackBstrT<sizeof(str)> var(str)
+
+#endif // BASE_SCOPED_BSTR_WIN_H_
diff --git a/ipc/chromium/src/base/scoped_cftyperef.h b/ipc/chromium/src/base/scoped_cftyperef.h
new file mode 100644
index 0000000000..9cd3cfa967
--- /dev/null
+++ b/ipc/chromium/src/base/scoped_cftyperef.h
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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_SCOPED_CFTYPEREF_H_
+#define BASE_SCOPED_CFTYPEREF_H_
+
+#include <CoreFoundation/CoreFoundation.h>
+#include "base/basictypes.h"
+
+// scoped_cftyperef<> is patterned after scoped_ptr<>, but maintains ownership
+// of a CoreFoundation object: any object that can be represented as a
+// CFTypeRef. Style deviations here are solely for compatibility with
+// scoped_ptr<>'s interface, with which everyone is already familiar.
+//
+// When scoped_cftyperef<> takes ownership of an object (in the constructor or
+// in reset()), it takes over the caller's existing ownership claim. The
+// caller must own the object it gives to scoped_cftyperef<>, and relinquishes
+// an ownership claim to that object. scoped_cftyperef<> does not call
+// CFRetain().
+template <typename CFT>
+class scoped_cftyperef {
+ public:
+ typedef CFT element_type;
+
+ explicit scoped_cftyperef(CFT object = NULL) : object_(object) {}
+
+ ~scoped_cftyperef() {
+ if (object_) CFRelease(object_);
+ }
+
+ void reset(CFT object = NULL) {
+ if (object_) CFRelease(object_);
+ object_ = object;
+ }
+
+ bool operator==(CFT that) const { return object_ == that; }
+
+ bool operator!=(CFT that) const { return object_ != that; }
+
+ operator CFT() const { return object_; }
+
+ CFT get() const { return object_; }
+
+ void swap(scoped_cftyperef& that) {
+ CFT temp = that.object_;
+ that.object_ = object_;
+ object_ = temp;
+ }
+
+ // scoped_cftyperef<>::release() is like scoped_ptr<>::release. It is NOT
+ // a wrapper for CFRelease(). To force a scoped_cftyperef<> object to call
+ // CFRelease(), use scoped_cftyperef<>::reset().
+ CFT release() {
+ CFT temp = object_;
+ object_ = NULL;
+ return temp;
+ }
+
+ private:
+ CFT object_;
+
+ DISALLOW_COPY_AND_ASSIGN(scoped_cftyperef);
+};
+
+#endif // BASE_SCOPED_CFTYPEREF_H_
diff --git a/ipc/chromium/src/base/scoped_handle.h b/ipc/chromium/src/base/scoped_handle.h
new file mode 100644
index 0000000000..97bb7f1240
--- /dev/null
+++ b/ipc/chromium/src/base/scoped_handle.h
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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_SCOPED_HANDLE_H_
+#define BASE_SCOPED_HANDLE_H_
+
+#include <stdio.h>
+
+#include "base/basictypes.h"
+
+#if defined(XP_WIN)
+# include "base/scoped_handle_win.h"
+#endif
+
+class ScopedStdioHandle {
+ public:
+ ScopedStdioHandle() : handle_(NULL) {}
+
+ explicit ScopedStdioHandle(FILE* handle) : handle_(handle) {}
+
+ ~ScopedStdioHandle() { Close(); }
+
+ void Close() {
+ if (handle_) {
+ fclose(handle_);
+ handle_ = NULL;
+ }
+ }
+
+ FILE* get() const { return handle_; }
+
+ FILE* Take() {
+ FILE* temp = handle_;
+ handle_ = NULL;
+ return temp;
+ }
+
+ void Set(FILE* newhandle) {
+ Close();
+ handle_ = newhandle;
+ }
+
+ private:
+ FILE* handle_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(ScopedStdioHandle);
+};
+
+#endif // BASE_SCOPED_HANDLE_H_
diff --git a/ipc/chromium/src/base/scoped_handle_win.h b/ipc/chromium/src/base/scoped_handle_win.h
new file mode 100644
index 0000000000..e8e419b7c5
--- /dev/null
+++ b/ipc/chromium/src/base/scoped_handle_win.h
@@ -0,0 +1,193 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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_SCOPED_HANDLE_WIN_H_
+#define BASE_SCOPED_HANDLE_WIN_H_
+
+#include <windows.h>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+// Used so we always remember to close the handle.
+// The class interface matches that of ScopedStdioHandle in addition to an
+// IsValid() method since invalid handles on windows can be either NULL or
+// INVALID_HANDLE_VALUE (-1).
+//
+// Example:
+// ScopedHandle hfile(CreateFile(...));
+// if (!hfile.Get())
+// ...process error
+// ReadFile(hfile.Get(), ...);
+//
+// To sqirrel the handle away somewhere else:
+// secret_handle_ = hfile.Take();
+//
+// To explicitly close the handle:
+// hfile.Close();
+class ScopedHandle {
+ public:
+ ScopedHandle() : handle_(NULL) {}
+
+ explicit ScopedHandle(HANDLE h) : handle_(NULL) { Set(h); }
+
+ ~ScopedHandle() { Close(); }
+
+ // Use this instead of comparing to INVALID_HANDLE_VALUE to pick up our NULL
+ // usage for errors.
+ bool IsValid() const { return handle_ != NULL; }
+
+ void Set(HANDLE new_handle) {
+ Close();
+
+ // Windows is inconsistent about invalid handles, so we always use NULL
+ if (new_handle != INVALID_HANDLE_VALUE) handle_ = new_handle;
+ }
+
+ HANDLE Get() { return handle_; }
+
+ operator HANDLE() { return handle_; }
+
+ HANDLE Take() {
+ // transfers ownership away from this object
+ HANDLE h = handle_;
+ handle_ = NULL;
+ return h;
+ }
+
+ void Close() {
+ if (handle_) {
+ if (!::CloseHandle(handle_)) {
+ NOTREACHED();
+ }
+ handle_ = NULL;
+ }
+ }
+
+ private:
+ HANDLE handle_;
+ DISALLOW_EVIL_CONSTRUCTORS(ScopedHandle);
+};
+
+// Like ScopedHandle, but for HANDLEs returned from FindFile().
+class ScopedFindFileHandle {
+ public:
+ explicit ScopedFindFileHandle(HANDLE handle) : handle_(handle) {
+ // Windows is inconsistent about invalid handles, so we always use NULL
+ if (handle_ == INVALID_HANDLE_VALUE) handle_ = NULL;
+ }
+
+ ~ScopedFindFileHandle() {
+ if (handle_) FindClose(handle_);
+ }
+
+ // Use this instead of comparing to INVALID_HANDLE_VALUE to pick up our NULL
+ // usage for errors.
+ bool IsValid() const { return handle_ != NULL; }
+
+ operator HANDLE() { return handle_; }
+
+ private:
+ HANDLE handle_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(ScopedFindFileHandle);
+};
+
+// Like ScopedHandle but for HDC. Only use this on HDCs returned from
+// CreateCompatibleDC. For an HDC returned by GetDC, use ReleaseDC instead.
+class ScopedHDC {
+ public:
+ ScopedHDC() : hdc_(NULL) {}
+ explicit ScopedHDC(HDC h) : hdc_(h) {}
+
+ ~ScopedHDC() { Close(); }
+
+ HDC Get() { return hdc_; }
+
+ void Set(HDC h) {
+ Close();
+ hdc_ = h;
+ }
+
+ operator HDC() { return hdc_; }
+
+ private:
+ void Close() {
+#ifdef NOGDI
+ assert(false);
+#else
+ if (hdc_) DeleteDC(hdc_);
+#endif // NOGDI
+ }
+
+ HDC hdc_;
+ DISALLOW_EVIL_CONSTRUCTORS(ScopedHDC);
+};
+
+// Like ScopedHandle but for GDI objects.
+template <class T>
+class ScopedGDIObject {
+ public:
+ ScopedGDIObject() : object_(NULL) {}
+ explicit ScopedGDIObject(T object) : object_(object) {}
+
+ ~ScopedGDIObject() { Close(); }
+
+ T Get() { return object_; }
+
+ void Set(T object) {
+ if (object_ && object != object_) Close();
+ object_ = object;
+ }
+
+ ScopedGDIObject& operator=(T object) {
+ Set(object);
+ return *this;
+ }
+
+ operator T() { return object_; }
+
+ private:
+ void Close() {
+ if (object_) DeleteObject(object_);
+ }
+
+ T object_;
+ DISALLOW_COPY_AND_ASSIGN(ScopedGDIObject);
+};
+
+// Typedefs for some common use cases.
+typedef ScopedGDIObject<HBITMAP> ScopedBitmap;
+typedef ScopedGDIObject<HRGN> ScopedHRGN;
+typedef ScopedGDIObject<HFONT> ScopedHFONT;
+
+// Like ScopedHandle except for HGLOBAL.
+template <class T>
+class ScopedHGlobal {
+ public:
+ explicit ScopedHGlobal(HGLOBAL glob) : glob_(glob) {
+ data_ = static_cast<T*>(GlobalLock(glob_));
+ }
+ ~ScopedHGlobal() { GlobalUnlock(glob_); }
+
+ T* get() { return data_; }
+
+ size_t Size() const { return GlobalSize(glob_); }
+
+ T* operator->() const {
+ assert(data_ != 0);
+ return data_;
+ }
+
+ private:
+ HGLOBAL glob_;
+
+ T* data_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(ScopedHGlobal);
+};
+
+#endif // BASE_SCOPED_HANDLE_WIN_H_
diff --git a/ipc/chromium/src/base/scoped_nsautorelease_pool.h b/ipc/chromium/src/base/scoped_nsautorelease_pool.h
new file mode 100644
index 0000000000..37d173b028
--- /dev/null
+++ b/ipc/chromium/src/base/scoped_nsautorelease_pool.h
@@ -0,0 +1,55 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_SCOPED_NSAUTORELEASE_POOL_H_
+#define BASE_SCOPED_NSAUTORELEASE_POOL_H_
+
+#include "base/basictypes.h"
+
+#if defined(XP_DARWIN)
+# if defined(__OBJC__)
+@class NSAutoreleasePool;
+# else // __OBJC__
+class NSAutoreleasePool;
+# endif // __OBJC__
+#endif // XP_DARWIN
+
+namespace base {
+
+// On the Mac, ScopedNSAutoreleasePool allocates an NSAutoreleasePool when
+// instantiated and sends it a -drain message when destroyed. This allows an
+// autorelease pool to be maintained in ordinary C++ code without bringing in
+// any direct Objective-C dependency.
+//
+// On other platforms, ScopedNSAutoreleasePool is an empty object with no
+// effects. This allows it to be used directly in cross-platform code without
+// ugly #ifdefs.
+class ScopedNSAutoreleasePool {
+ public:
+#if !defined(XP_DARWIN)
+ ScopedNSAutoreleasePool() {}
+ void Recycle() {}
+#else // XP_DARWIN
+ ScopedNSAutoreleasePool();
+ ~ScopedNSAutoreleasePool();
+
+ // Clear out the pool in case its position on the stack causes it to be
+ // alive for long periods of time (such as the entire length of the app).
+ // Only use then when you're certain the items currently in the pool are
+ // no longer needed.
+ void Recycle();
+
+ private:
+ NSAutoreleasePool* autorelease_pool_;
+#endif // XP_DARWIN
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ScopedNSAutoreleasePool);
+};
+
+} // namespace base
+
+#endif // BASE_SCOPED_NSAUTORELEASE_POOL_H_
diff --git a/ipc/chromium/src/base/scoped_nsautorelease_pool.mm b/ipc/chromium/src/base/scoped_nsautorelease_pool.mm
new file mode 100644
index 0000000000..174fb821d6
--- /dev/null
+++ b/ipc/chromium/src/base/scoped_nsautorelease_pool.mm
@@ -0,0 +1,30 @@
+// Copyright (c) 2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/scoped_nsautorelease_pool.h"
+
+#import <Foundation/Foundation.h>
+
+#include "base/logging.h"
+
+namespace base {
+
+ScopedNSAutoreleasePool::ScopedNSAutoreleasePool()
+ : autorelease_pool_([[NSAutoreleasePool alloc] init]) {
+ DCHECK(autorelease_pool_);
+}
+
+ScopedNSAutoreleasePool::~ScopedNSAutoreleasePool() {
+ [autorelease_pool_ drain];
+}
+
+// Cycle the internal pool, allowing everything there to get cleaned up and
+// start anew.
+void ScopedNSAutoreleasePool::Recycle() {
+ [autorelease_pool_ drain];
+ autorelease_pool_ = [[NSAutoreleasePool alloc] init];
+ DCHECK(autorelease_pool_);
+}
+
+} // namespace base
diff --git a/ipc/chromium/src/base/scoped_nsobject.h b/ipc/chromium/src/base/scoped_nsobject.h
new file mode 100644
index 0000000000..d1ef77d749
--- /dev/null
+++ b/ipc/chromium/src/base/scoped_nsobject.h
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=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.
+
+#ifndef BASE_SCOPED_NSOBJECT_H_
+#define BASE_SCOPED_NSOBJECT_H_
+
+#import <Foundation/Foundation.h>
+#include "base/basictypes.h"
+
+// scoped_nsobject<> is patterned after scoped_ptr<>, but maintains ownership
+// of an NSObject subclass object. Style deviations here are solely for
+// compatibility with scoped_ptr<>'s interface, with which everyone is already
+// familiar.
+//
+// When scoped_nsobject<> takes ownership of an object (in the constructor or
+// in reset()), it takes over the caller's existing ownership claim. The
+// caller must own the object it gives to scoped_nsobject<>, and relinquishes
+// an ownership claim to that object. scoped_nsobject<> does not call
+// -retain.
+template <typename NST>
+class scoped_nsobject {
+ public:
+ typedef NST* element_type;
+
+ explicit scoped_nsobject(NST* object = nil) : object_(object) {}
+
+ ~scoped_nsobject() { [object_ release]; }
+
+ void reset(NST* object = nil) {
+ [object_ release];
+ object_ = object;
+ }
+
+ bool operator==(NST* that) const { return object_ == that; }
+
+ bool operator!=(NST* that) const { return object_ != that; }
+
+ operator NST*() const { return object_; }
+
+ NST* get() const { return object_; }
+
+ void swap(scoped_nsobject& that) {
+ NST* temp = that.object_;
+ that.object_ = object_;
+ object_ = temp;
+ }
+
+ // scoped_nsobject<>::release() is like scoped_ptr<>::release. It is NOT
+ // a wrapper for [object_ release]. To force a scoped_nsobject<> object to
+ // call [object_ release], use scoped_nsobject<>::reset().
+ NST* release() {
+ NST* temp = object_;
+ object_ = nil;
+ return temp;
+ }
+
+ private:
+ NST* object_;
+
+ DISALLOW_COPY_AND_ASSIGN(scoped_nsobject);
+};
+
+#endif // BASE_SCOPED_NSOBJECT_H_
diff --git a/ipc/chromium/src/base/set_process_title_linux.cc b/ipc/chromium/src/base/set_process_title_linux.cc
new file mode 100644
index 0000000000..fed166a524
--- /dev/null
+++ b/ipc/chromium/src/base/set_process_title_linux.cc
@@ -0,0 +1,206 @@
+// Copyright 2009 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file implements BSD-style setproctitle() for Linux.
+// It is written such that it can easily be compiled outside Chromium.
+//
+// (This copy has been modified for use in the Mozilla codebase.)
+//
+// The Linux kernel sets up two locations in memory to pass arguments and
+// environment variables to processes. First, there are two char* arrays stored
+// one after another: argv and environ. A pointer to argv is passed to main(),
+// while glibc sets the global variable |environ| to point at the latter. Both
+// of these arrays are terminated by a null pointer; the environment array is
+// also followed by some empty space to allow additional variables to be added.
+//
+// These arrays contain pointers to a second location in memory, where the
+// strings themselves are stored one after another: first all the arguments,
+// then the environment variables.
+//
+// When the kernel reads the command line arguments for a process, it looks at
+// the range of memory that it initially used for the argument list. If the
+// terminating '\0' character is still where it expects, nothing further is
+// done. If it has been overwritten, the kernel will scan up to the size of
+// a page looking for another.
+//
+// Thus to change the process title, we must move any arguments and environment
+// variables out of the way to make room for a potentially longer title, and
+// then overwrite the memory pointed to by argv[0] with a single replacement
+// string, making sure its size does not exceed the available space.
+//
+// See the following kernel commit for the details of the contract between
+// kernel and setproctitle:
+// https://github.com/torvalds/linux/commit/2954152298c37804dab49d630aa959625b50cf64
+//
+// It is perhaps worth noting that patches to add a system call to Linux for
+// this, like in BSD, have never made it in: this is the "official" way to do
+// this on Linux. Presumably it is not in glibc due to some disagreement over
+// this position within the glibc project, leaving applications caught in the
+// middle. (Also, only a very few applications need or want this anyway.)
+
+#include "base/set_process_title_linux.h"
+
+#include "mozilla/UniquePtrExtensions.h"
+
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <string>
+#include <vector>
+
+extern char** environ;
+
+// g_orig_argv0 is the original process name found in argv[0].
+// It is set to a copy of argv[0] in setproctitle_init. It is nullptr if
+// setproctitle_init was unsuccessful or not called.
+static const char* g_orig_argv0 = nullptr;
+
+// Following pointers hold the initial argv/envp memory range.
+// They are initialized in setproctitle_init and are used to overwrite the
+// argv/envp memory range with a new process title to be read by the kernel.
+// They are nullptr if setproctitle_init was unsuccessful or not called.
+// Note that g_envp_start is not necessary because it is the same as g_argv_end.
+static char* g_argv_start = nullptr;
+static char* g_argv_end = nullptr;
+static char* g_envp_end = nullptr;
+
+void setproctitle(const char* fmt, ...) {
+ va_list ap;
+
+ // Sanity check before we try and set the process title.
+ // The BSD version allows a null fmt to restore the original title.
+ if (!g_orig_argv0 || !fmt) {
+ return;
+ }
+
+ // The title can be up to the end of envp.
+ const size_t avail_size = g_envp_end - g_argv_start - 1;
+
+ // Linux 4.18--5.2 have a bug where we can never set a process title
+ // shorter than the initial argv. Check if the bug exists in the current
+ // kernel on the first call of setproctitle.
+ static const bool buggy_kernel = [avail_size]() {
+ // Attempt to set an empty title. This will set cmdline to:
+ // "" (on Linux --4.17)
+ // "\0\0\0...\0\0\0.\0" (on Linux 4.18--5.2)
+ // "\0" (on Linux 5.3--)
+ memset(g_argv_start, 0, avail_size + 1);
+ g_argv_end[-1] = '.';
+
+ mozilla::UniqueFileHandle fd(
+ open("/proc/self/cmdline", O_RDONLY | O_CLOEXEC));
+ if (!fd) {
+ return false;
+ }
+
+ // We just want to see if there are at least 2 bytes in the file;
+ // we don't need to read the whole contents. Short reads probably
+ // aren't possible given how this procfs node is implemented, but
+ // it's not much more code to handle it anyway.
+ char buf[2];
+ ssize_t total_read = 0;
+ while (total_read < 2) {
+ ssize_t rd = read(fd.get(), buf, 2);
+ if (rd <= 0) {
+ return false;
+ }
+ total_read += rd;
+ }
+ return true;
+ }();
+
+ memset(g_argv_start, 0, avail_size + 1);
+
+ size_t size;
+ va_start(ap, fmt);
+ if (fmt[0] == '-') {
+ size = vsnprintf(g_argv_start, avail_size, &fmt[1], ap);
+ } else {
+ size = snprintf(g_argv_start, avail_size, "%s ", g_orig_argv0);
+ if (size < avail_size) {
+ size += vsnprintf(&g_argv_start[size], avail_size - size, fmt, ap);
+ }
+ }
+ va_end(ap);
+
+ // Kernel looks for a null terminator instead of the initial argv space
+ // when the end of the space is not terminated with a null.
+ // https://github.com/torvalds/linux/commit/d26d0cd97c88eb1a5704b42e41ab443406807810
+ //
+ // If the length of the new title is shorter than the original argv space,
+ // set the last byte of the space to an arbitrary non-null character to tell
+ // the kernel that setproctitle was called.
+ //
+ // On buggy kernels we can never make the process title shorter than the
+ // initial argv. In that case, just leave the remaining bytes filled with
+ // null characters.
+ const size_t argv_size = g_argv_end - g_argv_start - 1;
+ if (!buggy_kernel && size < argv_size) {
+ g_argv_end[-1] = '.';
+ }
+}
+
+// A version of this built into glibc would not need this function, since
+// it could stash the argv pointer in __libc_start_main(). But we need it.
+void setproctitle_init(char** main_argv) {
+ static bool init_called = false;
+ if (init_called) {
+ return;
+ }
+ init_called = true;
+
+ if (!main_argv) {
+ return;
+ }
+
+ // Verify that the memory layout matches expectation.
+ char** const argv = main_argv;
+ char* argv_start = argv[0];
+ char* p = argv_start;
+ for (size_t i = 0; argv[i]; ++i) {
+ if (p != argv[i]) {
+ return;
+ }
+ p += strlen(p) + 1;
+ }
+ char* argv_end = p;
+ size_t environ_size = 0;
+ for (size_t i = 0; environ[i]; ++i, ++environ_size) {
+ if (p != environ[i]) {
+ return;
+ }
+ p += strlen(p) + 1;
+ }
+ char* envp_end = p;
+
+ // Copy the arg and env strings into the heap. Leak Sanitizer
+ // doesn't seem to object to these strdup()s; if it ever does, we
+ // can always ensure the pointers are reachable from globals or add
+ // a suppresion for this function.
+ //
+ // Note that Chromium's version of this code didn't copy the
+ // arguments; this is probably because they access args via the
+ // CommandLine class, which copies into a std::vector<std::string>,
+ // but in general that's not a safe assumption for Gecko.
+ for (size_t i = 0; argv[i]; ++i) {
+ argv[i] = strdup(argv[i]);
+ }
+ for (size_t i = 0; environ[i]; ++i) {
+ environ[i] = strdup(environ[i]);
+ }
+
+ if (!argv[0]) {
+ return;
+ }
+
+ g_orig_argv0 = argv[0];
+ g_argv_start = argv_start;
+ g_argv_end = argv_end;
+ g_envp_end = envp_end;
+}
diff --git a/ipc/chromium/src/base/set_process_title_linux.h b/ipc/chromium/src/base/set_process_title_linux.h
new file mode 100644
index 0000000000..e950ce0619
--- /dev/null
+++ b/ipc/chromium/src/base/set_process_title_linux.h
@@ -0,0 +1,12 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef BASE_PROCESS_TITLE_LINUX_H_
+#define BASE_PROCESS_TITLE_LINUX_H_
+
+void setproctitle(const char* fmt, ...);
+void setproctitle_init(char** main_argv);
+
+#endif // BASE_PROCESS_TITLE_LINUX_H_
diff --git a/ipc/chromium/src/base/shared_memory.h b/ipc/chromium/src/base/shared_memory.h
new file mode 100644
index 0000000000..7735577334
--- /dev/null
+++ b/ipc/chromium/src/base/shared_memory.h
@@ -0,0 +1,197 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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_SHARED_MEMORY_H_
+#define BASE_SHARED_MEMORY_H_
+
+#if defined(XP_UNIX)
+# include <sys/types.h>
+# include <semaphore.h>
+#endif
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/process.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/UniquePtrExtensions.h"
+
+namespace base {
+
+// SharedMemoryHandle is a platform specific type which represents
+// the underlying OS handle to a shared memory segment.
+typedef mozilla::UniqueFileHandle SharedMemoryHandle;
+
+// Platform abstraction for shared memory. Provides a C++ wrapper
+// around the OS primitive for a memory mapped file.
+class SharedMemory {
+ public:
+ // Create a new SharedMemory object.
+ SharedMemory() = default;
+
+ // Create a new SharedMemory object from an existing, open
+ // shared memory file.
+ SharedMemory(SharedMemoryHandle init_handle, bool read_only)
+ : SharedMemory() {
+ SetHandle(std::move(init_handle), read_only);
+ }
+
+ // Move constructor; transfers ownership.
+ SharedMemory(SharedMemory&& other) = default;
+
+ // Destructor. Will close any open files.
+ ~SharedMemory();
+
+ // Initialize a new SharedMemory object from an existing, open
+ // shared memory file.
+ bool SetHandle(SharedMemoryHandle handle, bool read_only);
+
+ // Return true iff the given handle is valid (i.e. not the distingished
+ // invalid value; NULL for a HANDLE and -1 for a file descriptor)
+ static bool IsHandleValid(const SharedMemoryHandle& handle);
+
+ // IsHandleValid applied to this object's handle.
+ bool IsValid() const { return static_cast<bool>(mapped_file_); }
+
+ // Return invalid handle (see comment above for exact definition).
+ static SharedMemoryHandle NULLHandle();
+
+ // Creates a shared memory segment.
+ // Returns true on success, false on failure.
+ bool Create(size_t size) { return CreateInternal(size, false); }
+
+ // Creates a shared memory segment that supports the Freeze()
+ // method; see below. (Warning: creating freezeable shared memory
+ // within a sandboxed process isn't possible on some platforms.)
+ // Returns true on success, false on failure.
+ bool CreateFreezeable(size_t size) { return CreateInternal(size, true); }
+
+ // Maps the shared memory into the caller's address space.
+ // Returns true on success, false otherwise. The memory address
+ // is accessed via the memory() accessor.
+ //
+ // If the specified fixed address is not null, it is the address that the
+ // shared memory must be mapped at. Returns false if the shared memory
+ // could not be mapped at that address.
+ bool Map(size_t bytes, void* fixed_address = nullptr);
+
+ // Unmaps the shared memory from the caller's address space.
+ void Unmap() { memory_ = nullptr; }
+
+ // Get the size of the opened shared memory backing file.
+ // Note: This size is only available to the creator of the
+ // shared memory, and not to those that opened shared memory
+ // created externally.
+ // Returns 0 if not opened or unknown.
+ size_t max_size() const { return max_size_; }
+
+ // Gets a pointer to the opened memory space if it has been
+ // Mapped via Map(). Returns NULL if it is not mapped.
+ void* memory() const { return memory_.get(); }
+
+ // Extracts the underlying file handle, returning a RAII type.
+ // If `unmap_view` is true, this unmaps the memory as a side-effect (and
+ // cleans up any OS-specific resources).
+ mozilla::UniqueFileHandle TakeHandle(bool unmap_view = true) {
+ mozilla::UniqueFileHandle handle = std::move(mapped_file_);
+ Close(unmap_view);
+ return handle;
+ }
+
+ // Creates a copy of the underlying file handle, returning a RAII type.
+ // This operation may fail, in which case the returned file handle will be
+ // invalid.
+ mozilla::UniqueFileHandle CloneHandle();
+
+ // Make the shared memory object read-only, such that it cannot be
+ // written even if it's sent to an untrusted process. If it was
+ // mapped in this process, it will be unmapped. The object must
+ // have been created with CreateFreezeable(), and must not have
+ // already been shared to another process.
+ //
+ // (See bug 1479960 comment #0 for OS-specific implementation
+ // details.)
+ [[nodiscard]] bool Freeze() {
+ Unmap();
+ return ReadOnlyCopy(this);
+ }
+
+ // Similar to Freeze(), but assigns the read-only capability to
+ // another SharedMemory object and leaves this object's mapping in
+ // place and writeable. This can be used to broadcast data to
+ // several untrusted readers without copying.
+ //
+ // The other constraints of Freeze() still apply: this object closes
+ // its handle (as if by `Close(false)`), it cannot have been
+ // previously shared, and the read-only handle cannot be used to
+ // write the memory even by a malicious process.
+ //
+ // (The out parameter can currently be the same as `this` if and
+ // only if the memory was unmapped, but this is an implementation
+ // detail and shouldn't be relied on; for that use case Freeze()
+ // should be used instead.)
+ [[nodiscard]] bool ReadOnlyCopy(SharedMemory* ro_out);
+
+ // Closes the open shared memory segment.
+ // It is safe to call Close repeatedly.
+ void Close(bool unmap_view = true);
+
+ // Returns a page-aligned address at which the given number of bytes could
+ // probably be mapped. Returns NULL on error or if there is insufficient
+ // contiguous address space to map the required number of pages.
+ //
+ // Note that there is no guarantee that the given address space will actually
+ // be free by the time this function returns, since another thread might map
+ // something there in the meantime.
+ static void* FindFreeAddressSpace(size_t size);
+
+#ifdef XP_UNIX
+ // If named POSIX shm is being used, append the prefix (including
+ // the leading '/') that would be used by a process with the given
+ // pid to the given string and return true. If not, return false.
+ // (This is public so that the Linux sandboxing code can use it.)
+ static bool AppendPosixShmPrefix(std::string* str, pid_t pid);
+ // Similar, but simply returns whether POSIX shm is in use.
+ static bool UsingPosixShm();
+#endif
+
+ private:
+ bool CreateInternal(size_t size, bool freezeable);
+
+ // Unmapping shared memory requires the mapped size on Unix but not
+ // Windows; this encapsulates that difference.
+ struct MappingDeleter {
+#ifdef XP_UNIX
+ // A default-constructed deleter must be used only with nullptr
+ // (to allow default-constructing UniqueMapping). A deleter with
+ // a size must be used at most once.
+ size_t mapped_size_ = 0;
+ explicit MappingDeleter(size_t size) : mapped_size_(size) {}
+#endif
+ MappingDeleter() = default;
+ void operator()(void* ptr);
+ };
+ using UniqueMapping = mozilla::UniquePtr<void, MappingDeleter>;
+
+ UniqueMapping memory_;
+ size_t max_size_ = 0;
+ mozilla::UniqueFileHandle mapped_file_;
+#if defined(XP_WIN)
+ // If true indicates this came from an external source so needs extra checks
+ // before being mapped.
+ bool external_section_ = false;
+#elif !defined(ANDROID)
+ mozilla::UniqueFileHandle frozen_file_;
+ bool is_memfd_ = false;
+#endif
+ bool read_only_ = false;
+ bool freezeable_ = false;
+
+ DISALLOW_EVIL_CONSTRUCTORS(SharedMemory);
+};
+
+} // namespace base
+
+#endif // BASE_SHARED_MEMORY_H_
diff --git a/ipc/chromium/src/base/shared_memory_posix.cc b/ipc/chromium/src/base/shared_memory_posix.cc
new file mode 100644
index 0000000000..bfe20e343a
--- /dev/null
+++ b/ipc/chromium/src/base/shared_memory_posix.cc
@@ -0,0 +1,563 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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 "base/shared_memory.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#ifdef ANDROID
+# include "mozilla/Ashmem.h"
+#endif
+
+#ifdef XP_LINUX
+# include "linux_memfd_defs.h"
+#endif
+#ifdef MOZ_WIDGET_GTK
+# include "mozilla/WidgetUtilsGtk.h"
+#endif
+
+#ifdef __FreeBSD__
+# include <sys/capsicum.h>
+#endif
+
+#ifdef MOZ_VALGRIND
+# include <valgrind/valgrind.h>
+#endif
+
+#include "base/eintr_wrapper.h"
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "mozilla/Atomics.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/ProfilerThreadSleep.h"
+#include "mozilla/UniquePtrExtensions.h"
+#include "prenv.h"
+
+namespace base {
+
+void SharedMemory::MappingDeleter::operator()(void* ptr) {
+ // Check that this isn't a default-constructed deleter. (`munmap`
+ // is specified to fail with `EINVAL` if the length is 0, so this
+ // assertion isn't load-bearing.)
+ DCHECK(mapped_size_ != 0);
+ munmap(ptr, mapped_size_);
+ // Guard against multiple calls of the same deleter, which shouldn't
+ // happen (but could, if `UniquePtr::reset` were used). Calling
+ // `munmap` with an incorrect non-zero length would be bad.
+ mapped_size_ = 0;
+}
+
+SharedMemory::~SharedMemory() {
+ // This is almost equal to the default destructor, except for the
+ // warning message about unfrozen freezable memory.
+ Close();
+}
+
+bool SharedMemory::SetHandle(SharedMemoryHandle handle, bool read_only) {
+ DCHECK(!mapped_file_);
+#ifndef ANDROID
+ DCHECK(!frozen_file_);
+#endif
+
+ freezeable_ = false;
+ mapped_file_ = std::move(handle);
+ read_only_ = read_only;
+ // is_memfd_ only matters for freezing, which isn't possible
+ return true;
+}
+
+// static
+bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) {
+ return handle != nullptr;
+}
+
+// static
+SharedMemoryHandle SharedMemory::NULLHandle() { return nullptr; }
+
+// static
+bool SharedMemory::UsingPosixShm() {
+ // Undocumented feature of AppendPosixShmPrefix to reduce code
+ // duplication: if the string pointer is null, it's ignored.
+ return AppendPosixShmPrefix(nullptr, 0);
+}
+
+#ifdef ANDROID
+
+// Android has its own shared memory API, ashmem. It doesn't support
+// POSIX shm_open, and the memfd support (see below) also doesn't work
+// because its SELinux policy prevents the procfs operations we'd use
+// (see bug 1670277 for more details).
+
+// static
+bool SharedMemory::AppendPosixShmPrefix(std::string* str, pid_t pid) {
+ return false;
+}
+
+bool SharedMemory::CreateInternal(size_t size, bool freezeable) {
+ read_only_ = false;
+
+ DCHECK(size > 0);
+ DCHECK(!mapped_file_);
+
+ int fd = mozilla::android::ashmem_create(nullptr, size);
+ if (fd < 0) {
+ CHROMIUM_LOG(WARNING) << "failed to open shm: " << strerror(errno);
+ return false;
+ }
+
+ mapped_file_.reset(fd);
+ max_size_ = size;
+ freezeable_ = freezeable;
+ return true;
+}
+
+bool SharedMemory::ReadOnlyCopy(SharedMemory* ro_out) {
+ DCHECK(mapped_file_);
+ DCHECK(!read_only_);
+ CHECK(freezeable_);
+
+ if (ro_out == this) {
+ DCHECK(!memory_);
+ }
+
+ if (mozilla::android::ashmem_setProt(mapped_file_.get(), PROT_READ) != 0) {
+ CHROMIUM_LOG(WARNING) << "failed to set ashmem read-only: "
+ << strerror(errno);
+ return false;
+ }
+
+ mozilla::UniqueFileHandle ro_file = std::move(mapped_file_);
+
+ freezeable_ = false;
+ ro_out->Close();
+ ro_out->mapped_file_ = std::move(ro_file);
+ ro_out->max_size_ = max_size_;
+ ro_out->read_only_ = true;
+ ro_out->freezeable_ = false;
+
+ return true;
+}
+
+#else // not Android
+
+// memfd_create is a nonstandard interface for creating anonymous
+// shared memory accessible as a file descriptor but not tied to any
+// filesystem. It first appeared in Linux 3.17, and was adopted by
+// FreeBSD in version 13.
+
+# if !defined(HAVE_MEMFD_CREATE) && defined(XP_LINUX) && \
+ defined(SYS_memfd_create)
+
+// Older libc versions (e.g., glibc before 2.27) don't have the
+// wrapper, but we can supply our own; see `linux_memfd_defs.h`.
+
+static int memfd_create(const char* name, unsigned int flags) {
+ return syscall(SYS_memfd_create, name, flags);
+}
+
+# define HAVE_MEMFD_CREATE 1
+# endif
+
+// memfd supports having "seals" applied to the file, to prevent
+// various types of changes (which apply to all fds referencing the
+// file). Unfortunately, we can't rely on F_SEAL_WRITE to implement
+// Freeze(); see the comments in ReadOnlyCopy() below.
+//
+// Instead, to prevent a child process from regaining write access to
+// a read-only copy, the OS must also provide a way to remove write
+// permissions at the file descriptor level. This next section
+// attempts to accomplish that.
+
+# ifdef HAVE_MEMFD_CREATE
+# ifdef XP_LINUX
+# define USE_MEMFD_CREATE 1
+
+// To create a read-only duplicate of an fd, we can use procfs; the
+// same operation could restore write access, but sandboxing prevents
+// child processes from accessing /proc.
+//
+// (Note: if this ever changes to not use /proc, also reconsider how
+// and if HaveMemfd should check whether this works.)
+
+static int DupReadOnly(int fd) {
+ std::string path = StringPrintf("/proc/self/fd/%d", fd);
+ // procfs opens probably won't EINTR, but checking for it can't hurt
+ return HANDLE_EINTR(open(path.c_str(), O_RDONLY | O_CLOEXEC));
+}
+
+# elif defined(__FreeBSD__)
+# define USE_MEMFD_CREATE 1
+
+// FreeBSD's Capsicum framework allows irrevocably restricting the
+// operations permitted on a file descriptor.
+
+static int DupReadOnly(int fd) {
+ int rofd = dup(fd);
+ if (rofd < 0) {
+ return -1;
+ }
+
+ cap_rights_t rights;
+ cap_rights_init(&rights, CAP_FSTAT, CAP_MMAP_R);
+ if (cap_rights_limit(rofd, &rights) < 0) {
+ int err = errno;
+ close(rofd);
+ errno = err;
+ return -1;
+ }
+
+ return rofd;
+}
+
+# else // unhandled OS
+# warning "OS has memfd_create but no DupReadOnly implementation"
+# endif // OS selection
+# endif // HAVE_MEMFD_CREATE
+
+// Runtime detection for memfd support.
+static bool HaveMemfd() {
+# ifdef USE_MEMFD_CREATE
+ static const bool kHave = [] {
+ mozilla::UniqueFileHandle fd(
+ memfd_create("mozilla-ipc-test", MFD_CLOEXEC | MFD_ALLOW_SEALING));
+ if (!fd) {
+ DCHECK_EQ(errno, ENOSYS);
+ return false;
+ }
+
+ // Verify that DupReadOnly works; on Linux it's known to fail if:
+ //
+ // * SELinux assigns the memfd a type for which this process's
+ // domain doesn't have "open" permission; this is always the
+ // case on Android but could occur on desktop as well
+ //
+ // * /proc (used by the DupReadOnly implementation) isn't mounted,
+ // which is a configuration that the Tor Browser project is
+ // interested in as a way to reduce fingerprinting risk
+ //
+ // Sandboxed processes on Linux also can't use it if sandboxing
+ // has already been started, but that's expected. It should be
+ // safe for sandboxed child processes to use memfd even if an
+ // unsandboxed process couldn't freeze them, because freezing
+ // isn't allowed (or meaningful) for memory created by another
+ // process.
+
+ if (!PR_GetEnv("MOZ_SANDBOXED")) {
+ mozilla::UniqueFileHandle rofd(DupReadOnly(fd.get()));
+ if (!rofd) {
+ CHROMIUM_LOG(WARNING) << "read-only dup failed (" << strerror(errno)
+ << "); not using memfd";
+ return false;
+ }
+ }
+ return true;
+ }();
+ return kHave;
+# else
+ return false;
+# endif // USE_MEMFD_CREATE
+}
+
+// static
+bool SharedMemory::AppendPosixShmPrefix(std::string* str, pid_t pid) {
+ if (HaveMemfd()) {
+ return false;
+ }
+ // See also UsingPosixShm().
+ if (!str) {
+ return true;
+ }
+ *str += '/';
+# ifdef MOZ_WIDGET_GTK
+ // The Snap package environment doesn't provide a private /dev/shm
+ // (it's used for communication with services like PulseAudio);
+ // instead AppArmor is used to restrict access to it. Anything with
+ // this prefix is allowed:
+ if (const char* snap = mozilla::widget::GetSnapInstanceName()) {
+ StringAppendF(str, "snap.%s.", snap);
+ }
+# endif // XP_LINUX
+ // Hopefully the "implementation defined" name length limit is long
+ // enough for this.
+ StringAppendF(str, "org.mozilla.ipc.%d.", static_cast<int>(pid));
+ return true;
+}
+
+bool SharedMemory::CreateInternal(size_t size, bool freezeable) {
+ read_only_ = false;
+
+ DCHECK(size > 0);
+ DCHECK(!mapped_file_);
+ DCHECK(!frozen_file_);
+
+ mozilla::UniqueFileHandle fd;
+ mozilla::UniqueFileHandle frozen_fd;
+ bool is_memfd = false;
+
+# ifdef USE_MEMFD_CREATE
+ if (HaveMemfd()) {
+ const unsigned flags = MFD_CLOEXEC | (freezeable ? MFD_ALLOW_SEALING : 0);
+ fd.reset(memfd_create("mozilla-ipc", flags));
+ if (!fd) {
+ // In general it's too late to fall back here -- in a sandboxed
+ // child process, shm_open is already blocked. And it shouldn't
+ // be necessary.
+ CHROMIUM_LOG(WARNING) << "failed to create memfd: " << strerror(errno);
+ return false;
+ }
+ is_memfd = true;
+ if (freezeable) {
+ frozen_fd.reset(DupReadOnly(fd.get()));
+ if (!frozen_fd) {
+ CHROMIUM_LOG(WARNING)
+ << "failed to create read-only memfd: " << strerror(errno);
+ return false;
+ }
+ }
+ }
+# endif
+
+ if (!fd) {
+ // Generic Unix: shm_open + shm_unlink
+ do {
+ // The names don't need to be unique, but it saves time if they
+ // usually are.
+ static mozilla::Atomic<size_t> sNameCounter;
+ std::string name;
+ CHECK(AppendPosixShmPrefix(&name, getpid()));
+ StringAppendF(&name, "%zu", sNameCounter++);
+ // O_EXCL means the names being predictable shouldn't be a problem.
+ fd.reset(HANDLE_EINTR(
+ shm_open(name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600)));
+ if (fd) {
+ if (freezeable) {
+ frozen_fd.reset(HANDLE_EINTR(shm_open(name.c_str(), O_RDONLY, 0400)));
+ if (!frozen_fd) {
+ int open_err = errno;
+ shm_unlink(name.c_str());
+ DLOG(FATAL) << "failed to re-open freezeable shm: "
+ << strerror(open_err);
+ return false;
+ }
+ }
+ if (shm_unlink(name.c_str()) != 0) {
+ // This shouldn't happen, but if it does: assume the file is
+ // in fact leaked, and bail out now while it's still 0-length.
+ DLOG(FATAL) << "failed to unlink shm: " << strerror(errno);
+ return false;
+ }
+ }
+ } while (!fd && errno == EEXIST);
+ }
+
+ if (!fd) {
+ CHROMIUM_LOG(WARNING) << "failed to open shm: " << strerror(errno);
+ return false;
+ }
+
+ mozilla::Maybe<int> fallocateError;
+# if defined(HAVE_POSIX_FALLOCATE)
+ // Using posix_fallocate will ensure that there's actually space for this
+ // file. Otherwise we end up with a sparse file that can give SIGBUS if we
+ // run out of space while writing to it. (This doesn't apply to memfd.)
+ if (!is_memfd) {
+ int rv;
+ // Avoid repeated interruptions of posix_fallocate by the profiler's
+ // SIGPROF sampling signal. Indicating "thread sleep" here means we'll
+ // get up to one interruption but not more. See bug 1658847 for more.
+ // This has to be scoped outside the HANDLE_RV_EINTR retry loop.
+ {
+ AUTO_PROFILER_THREAD_SLEEP;
+
+ rv = HANDLE_RV_EINTR(
+ posix_fallocate(fd.get(), 0, static_cast<off_t>(size)));
+ }
+
+ // Some filesystems have trouble with posix_fallocate. For now, we must
+ // fallback ftruncate and accept the allocation failures like we do
+ // without posix_fallocate.
+ // See https://bugzilla.mozilla.org/show_bug.cgi?id=1618914
+ if (rv != 0 && rv != EOPNOTSUPP && rv != EINVAL && rv != ENODEV) {
+ CHROMIUM_LOG(WARNING)
+ << "fallocate failed to set shm size: " << strerror(rv);
+ return false;
+ }
+ fallocateError = mozilla::Some(rv);
+ }
+# endif
+
+ // If posix_fallocate isn't supported / relevant for this type of
+ // file (either failed with an expected error, or wasn't attempted),
+ // then set the size with ftruncate:
+ if (fallocateError != mozilla::Some(0)) {
+ int rv = HANDLE_EINTR(ftruncate(fd.get(), static_cast<off_t>(size)));
+ if (rv != 0) {
+ int ftruncate_errno = errno;
+ if (fallocateError) {
+ CHROMIUM_LOG(WARNING) << "fallocate failed to set shm size: "
+ << strerror(*fallocateError);
+ }
+ CHROMIUM_LOG(WARNING)
+ << "ftruncate failed to set shm size: " << strerror(ftruncate_errno);
+ return false;
+ }
+ }
+
+ mapped_file_ = std::move(fd);
+ frozen_file_ = std::move(frozen_fd);
+ max_size_ = size;
+ freezeable_ = freezeable;
+ is_memfd_ = is_memfd;
+ return true;
+}
+
+bool SharedMemory::ReadOnlyCopy(SharedMemory* ro_out) {
+ DCHECK(mapped_file_);
+ DCHECK(!read_only_);
+ CHECK(freezeable_);
+
+ if (ro_out == this) {
+ DCHECK(!memory_);
+ }
+
+# ifdef USE_MEMFD_CREATE
+# ifdef MOZ_VALGRIND
+ // Valgrind allows memfd_create but doesn't understand F_ADD_SEALS.
+ static const bool haveSeals = RUNNING_ON_VALGRIND == 0;
+# else
+ static const bool haveSeals = true;
+# endif
+ static const bool useSeals = !PR_GetEnv("MOZ_SHM_NO_SEALS");
+ if (is_memfd_ && haveSeals && useSeals) {
+ // Seals are added to the file as defense-in-depth. The primary
+ // method of access control is creating a read-only fd (using
+ // procfs in this case) and requiring that sandboxes processes not
+ // have access to /proc/self/fd to regain write permission; this
+ // is the same as with shm_open.
+ //
+ // Unfortunately, F_SEAL_WRITE is unreliable: if the process
+ // forked while there was a writeable mapping, it will inherit a
+ // copy of the mapping, which causes the seal to fail.
+ //
+ // (Also, in the future we may want to split this into separate
+ // classes for mappings and shared memory handles, which would
+ // complicate identifying the case where `F_SEAL_WRITE` would be
+ // possible even in the absence of races with fork.)
+ //
+ // However, Linux 5.1 added F_SEAL_FUTURE_WRITE, which prevents
+ // write operations afterwards, but existing writeable mappings
+ // are unaffected (similar to ashmem protection semantics).
+
+ const int seals = F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL;
+ int sealError = EINVAL;
+
+# ifdef F_SEAL_FUTURE_WRITE
+ sealError =
+ fcntl(mapped_file_.get(), F_ADD_SEALS, seals | F_SEAL_FUTURE_WRITE) == 0
+ ? 0
+ : errno;
+# endif // F_SEAL_FUTURE_WRITE
+ if (sealError == EINVAL) {
+ sealError =
+ fcntl(mapped_file_.get(), F_ADD_SEALS, seals) == 0 ? 0 : errno;
+ }
+ if (sealError != 0) {
+ CHROMIUM_LOG(WARNING) << "failed to seal memfd: " << strerror(errno);
+ return false;
+ }
+ }
+# else // !USE_MEMFD_CREATE
+ DCHECK(!is_memfd_);
+# endif
+
+ DCHECK(frozen_file_);
+ DCHECK(mapped_file_);
+ mapped_file_ = nullptr;
+ mozilla::UniqueFileHandle ro_file = std::move(frozen_file_);
+
+ DCHECK(ro_file);
+ freezeable_ = false;
+ ro_out->Close();
+ ro_out->mapped_file_ = std::move(ro_file);
+ ro_out->max_size_ = max_size_;
+ ro_out->read_only_ = true;
+ ro_out->freezeable_ = false;
+
+ return true;
+}
+
+#endif // not Android
+
+#ifndef MAP_NORESERVE
+# define MAP_NORESERVE 0
+#endif
+
+bool SharedMemory::Map(size_t bytes, void* fixed_address) {
+ if (!mapped_file_) {
+ return false;
+ }
+ DCHECK(!memory_);
+
+ // Don't use MAP_FIXED when a fixed_address was specified, since that can
+ // replace pages that are alread mapped at that address.
+ void* mem =
+ mmap(fixed_address, bytes, PROT_READ | (read_only_ ? 0 : PROT_WRITE),
+ MAP_SHARED, mapped_file_.get(), 0);
+
+ if (mem == MAP_FAILED) {
+ CHROMIUM_LOG(WARNING) << "Call to mmap failed: " << strerror(errno);
+ return false;
+ }
+
+ if (fixed_address && mem != fixed_address) {
+ bool munmap_succeeded = munmap(mem, bytes) == 0;
+ DCHECK(munmap_succeeded) << "Call to munmap failed, errno=" << errno;
+ return false;
+ }
+
+ memory_ = UniqueMapping(mem, MappingDeleter(bytes));
+ return true;
+}
+
+void* SharedMemory::FindFreeAddressSpace(size_t size) {
+ void* memory = mmap(nullptr, size, PROT_NONE,
+ MAP_ANONYMOUS | MAP_NORESERVE | MAP_PRIVATE, -1, 0);
+ if (memory == MAP_FAILED) {
+ return nullptr;
+ }
+ munmap(memory, size);
+ return memory;
+}
+
+SharedMemoryHandle SharedMemory::CloneHandle() {
+ freezeable_ = false;
+ const int new_fd = dup(mapped_file_.get());
+ if (new_fd < 0) {
+ CHROMIUM_LOG(WARNING) << "failed to duplicate file descriptor: "
+ << strerror(errno);
+ return nullptr;
+ }
+ return mozilla::UniqueFileHandle(new_fd);
+}
+void SharedMemory::Close(bool unmap_view) {
+ if (unmap_view) {
+ Unmap();
+ }
+
+ mapped_file_ = nullptr;
+#ifndef ANDROID
+ if (frozen_file_) {
+ CHROMIUM_LOG(WARNING) << "freezeable shared memory was never frozen";
+ frozen_file_ = nullptr;
+ }
+#endif
+}
+
+} // namespace base
diff --git a/ipc/chromium/src/base/shared_memory_win.cc b/ipc/chromium/src/base/shared_memory_win.cc
new file mode 100644
index 0000000000..8269912156
--- /dev/null
+++ b/ipc/chromium/src/base/shared_memory_win.cc
@@ -0,0 +1,266 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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 "base/shared_memory.h"
+
+#include "base/logging.h"
+#include "base/win_util.h"
+#include "base/string_util.h"
+#include "mozilla/ipc/ProtocolUtils.h"
+#include "mozilla/RandomNum.h"
+#include "nsDebug.h"
+#include "nsString.h"
+#ifdef MOZ_MEMORY
+# include "mozmemory_utils.h"
+#endif
+
+namespace {
+// NtQuerySection is an internal (but believed to be stable) API and the
+// structures it uses are defined in nt_internals.h.
+// So we have to define them ourselves.
+typedef enum _SECTION_INFORMATION_CLASS {
+ SectionBasicInformation,
+} SECTION_INFORMATION_CLASS;
+
+typedef struct _SECTION_BASIC_INFORMATION {
+ PVOID BaseAddress;
+ ULONG Attributes;
+ LARGE_INTEGER Size;
+} SECTION_BASIC_INFORMATION, *PSECTION_BASIC_INFORMATION;
+
+typedef ULONG(__stdcall* NtQuerySectionType)(
+ HANDLE SectionHandle, SECTION_INFORMATION_CLASS SectionInformationClass,
+ PVOID SectionInformation, ULONG SectionInformationLength,
+ PULONG ResultLength);
+
+// Checks if the section object is safe to map. At the moment this just means
+// it's not an image section.
+bool IsSectionSafeToMap(HANDLE handle) {
+ static NtQuerySectionType nt_query_section_func =
+ reinterpret_cast<NtQuerySectionType>(
+ ::GetProcAddress(::GetModuleHandle(L"ntdll.dll"), "NtQuerySection"));
+ DCHECK(nt_query_section_func);
+
+ // The handle must have SECTION_QUERY access for this to succeed.
+ SECTION_BASIC_INFORMATION basic_information = {};
+ ULONG status =
+ nt_query_section_func(handle, SectionBasicInformation, &basic_information,
+ sizeof(basic_information), nullptr);
+ if (status) {
+ return false;
+ }
+
+ return (basic_information.Attributes & SEC_IMAGE) != SEC_IMAGE;
+}
+
+} // namespace
+
+namespace base {
+
+void SharedMemory::MappingDeleter::operator()(void* ptr) {
+ UnmapViewOfFile(ptr);
+}
+
+SharedMemory::~SharedMemory() = default;
+
+bool SharedMemory::SetHandle(SharedMemoryHandle handle, bool read_only) {
+ DCHECK(!mapped_file_);
+
+ external_section_ = true;
+ freezeable_ = false; // just in case
+ mapped_file_ = std::move(handle);
+ read_only_ = read_only;
+ return true;
+}
+
+// static
+bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) {
+ return handle != nullptr;
+}
+
+// static
+SharedMemoryHandle SharedMemory::NULLHandle() { return nullptr; }
+
+// Wrapper around CreateFileMappingW for pagefile-backed regions. When out of
+// memory, may attempt to stall and retry rather than returning immediately, in
+// hopes that the page file is about to be expanded by Windows. (bug 1822383,
+// bug 1716727)
+//
+// This method is largely a copy of the MozVirtualAlloc method from
+// mozjemalloc.cpp, which implements this strategy for VirtualAlloc calls,
+// except re-purposed to handle CreateFileMapping.
+static HANDLE MozCreateFileMappingW(
+ LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect,
+ DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCWSTR lpName) {
+#ifdef MOZ_MEMORY
+ constexpr auto IsOOMError = [] {
+ return ::GetLastError() == ERROR_COMMITMENT_LIMIT;
+ };
+
+ {
+ HANDLE handle = ::CreateFileMappingW(
+ INVALID_HANDLE_VALUE, lpFileMappingAttributes, flProtect,
+ dwMaximumSizeHigh, dwMaximumSizeLow, lpName);
+ if (MOZ_LIKELY(handle)) {
+ MOZ_DIAGNOSTIC_ASSERT(handle != INVALID_HANDLE_VALUE,
+ "::CreateFileMapping should return NULL, not "
+ "INVALID_HANDLE_VALUE, on failure");
+ return handle;
+ }
+
+ // We can't do anything for errors other than OOM.
+ if (!IsOOMError()) {
+ return nullptr;
+ }
+ }
+
+ // Retry as many times as desired (possibly zero).
+ const mozilla::StallSpecs stallSpecs = mozilla::GetAllocatorStallSpecs();
+
+ const auto ret =
+ stallSpecs.StallAndRetry(&::Sleep, [&]() -> std::optional<HANDLE> {
+ HANDLE handle = ::CreateFileMappingW(
+ INVALID_HANDLE_VALUE, lpFileMappingAttributes, flProtect,
+ dwMaximumSizeHigh, dwMaximumSizeLow, lpName);
+
+ if (handle) {
+ MOZ_DIAGNOSTIC_ASSERT(handle != INVALID_HANDLE_VALUE,
+ "::CreateFileMapping should return NULL, not "
+ "INVALID_HANDLE_VALUE, on failure");
+ return handle;
+ }
+
+ // Failure for some reason other than OOM.
+ if (!IsOOMError()) {
+ return nullptr;
+ }
+
+ return std::nullopt;
+ });
+
+ return ret.value_or(nullptr);
+#else
+ return ::CreateFileMappingW(INVALID_HANDLE_VALUE, lpFileMappingAttributes,
+ flProtect, dwMaximumSizeHigh, dwMaximumSizeLow,
+ lpName);
+#endif
+}
+
+bool SharedMemory::CreateInternal(size_t size, bool freezeable) {
+ DCHECK(!mapped_file_);
+ read_only_ = false;
+
+ // If the shared memory object has no DACL, any process can
+ // duplicate its handles with any access rights; e.g., re-add write
+ // access to a read-only handle. To prevent that, we give it an
+ // empty DACL, so that no process can do that.
+ SECURITY_ATTRIBUTES sa, *psa = nullptr;
+ SECURITY_DESCRIPTOR sd;
+ ACL dacl;
+
+ if (freezeable) {
+ psa = &sa;
+ sa.nLength = sizeof(sa);
+ sa.lpSecurityDescriptor = &sd;
+ sa.bInheritHandle = FALSE;
+
+ if (NS_WARN_IF(!InitializeAcl(&dacl, sizeof(dacl), ACL_REVISION)) ||
+ NS_WARN_IF(
+ !InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) ||
+ NS_WARN_IF(!SetSecurityDescriptorDacl(&sd, TRUE, &dacl, FALSE))) {
+ return false;
+ }
+ }
+
+ mapped_file_.reset(MozCreateFileMappingW(psa, PAGE_READWRITE, 0,
+ static_cast<DWORD>(size), nullptr));
+ if (!mapped_file_) return false;
+
+ max_size_ = size;
+ freezeable_ = freezeable;
+ return true;
+}
+
+bool SharedMemory::ReadOnlyCopy(SharedMemory* ro_out) {
+ DCHECK(!read_only_);
+ CHECK(freezeable_);
+
+ if (ro_out == this) {
+ DCHECK(!memory_);
+ }
+
+ HANDLE ro_handle;
+ if (!::DuplicateHandle(GetCurrentProcess(), mapped_file_.release(),
+ GetCurrentProcess(), &ro_handle,
+ GENERIC_READ | FILE_MAP_READ, false,
+ DUPLICATE_CLOSE_SOURCE)) {
+ // DUPLICATE_CLOSE_SOURCE applies even if there is an error.
+ return false;
+ }
+
+ freezeable_ = false;
+
+ ro_out->Close();
+ ro_out->mapped_file_.reset(ro_handle);
+ ro_out->max_size_ = max_size_;
+ ro_out->read_only_ = true;
+ ro_out->freezeable_ = false;
+ ro_out->external_section_ = external_section_;
+
+ return true;
+}
+
+bool SharedMemory::Map(size_t bytes, void* fixed_address) {
+ if (!mapped_file_) {
+ return false;
+ }
+
+ if (external_section_ && !IsSectionSafeToMap(mapped_file_.get())) {
+ return false;
+ }
+
+ void* mem = MapViewOfFileEx(
+ mapped_file_.get(),
+ read_only_ ? FILE_MAP_READ : FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, bytes,
+ fixed_address);
+ if (mem) {
+ MOZ_ASSERT(!fixed_address || mem == fixed_address,
+ "MapViewOfFileEx returned an expected address");
+ memory_.reset(mem);
+ return true;
+ }
+ return false;
+}
+
+void* SharedMemory::FindFreeAddressSpace(size_t size) {
+ void* memory = VirtualAlloc(NULL, size, MEM_RESERVE, PAGE_NOACCESS);
+ if (memory) {
+ VirtualFree(memory, 0, MEM_RELEASE);
+ }
+ return memory;
+}
+
+SharedMemoryHandle SharedMemory::CloneHandle() {
+ freezeable_ = false;
+ HANDLE handle = INVALID_HANDLE_VALUE;
+ if (DuplicateHandle(GetCurrentProcess(), mapped_file_.get(),
+ GetCurrentProcess(), &handle, 0, false,
+ DUPLICATE_SAME_ACCESS)) {
+ return SharedMemoryHandle(handle);
+ }
+ NS_WARNING("DuplicateHandle Failed!");
+ return nullptr;
+}
+
+void SharedMemory::Close(bool unmap_view) {
+ if (unmap_view) {
+ Unmap();
+ }
+
+ mapped_file_ = nullptr;
+}
+
+} // namespace base
diff --git a/ipc/chromium/src/base/stack_container.h b/ipc/chromium/src/base/stack_container.h
new file mode 100644
index 0000000000..d9add9904c
--- /dev/null
+++ b/ipc/chromium/src/base/stack_container.h
@@ -0,0 +1,244 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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_STACK_CONTAINER_H_
+#define BASE_STACK_CONTAINER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+
+// This allocator can be used with STL containers to provide a stack buffer
+// from which to allocate memory and overflows onto the heap. This stack buffer
+// would be allocated on the stack and allows us to avoid heap operations in
+// some situations.
+//
+// STL likes to make copies of allocators, so the allocator itself can't hold
+// the data. Instead, we make the creator responsible for creating a
+// StackAllocator::Source which contains the data. Copying the allocator
+// merely copies the pointer to this shared source, so all allocators created
+// based on our allocator will share the same stack buffer.
+//
+// This stack buffer implementation is very simple. The first allocation that
+// fits in the stack buffer will use the stack buffer. Any subsequent
+// allocations will not use the stack buffer, even if there is unused room.
+// This makes it appropriate for array-like containers, but the caller should
+// be sure to reserve() in the container up to the stack buffer size. Otherwise
+// the container will allocate a small array which will "use up" the stack
+// buffer.
+template <typename T, size_t stack_capacity>
+class StackAllocator : public std::allocator<T> {
+ public:
+ typedef typename std::allocator<T>::pointer pointer;
+ typedef typename std::allocator<T>::size_type size_type;
+
+ // Backing store for the allocator. The container owner is responsible for
+ // maintaining this for as long as any containers using this allocator are
+ // live.
+ struct Source {
+ Source() : used_stack_buffer_(false) {}
+
+ // Casts the buffer in its right type.
+ T* stack_buffer() { return reinterpret_cast<T*>(stack_buffer_); }
+ const T* stack_buffer() const {
+ return reinterpret_cast<const T*>(stack_buffer_);
+ }
+
+ //
+ // IMPORTANT: Take care to ensure that stack_buffer_ is aligned
+ // since it is used to mimic an array of T.
+ // Be careful while declaring any unaligned types (like bool)
+ // before stack_buffer_.
+ //
+
+ // The buffer itself. It is not of type T because we don't want the
+ // constructors and destructors to be automatically called. Define a POD
+ // buffer of the right size instead.
+ char stack_buffer_[sizeof(T[stack_capacity])];
+
+ // Set when the stack buffer is used for an allocation. We do not track
+ // how much of the buffer is used, only that somebody is using it.
+ bool used_stack_buffer_;
+ };
+
+ // Used by containers when they want to refer to an allocator of type U.
+ template <typename U>
+ struct rebind {
+ typedef StackAllocator<U, stack_capacity> other;
+ };
+
+ // For the straight up copy c-tor, we can share storage.
+ StackAllocator(const StackAllocator<T, stack_capacity>& rhs)
+ : source_(rhs.source_) {}
+
+ // ISO C++ requires the following constructor to be defined,
+ // and std::vector in VC++2008SP1 Release fails with an error
+ // in the class _Container_base_aux_alloc_real (from <xutility>)
+ // if the constructor does not exist.
+ // For this constructor, we cannot share storage; there's
+ // no guarantee that the Source buffer of Ts is large enough
+ // for Us.
+ // TODO: If we were fancy pants, perhaps we could share storage
+ // iff sizeof(T) == sizeof(U).
+ template <typename U, size_t other_capacity>
+ explicit StackAllocator(const StackAllocator<U, other_capacity>& other)
+ : source_(NULL) {}
+
+ explicit StackAllocator(Source* source) : source_(source) {}
+
+ // Actually do the allocation. Use the stack buffer if nobody has used it yet
+ // and the size requested fits. Otherwise, fall through to the standard
+ // allocator.
+ pointer allocate(size_type n, void* hint = 0) {
+ if (source_ != NULL && !source_->used_stack_buffer_ &&
+ n <= stack_capacity) {
+ source_->used_stack_buffer_ = true;
+ return source_->stack_buffer();
+ } else {
+ return std::allocator<T>::allocate(n, hint);
+ }
+ }
+
+ // Free: when trying to free the stack buffer, just mark it as free. For
+ // non-stack-buffer pointers, just fall though to the standard allocator.
+ void deallocate(pointer p, size_type n) {
+ if (source_ != NULL && p == source_->stack_buffer())
+ source_->used_stack_buffer_ = false;
+ else
+ std::allocator<T>::deallocate(p, n);
+ }
+
+ private:
+ Source* source_;
+};
+
+// A wrapper around STL containers that maintains a stack-sized buffer that the
+// initial capacity of the vector is based on. Growing the container beyond the
+// stack capacity will transparently overflow onto the heap. The container must
+// support reserve().
+//
+// WATCH OUT: the ContainerType MUST use the proper StackAllocator for this
+// type. This object is really intended to be used only internally. You'll want
+// to use the wrappers below for different types.
+template <typename TContainerType, int stack_capacity>
+class StackContainer {
+ public:
+ typedef TContainerType ContainerType;
+ typedef typename ContainerType::value_type ContainedType;
+ typedef StackAllocator<ContainedType, stack_capacity> Allocator;
+
+ // Allocator must be constructed before the container!
+ StackContainer() : allocator_(&stack_data_), container_(allocator_) {
+ // Make the container use the stack allocation by reserving our buffer size
+ // before doing anything else.
+ container_.reserve(stack_capacity);
+ }
+
+ // Getters for the actual container.
+ //
+ // Danger: any copies of this made using the copy constructor must have
+ // shorter lifetimes than the source. The copy will share the same allocator
+ // and therefore the same stack buffer as the original. Use std::copy to
+ // copy into a "real" container for longer-lived objects.
+ ContainerType& container() { return container_; }
+ const ContainerType& container() const { return container_; }
+
+ // Support operator-> to get to the container. This allows nicer syntax like:
+ // StackContainer<...> foo;
+ // std::sort(foo->begin(), foo->end());
+ ContainerType* operator->() { return &container_; }
+ const ContainerType* operator->() const { return &container_; }
+
+#ifdef UNIT_TEST
+ // Retrieves the stack source so that that unit tests can verify that the
+ // buffer is being used properly.
+ const typename Allocator::Source& stack_data() const { return stack_data_; }
+#endif
+
+ protected:
+ typename Allocator::Source stack_data_;
+ Allocator allocator_;
+ ContainerType container_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(StackContainer);
+};
+
+// StackString
+template <size_t stack_capacity>
+class StackString
+ : public StackContainer<
+ std::basic_string<char, std::char_traits<char>,
+ StackAllocator<char, stack_capacity> >,
+ stack_capacity> {
+ public:
+ StackString()
+ : StackContainer<std::basic_string<char, std::char_traits<char>,
+ StackAllocator<char, stack_capacity> >,
+ stack_capacity>() {}
+
+ private:
+ DISALLOW_EVIL_CONSTRUCTORS(StackString);
+};
+
+// StackWString
+template <size_t stack_capacity>
+class StackWString
+ : public StackContainer<
+ std::basic_string<wchar_t, std::char_traits<wchar_t>,
+ StackAllocator<wchar_t, stack_capacity> >,
+ stack_capacity> {
+ public:
+ StackWString()
+ : StackContainer<
+ std::basic_string<wchar_t, std::char_traits<wchar_t>,
+ StackAllocator<wchar_t, stack_capacity> >,
+ stack_capacity>() {}
+
+ private:
+ DISALLOW_EVIL_CONSTRUCTORS(StackWString);
+};
+
+// StackVector
+//
+// Example:
+// StackVector<int, 16> foo;
+// foo->push_back(22); // we have overloaded operator->
+// foo[0] = 10; // as well as operator[]
+template <typename T, size_t stack_capacity>
+class StackVector
+ : public StackContainer<std::vector<T, StackAllocator<T, stack_capacity> >,
+ stack_capacity> {
+ public:
+ StackVector()
+ : StackContainer<std::vector<T, StackAllocator<T, stack_capacity> >,
+ stack_capacity>() {}
+
+ // We need to put this in STL containers sometimes, which requires a copy
+ // constructor. We can't call the regular copy constructor because that will
+ // take the stack buffer from the original. Here, we create an empty object
+ // and make a stack buffer of its own.
+ StackVector(const StackVector<T, stack_capacity>& other)
+ : StackContainer<std::vector<T, StackAllocator<T, stack_capacity> >,
+ stack_capacity>() {
+ this->container().assign(other->begin(), other->end());
+ }
+
+ StackVector<T, stack_capacity>& operator=(
+ const StackVector<T, stack_capacity>& other) {
+ this->container().assign(other->begin(), other->end());
+ return *this;
+ }
+
+ // Vectors are commonly indexed, which isn't very convenient even with
+ // operator-> (using "->at()" does exception stuff we don't want).
+ T& operator[](size_t i) { return this->container().operator[](i); }
+ const T& operator[](size_t i) const {
+ return this->container().operator[](i);
+ }
+};
+
+#endif // BASE_STACK_CONTAINER_H_
diff --git a/ipc/chromium/src/base/stl_util-inl.h b/ipc/chromium/src/base/stl_util-inl.h
new file mode 100644
index 0000000000..034c16049c
--- /dev/null
+++ b/ipc/chromium/src/base/stl_util-inl.h
@@ -0,0 +1,435 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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.
+
+// STL utility functions. Usually, these replace built-in, but slow(!),
+// STL functions with more efficient versions.
+
+#ifndef BASE_STL_UTIL_INL_H_
+#define BASE_STL_UTIL_INL_H_
+
+#include <string.h> // for memcpy
+#include <functional>
+#include <set>
+#include <string>
+#include <vector>
+#include <cassert>
+
+// Clear internal memory of an STL object.
+// STL clear()/reserve(0) does not always free internal memory allocated
+// This function uses swap/destructor to ensure the internal memory is freed.
+template <class T>
+void STLClearObject(T* obj) {
+ T tmp;
+ tmp.swap(*obj);
+ obj->reserve(0); // this is because sometimes "T tmp" allocates objects with
+ // memory (arena implementation?). use reserve()
+ // to clear() even if it doesn't always work
+}
+
+// Reduce memory usage on behalf of object if it is using more than
+// "bytes" bytes of space. By default, we clear objects over 1MB.
+template <class T>
+inline void STLClearIfBig(T* obj, size_t limit = 1 << 20) {
+ if (obj->capacity() >= limit) {
+ STLClearObject(obj);
+ } else {
+ obj->clear();
+ }
+}
+
+// Reserve space for STL object.
+// STL's reserve() will always copy.
+// This function avoid the copy if we already have capacity
+template <class T>
+void STLReserveIfNeeded(T* obj, int new_size) {
+ if (obj->capacity() < new_size) // increase capacity
+ obj->reserve(new_size);
+ else if (obj->size() > new_size) // reduce size
+ obj->resize(new_size);
+}
+
+// STLDeleteContainerPointers()
+// For a range within a container of pointers, calls delete
+// (non-array version) on these pointers.
+// NOTE: for these three functions, we could just implement a DeleteObject
+// functor and then call for_each() on the range and functor, but this
+// requires us to pull in all of algorithm.h, which seems expensive.
+// For hash_[multi]set, it is important that this deletes behind the iterator
+// because the hash_set may call the hash function on the iterator when it is
+// advanced, which could result in the hash function trying to deference a
+// stale pointer.
+template <class ForwardIterator>
+void STLDeleteContainerPointers(ForwardIterator begin, ForwardIterator end) {
+ while (begin != end) {
+ ForwardIterator temp = begin;
+ ++begin;
+ delete *temp;
+ }
+}
+
+// STLDeleteContainerPairPointers()
+// For a range within a container of pairs, calls delete
+// (non-array version) on BOTH items in the pairs.
+// NOTE: Like STLDeleteContainerPointers, it is important that this deletes
+// behind the iterator because if both the key and value are deleted, the
+// container may call the hash function on the iterator when it is advanced,
+// which could result in the hash function trying to dereference a stale
+// pointer.
+template <class ForwardIterator>
+void STLDeleteContainerPairPointers(ForwardIterator begin,
+ ForwardIterator end) {
+ while (begin != end) {
+ ForwardIterator temp = begin;
+ ++begin;
+ delete temp->first;
+ delete temp->second;
+ }
+}
+
+// STLDeleteContainerPairFirstPointers()
+// For a range within a container of pairs, calls delete (non-array version)
+// on the FIRST item in the pairs.
+// NOTE: Like STLDeleteContainerPointers, deleting behind the iterator.
+template <class ForwardIterator>
+void STLDeleteContainerPairFirstPointers(ForwardIterator begin,
+ ForwardIterator end) {
+ while (begin != end) {
+ ForwardIterator temp = begin;
+ ++begin;
+ delete temp->first;
+ }
+}
+
+// STLDeleteContainerPairSecondPointers()
+// For a range within a container of pairs, calls delete
+// (non-array version) on the SECOND item in the pairs.
+template <class ForwardIterator>
+void STLDeleteContainerPairSecondPointers(ForwardIterator begin,
+ ForwardIterator end) {
+ while (begin != end) {
+ delete begin->second;
+ ++begin;
+ }
+}
+
+template <typename T>
+inline void STLAssignToVector(std::vector<T>* vec, const T* ptr, size_t n) {
+ vec->resize(n);
+ memcpy(&vec->front(), ptr, n * sizeof(T));
+}
+
+/***** Hack to allow faster assignment to a vector *****/
+
+// This routine speeds up an assignment of 32 bytes to a vector from
+// about 250 cycles per assignment to about 140 cycles.
+//
+// Usage:
+// STLAssignToVectorChar(&vec, ptr, size);
+// STLAssignToString(&str, ptr, size);
+
+inline void STLAssignToVectorChar(std::vector<char>* vec, const char* ptr,
+ size_t n) {
+ STLAssignToVector(vec, ptr, n);
+}
+
+inline void STLAssignToString(std::string* str, const char* ptr, size_t n) {
+ str->resize(n);
+ memcpy(&*str->begin(), ptr, n);
+}
+
+// To treat a possibly-empty vector as an array, use these functions.
+// If you know the array will never be empty, you can use &*v.begin()
+// directly, but that is allowed to dump core if v is empty. This
+// function is the most efficient code that will work, taking into
+// account how our STL is actually implemented. THIS IS NON-PORTABLE
+// CODE, so call us instead of repeating the nonportable code
+// everywhere. If our STL implementation changes, we will need to
+// change this as well.
+
+template <typename T>
+inline T* vector_as_array(std::vector<T>* v) {
+#ifdef NDEBUG
+ return &*v->begin();
+#else
+ return v->empty() ? NULL : &*v->begin();
+#endif
+}
+
+template <typename T>
+inline const T* vector_as_array(const std::vector<T>* v) {
+#ifdef NDEBUG
+ return &*v->begin();
+#else
+ return v->empty() ? NULL : &*v->begin();
+#endif
+}
+
+// Return a mutable char* pointing to a string's internal buffer,
+// which may not be null-terminated. Writing through this pointer will
+// modify the string.
+//
+// string_as_array(&str)[i] is valid for 0 <= i < str.size() until the
+// next call to a string method that invalidates iterators.
+//
+// As of 2006-04, there is no standard-blessed way of getting a
+// mutable reference to a string's internal buffer. However, issue 530
+// (http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-active.html#530)
+// proposes this as the method. According to Matt Austern, this should
+// already work on all current implementations.
+inline char* string_as_array(std::string* str) {
+ // DO NOT USE const_cast<char*>(str->data())! See the unittest for why.
+ return str->empty() ? NULL : &*str->begin();
+}
+
+// These are methods that test two hash maps/sets for equality. These exist
+// because the == operator in the STL can return false when the maps/sets
+// contain identical elements. This is because it compares the internal hash
+// tables which may be different if the order of insertions and deletions
+// differed.
+
+template <class HashSet>
+inline bool HashSetEquality(const HashSet& set_a, const HashSet& set_b) {
+ if (set_a.size() != set_b.size()) return false;
+ for (typename HashSet::const_iterator i = set_a.begin(); i != set_a.end();
+ ++i) {
+ if (set_b.find(*i) == set_b.end()) return false;
+ }
+ return true;
+}
+
+template <class HashMap>
+inline bool HashMapEquality(const HashMap& map_a, const HashMap& map_b) {
+ if (map_a.size() != map_b.size()) return false;
+ for (typename HashMap::const_iterator i = map_a.begin(); i != map_a.end();
+ ++i) {
+ typename HashMap::const_iterator j = map_b.find(i->first);
+ if (j == map_b.end()) return false;
+ if (i->second != j->second) return false;
+ }
+ return true;
+}
+
+// The following functions are useful for cleaning up STL containers
+// whose elements point to allocated memory.
+
+// STLDeleteElements() deletes all the elements in an STL container and clears
+// the container. This function is suitable for use with a vector, set,
+// hash_set, or any other STL container which defines sensible begin(), end(),
+// and clear() methods.
+//
+// If container is NULL, this function is a no-op.
+//
+// As an alternative to calling STLDeleteElements() directly, consider
+// STLElementDeleter (defined below), which ensures that your container's
+// elements are deleted when the STLElementDeleter goes out of scope.
+template <class T>
+void STLDeleteElements(T* container) {
+ if (!container) return;
+ STLDeleteContainerPointers(container->begin(), container->end());
+ container->clear();
+}
+
+// Given an STL container consisting of (key, value) pairs, STLDeleteValues
+// deletes all the "value" components and clears the container. Does nothing
+// in the case it's given a NULL pointer.
+
+template <class T>
+void STLDeleteValues(T* v) {
+ if (!v) return;
+ for (typename T::iterator i = v->begin(); i != v->end(); ++i) {
+ delete i->second;
+ }
+ v->clear();
+}
+
+// The following classes provide a convenient way to delete all elements or
+// values from STL containers when they goes out of scope. This greatly
+// simplifies code that creates temporary objects and has multiple return
+// statements. Example:
+//
+// vector<MyProto *> tmp_proto;
+// STLElementDeleter<vector<MyProto *> > d(&tmp_proto);
+// if (...) return false;
+// ...
+// return success;
+
+// Given a pointer to an STL container this class will delete all the element
+// pointers when it goes out of scope.
+
+template <class STLContainer>
+class STLElementDeleter {
+ public:
+ explicit STLElementDeleter(STLContainer* ptr) : container_ptr_(ptr) {}
+ ~STLElementDeleter() { STLDeleteElements(container_ptr_); }
+
+ private:
+ STLContainer* container_ptr_;
+};
+
+// Given a pointer to an STL container this class will delete all the value
+// pointers when it goes out of scope.
+
+template <class STLContainer>
+class STLValueDeleter {
+ public:
+ explicit STLValueDeleter(STLContainer* ptr) : container_ptr_(ptr) {}
+ ~STLValueDeleter() { STLDeleteValues(container_ptr_); }
+
+ private:
+ STLContainer* container_ptr_;
+};
+
+// Forward declare some callback classes in callback.h for STLBinaryFunction
+template <class R, class T1, class T2>
+class ResultCallback2;
+
+// STLBinaryFunction is a wrapper for the ResultCallback2 class in callback.h
+// It provides an operator () method instead of a Run method, so it may be
+// passed to STL functions in <algorithm>.
+//
+// The client should create callback with NewPermanentCallback, and should
+// delete callback after it is done using the STLBinaryFunction.
+
+template <class Result, class Arg1, class Arg2>
+class STLBinaryFunction : public std::binary_function<Arg1, Arg2, Result> {
+ public:
+ typedef ResultCallback2<Result, Arg1, Arg2> Callback;
+
+ explicit STLBinaryFunction(Callback* callback) : callback_(callback) {
+ assert(callback_);
+ }
+
+ Result operator()(Arg1 arg1, Arg2 arg2) { return callback_->Run(arg1, arg2); }
+
+ private:
+ Callback* callback_;
+};
+
+// STLBinaryPredicate is a specialized version of STLBinaryFunction, where the
+// return type is bool and both arguments have type Arg. It can be used
+// wherever STL requires a StrictWeakOrdering, such as in sort() or
+// lower_bound().
+//
+// templated typedefs are not supported, so instead we use inheritance.
+
+template <class Arg>
+class STLBinaryPredicate : public STLBinaryFunction<bool, Arg, Arg> {
+ public:
+ typedef typename STLBinaryPredicate<Arg>::Callback Callback;
+ explicit STLBinaryPredicate(Callback* callback)
+ : STLBinaryFunction<bool, Arg, Arg>(callback) {}
+};
+
+// Functors that compose arbitrary unary and binary functions with a
+// function that "projects" one of the members of a pair.
+// Specifically, if p1 and p2, respectively, are the functions that
+// map a pair to its first and second, respectively, members, the
+// table below summarizes the functions that can be constructed:
+//
+// * UnaryOperate1st<pair>(f) returns the function x -> f(p1(x))
+// * UnaryOperate2nd<pair>(f) returns the function x -> f(p2(x))
+// * BinaryOperate1st<pair>(f) returns the function (x,y) -> f(p1(x),p1(y))
+// * BinaryOperate2nd<pair>(f) returns the function (x,y) -> f(p2(x),p2(y))
+//
+// A typical usage for these functions would be when iterating over
+// the contents of an STL map. For other sample usage, see the unittest.
+
+template <typename Pair, typename UnaryOp>
+class UnaryOperateOnFirst
+ : public std::unary_function<Pair, typename UnaryOp::result_type> {
+ public:
+ UnaryOperateOnFirst() {}
+
+ explicit UnaryOperateOnFirst(const UnaryOp& f) : f_(f) {}
+
+ typename UnaryOp::result_type operator()(const Pair& p) const {
+ return f_(p.first);
+ }
+
+ private:
+ UnaryOp f_;
+};
+
+template <typename Pair, typename UnaryOp>
+UnaryOperateOnFirst<Pair, UnaryOp> UnaryOperate1st(const UnaryOp& f) {
+ return UnaryOperateOnFirst<Pair, UnaryOp>(f);
+}
+
+template <typename Pair, typename UnaryOp>
+class UnaryOperateOnSecond
+ : public std::unary_function<Pair, typename UnaryOp::result_type> {
+ public:
+ UnaryOperateOnSecond() {}
+
+ explicit UnaryOperateOnSecond(const UnaryOp& f) : f_(f) {}
+
+ typename UnaryOp::result_type operator()(const Pair& p) const {
+ return f_(p.second);
+ }
+
+ private:
+ UnaryOp f_;
+};
+
+template <typename Pair, typename UnaryOp>
+UnaryOperateOnSecond<Pair, UnaryOp> UnaryOperate2nd(const UnaryOp& f) {
+ return UnaryOperateOnSecond<Pair, UnaryOp>(f);
+}
+
+template <typename Pair, typename BinaryOp>
+class BinaryOperateOnFirst
+ : public std::binary_function<Pair, Pair, typename BinaryOp::result_type> {
+ public:
+ BinaryOperateOnFirst() {}
+
+ explicit BinaryOperateOnFirst(const BinaryOp& f) : f_(f) {}
+
+ typename BinaryOp::result_type operator()(const Pair& p1,
+ const Pair& p2) const {
+ return f_(p1.first, p2.first);
+ }
+
+ private:
+ BinaryOp f_;
+};
+
+template <typename Pair, typename BinaryOp>
+BinaryOperateOnFirst<Pair, BinaryOp> BinaryOperate1st(const BinaryOp& f) {
+ return BinaryOperateOnFirst<Pair, BinaryOp>(f);
+}
+
+template <typename Pair, typename BinaryOp>
+class BinaryOperateOnSecond
+ : public std::binary_function<Pair, Pair, typename BinaryOp::result_type> {
+ public:
+ BinaryOperateOnSecond() {}
+
+ explicit BinaryOperateOnSecond(const BinaryOp& f) : f_(f) {}
+
+ typename BinaryOp::result_type operator()(const Pair& p1,
+ const Pair& p2) const {
+ return f_(p1.second, p2.second);
+ }
+
+ private:
+ BinaryOp f_;
+};
+
+template <typename Pair, typename BinaryOp>
+BinaryOperateOnSecond<Pair, BinaryOp> BinaryOperate2nd(const BinaryOp& f) {
+ return BinaryOperateOnSecond<Pair, BinaryOp>(f);
+}
+
+// Translates a set into a vector.
+template <typename T>
+std::vector<T> SetToVector(const std::set<T>& values) {
+ std::vector<T> result;
+ result.reserve(values.size());
+ result.insert(result.begin(), values.begin(), values.end());
+ return result;
+}
+
+#endif // BASE_STL_UTIL_INL_H_
diff --git a/ipc/chromium/src/base/string16.cc b/ipc/chromium/src/base/string16.cc
new file mode 100644
index 0000000000..8a0c406eff
--- /dev/null
+++ b/ipc/chromium/src/base/string16.cc
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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 "base/string16.h"
+
+#if defined(XP_WIN)
+
+# 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.
+
+#else
+
+# include "base/string_util.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>;
+
+#endif
diff --git a/ipc/chromium/src/base/string16.h b/ipc/chromium/src/base/string16.h
new file mode 100644
index 0000000000..c7cc1868e2
--- /dev/null
+++ b/ipc/chromium/src/base/string16.h
@@ -0,0 +1,161 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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_STRING16_H_
+#define BASE_STRING16_H_
+
+// 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/basictypes.h"
+
+#if defined(XP_WIN)
+
+typedef wchar_t char16;
+typedef std::wstring string16;
+
+#else
+
+typedef uint16_t 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").
+int c16memcmp(const char16* s1, const char16* s2, size_t n);
+size_t c16len(const char16* s);
+const char16* c16memchr(const char16* s, char16 c, size_t n);
+char16* c16memmove(char16* s1, const char16* s2, size_t n);
+char16* c16memcpy(char16* s1, const char16* s2, size_t n);
+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;
+
+extern std::ostream& operator<<(std::ostream& out, const string16& str);
+
+#endif
+
+#endif // BASE_STRING16_H_
diff --git a/ipc/chromium/src/base/string_piece.cc b/ipc/chromium/src/base/string_piece.cc
new file mode 100644
index 0000000000..7b83df0758
--- /dev/null
+++ b/ipc/chromium/src/base/string_piece.cc
@@ -0,0 +1,190 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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.
+// Copied from strings/stringpiece.cc with modifications
+
+#include <algorithm>
+#include <ostream>
+
+#include "base/string_piece.h"
+
+typedef StringPiece::size_type size_type;
+
+std::ostream& operator<<(std::ostream& o, const StringPiece& piece) {
+ o.write(piece.data(), static_cast<std::streamsize>(piece.size()));
+ return o;
+}
+
+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_ ? 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 ? 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);
diff --git a/ipc/chromium/src/base/string_piece.h b/ipc/chromium/src/base/string_piece.h
new file mode 100644
index 0000000000..8ebdb281d1
--- /dev/null
+++ b/ipc/chromium/src/base/string_piece.h
@@ -0,0 +1,189 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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.
+// 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.
+//
+
+#ifndef BASE_STRING_PIECE_H_
+#define BASE_STRING_PIECE_H_
+
+#include <algorithm>
+#include <iosfwd>
+#include <string>
+
+#include "base/basictypes.h"
+
+class StringPiece {
+ public:
+ typedef size_t size_type;
+
+ private:
+ const char* ptr_;
+ size_type length_;
+
+ 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) {}
+ MOZ_IMPLICIT StringPiece(const char* str)
+ : ptr_(str), length_((str == NULL) ? 0 : strlen(str)) {}
+ MOZ_IMPLICIT 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* aData, size_type aLen) {
+ ptr_ = aData;
+ length_ = aLen;
+ }
+ void set(const char* str) {
+ ptr_ = str;
+ length_ = str ? strlen(str) : 0;
+ }
+ void set(const void* aData, size_type aLen) {
+ ptr_ = reinterpret_cast<const char*>(aData);
+ length_ = aLen;
+ }
+
+ 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_, std::min(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));
+ }
+
+ // standard STL container boilerplate
+ typedef char value_type;
+ typedef const char* pointer;
+ typedef const char& reference;
+ typedef const char& const_reference;
+ typedef ptrdiff_t difference_type;
+ static const size_type npos;
+ 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;
+ 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);
+ }
+};
+
+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(),
+ std::min(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);
+}
+
+// allow StringPiece to be logged (needed for unit testing).
+extern std::ostream& operator<<(std::ostream& o, const ::StringPiece& piece);
+
+#endif // BASE_STRING_PIECE_H_
diff --git a/ipc/chromium/src/base/string_util.cc b/ipc/chromium/src/base/string_util.cc
new file mode 100644
index 0000000000..39b8463cb1
--- /dev/null
+++ b/ipc/chromium/src/base/string_util.cc
@@ -0,0 +1,719 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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 "base/string_util.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <math.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#include <algorithm>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+
+namespace {
+
+// Hack to convert any char-like type to its unsigned counterpart.
+// For example, it will convert char, signed char and unsigned char to unsigned
+// char.
+template <typename T>
+struct ToUnsigned {
+ typedef T Unsigned;
+};
+
+template <>
+struct ToUnsigned<char> {
+ typedef unsigned char Unsigned;
+};
+template <>
+struct ToUnsigned<signed char> {
+ typedef unsigned char Unsigned;
+};
+template <>
+struct ToUnsigned<wchar_t> {
+#if defined(XP_WIN)
+ typedef unsigned short Unsigned;
+#else
+ typedef uint32_t Unsigned;
+#endif
+};
+template <>
+struct ToUnsigned<short> {
+ typedef unsigned short Unsigned;
+};
+
+// Generalized string-to-number conversion.
+//
+// StringToNumberTraits should provide:
+// - a typedef for string_type, the STL string type used as input.
+// - a typedef for value_type, the target numeric type.
+// - a static function, convert_func, which dispatches to an appropriate
+// strtol-like function and returns type value_type.
+// - a static function, valid_func, which validates |input| and returns a bool
+// indicating whether it is in proper form. This is used to check for
+// conditions that convert_func tolerates but should result in
+// StringToNumber returning false. For strtol-like funtions, valid_func
+// should check for leading whitespace.
+template <typename StringToNumberTraits>
+bool StringToNumber(const typename StringToNumberTraits::string_type& input,
+ typename StringToNumberTraits::value_type* output) {
+ typedef StringToNumberTraits traits;
+
+ errno = 0; // Thread-safe? It is on at least Mac, Linux, and Windows.
+ typename traits::string_type::value_type* endptr = NULL;
+ typename traits::value_type value =
+ traits::convert_func(input.c_str(), &endptr);
+ *output = value;
+
+ // 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.
+ // - valid_func determines that the input is not in preferred form.
+ return errno == 0 && !input.empty() &&
+ input.c_str() + input.length() == endptr && traits::valid_func(input);
+}
+
+class StringToLongTraits {
+ public:
+ typedef std::string string_type;
+ typedef long value_type;
+ static const int kBase = 10;
+ static inline value_type convert_func(const string_type::value_type* str,
+ string_type::value_type** endptr) {
+ return strtol(str, endptr, kBase);
+ }
+ static inline bool valid_func(const string_type& str) {
+ return !str.empty() && !isspace(str[0]);
+ }
+};
+
+class String16ToLongTraits {
+ public:
+ typedef string16 string_type;
+ typedef long value_type;
+ static const int kBase = 10;
+ static inline value_type convert_func(const string_type::value_type* str,
+ string_type::value_type** endptr) {
+#if defined(XP_WIN)
+ return wcstol(str, endptr, kBase);
+#else
+ std::string ascii_string = UTF16ToASCII(string16(str));
+ char* ascii_end = NULL;
+ value_type ret = strtol(ascii_string.c_str(), &ascii_end, kBase);
+ if (ascii_string.c_str() + ascii_string.length() == ascii_end) {
+ *endptr =
+ const_cast<string_type::value_type*>(str) + ascii_string.length();
+ }
+ return ret;
+#endif
+ }
+ static inline bool valid_func(const string_type& str) {
+ return !str.empty() && !iswspace(str[0]);
+ }
+};
+
+class StringToInt64Traits {
+ public:
+ typedef std::string string_type;
+ typedef int64_t value_type;
+ static const int kBase = 10;
+ static inline value_type convert_func(const string_type::value_type* str,
+ string_type::value_type** endptr) {
+#ifdef XP_WIN
+ return _strtoi64(str, endptr, kBase);
+#else // assume XP_UNIX
+ return strtoll(str, endptr, kBase);
+#endif
+ }
+ static inline bool valid_func(const string_type& str) {
+ return !str.empty() && !isspace(str[0]);
+ }
+};
+
+class String16ToInt64Traits {
+ public:
+ typedef string16 string_type;
+ typedef int64_t value_type;
+ static const int kBase = 10;
+ static inline value_type convert_func(const string_type::value_type* str,
+ string_type::value_type** endptr) {
+#ifdef XP_WIN
+ return _wcstoi64(str, endptr, kBase);
+#else // assume XP_UNIX
+ std::string ascii_string = UTF16ToASCII(string16(str));
+ char* ascii_end = NULL;
+ value_type ret = strtoll(ascii_string.c_str(), &ascii_end, kBase);
+ if (ascii_string.c_str() + ascii_string.length() == ascii_end) {
+ *endptr =
+ const_cast<string_type::value_type*>(str) + ascii_string.length();
+ }
+ return ret;
+#endif
+ }
+ static inline bool valid_func(const string_type& str) {
+ return !str.empty() && !iswspace(str[0]);
+ }
+};
+
+} // namespace
+
+namespace base {
+
+bool IsWprintfFormatPortable(const wchar_t* format) {
+ for (const wchar_t* position = format; *position != '\0'; ++position) {
+ if (*position == '%') {
+ bool in_specification = true;
+ bool modifier_l = false;
+ while (in_specification) {
+ // Eat up characters until reaching a known specifier.
+ if (*++position == '\0') {
+ // The format string ended in the middle of a specification. Call
+ // it portable because no unportable specifications were found. The
+ // string is equally broken on all platforms.
+ return true;
+ }
+
+ if (*position == 'l') {
+ // 'l' is the only thing that can save the 's' and 'c' specifiers.
+ modifier_l = true;
+ } else if (((*position == 's' || *position == 'c') && !modifier_l) ||
+ *position == 'S' || *position == 'C' || *position == 'F' ||
+ *position == 'D' || *position == 'O' || *position == 'U') {
+ // Not portable.
+ return false;
+ }
+
+ if (wcschr(L"diouxXeEfgGaAcspn%", *position)) {
+ // Portable, keep scanning the rest of the format string.
+ in_specification = false;
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+} // namespace base
+
+static const wchar_t kWhitespaceWide[] = {
+ 0x0009, // <control-0009> to <control-000D>
+ 0x000A, 0x000B, 0x000C, 0x000D,
+ 0x0020, // Space
+ 0x0085, // <control-0085>
+ 0x00A0, // No-Break Space
+ 0x1680, // Ogham Space Mark
+ 0x180E, // Mongolian Vowel Separator
+ 0x2000, // En Quad to Hair Space
+ 0x2001, 0x2002, 0x2003, 0x2004, 0x2005,
+ 0x2006, 0x2007, 0x2008, 0x2009, 0x200A,
+ 0x200C, // Zero Width Non-Joiner
+ 0x2028, // Line Separator
+ 0x2029, // Paragraph Separator
+ 0x202F, // Narrow No-Break Space
+ 0x205F, // Medium Mathematical Space
+ 0x3000, // Ideographic Space
+ 0};
+static const char kWhitespaceASCII[] = {
+ 0x09, // <control-0009> to <control-000D>
+ 0x0A, 0x0B, 0x0C, 0x0D,
+ 0x20, // Space
+ 0};
+
+template <typename STR>
+TrimPositions TrimStringT(const STR& input,
+ const typename STR::value_type trim_chars[],
+ TrimPositions positions, STR* output) {
+ // Find the edges of leading/trailing whitespace as desired.
+ const typename STR::size_type last_char = input.length() - 1;
+ const typename STR::size_type first_good_char =
+ (positions & TRIM_LEADING) ? input.find_first_not_of(trim_chars) : 0;
+ const typename STR::size_type last_good_char =
+ (positions & TRIM_TRAILING) ? input.find_last_not_of(trim_chars)
+ : last_char;
+
+ // When the string was all whitespace, report that we stripped off whitespace
+ // from whichever position the caller was interested in. For empty input, we
+ // stripped no whitespace, but we still need to clear |output|.
+ if (input.empty() || (first_good_char == STR::npos) ||
+ (last_good_char == STR::npos)) {
+ bool input_was_empty = input.empty(); // in case output == &input
+ output->clear();
+ return input_was_empty ? TRIM_NONE : positions;
+ }
+
+ // Trim the whitespace.
+ *output = input.substr(first_good_char, last_good_char - first_good_char + 1);
+
+ // Return where we trimmed from.
+ return static_cast<TrimPositions>(
+ ((first_good_char == 0) ? TRIM_NONE : TRIM_LEADING) |
+ ((last_good_char == last_char) ? TRIM_NONE : TRIM_TRAILING));
+}
+
+TrimPositions TrimWhitespace(const std::wstring& input, TrimPositions positions,
+ std::wstring* output) {
+ return TrimStringT(input, kWhitespaceWide, positions, output);
+}
+
+TrimPositions TrimWhitespaceASCII(const std::string& input,
+ TrimPositions positions,
+ std::string* output) {
+ return TrimStringT(input, kWhitespaceASCII, positions, output);
+}
+
+// This function is only for backward-compatibility.
+// To be removed when all callers are updated.
+TrimPositions TrimWhitespace(const std::string& input, TrimPositions positions,
+ std::string* output) {
+ return TrimWhitespaceASCII(input, positions, output);
+}
+
+std::string WideToASCII(const std::wstring& wide) {
+ DCHECK(IsStringASCII(wide));
+ return std::string(wide.begin(), wide.end());
+}
+
+std::wstring ASCIIToWide(const std::string& ascii) {
+ DCHECK(IsStringASCII(ascii));
+ return std::wstring(ascii.begin(), ascii.end());
+}
+
+std::string UTF16ToASCII(const string16& utf16) {
+ DCHECK(IsStringASCII(utf16));
+ return std::string(utf16.begin(), utf16.end());
+}
+
+string16 ASCIIToUTF16(const std::string& ascii) {
+ DCHECK(IsStringASCII(ascii));
+ return string16(ascii.begin(), ascii.end());
+}
+
+template <class STR>
+static bool DoIsStringASCII(const STR& str) {
+ for (size_t i = 0; i < str.length(); i++) {
+ typename ToUnsigned<typename STR::value_type>::Unsigned c = str[i];
+ if (c > 0x7F) return false;
+ }
+ return true;
+}
+
+bool IsStringASCII(const std::wstring& str) { return DoIsStringASCII(str); }
+
+#if !defined(XP_WIN)
+bool IsStringASCII(const string16& str) { return DoIsStringASCII(str); }
+#endif
+
+bool IsStringASCII(const std::string& str) { return DoIsStringASCII(str); }
+
+// Overloaded wrappers around vsnprintf and vswprintf. The buf_size parameter
+// is the size of the buffer. These return the number of characters in the
+// formatted string excluding the NUL terminator. If the buffer is not
+// large enough to accommodate the formatted string without truncation, they
+// return the number of characters that would be in the fully-formatted string
+// (vsnprintf, and vswprintf on Windows), or -1 (vswprintf on POSIX platforms).
+inline int vsnprintfT(char* buffer, size_t buf_size, const char* format,
+ va_list argptr) {
+ return base::vsnprintf(buffer, buf_size, format, argptr);
+}
+
+inline int vsnprintfT(wchar_t* buffer, size_t buf_size, const wchar_t* format,
+ va_list argptr) {
+ return base::vswprintf(buffer, buf_size, format, argptr);
+}
+
+// Templatized backend for StringPrintF/StringAppendF. This does not finalize
+// the va_list, the caller is expected to do that.
+template <class StringType>
+static void StringAppendVT(StringType* dst,
+ const typename StringType::value_type* format,
+ va_list ap) {
+ // First try with a small fixed size buffer.
+ // This buffer size should be kept in sync with StringUtilTest.GrowBoundary
+ // and StringUtilTest.StringPrintfBounds.
+ typename StringType::value_type stack_buf[1024];
+
+ va_list backup_ap;
+ base_va_copy(backup_ap, ap);
+
+#if !defined(XP_WIN)
+ errno = 0;
+#endif
+ int result = vsnprintfT(stack_buf, arraysize(stack_buf), format, backup_ap);
+ va_end(backup_ap);
+
+ if (result >= 0 && result < static_cast<int>(arraysize(stack_buf))) {
+ // It fit.
+ dst->append(stack_buf, result);
+ return;
+ }
+
+ // Repeatedly increase buffer size until it fits.
+ int mem_length = arraysize(stack_buf);
+ while (true) {
+ if (result < 0) {
+#if !defined(XP_WIN)
+ // On Windows, vsnprintfT always returns the number of characters in a
+ // fully-formatted string, so if we reach this point, something else is
+ // wrong and no amount of buffer-doubling is going to fix it.
+ if (errno != 0 && errno != EOVERFLOW)
+#endif
+ {
+ // If an error other than overflow occurred, it's never going to work.
+ DLOG(WARNING) << "Unable to printf the requested string due to error.";
+ return;
+ }
+ // Try doubling the buffer size.
+ mem_length *= 2;
+ } else {
+ // We need exactly "result + 1" characters.
+ mem_length = result + 1;
+ }
+
+ if (mem_length > 32 * 1024 * 1024) {
+ // That should be plenty, don't try anything larger. This protects
+ // against huge allocations when using vsnprintfT implementations that
+ // return -1 for reasons other than overflow without setting errno.
+ DLOG(WARNING) << "Unable to printf the requested string due to size.";
+ return;
+ }
+
+ std::vector<typename StringType::value_type> mem_buf(mem_length);
+
+ // Restore the va_list before we use it again.
+ base_va_copy(backup_ap, ap);
+
+ result = vsnprintfT(&mem_buf[0], mem_length, format, ap);
+ va_end(backup_ap);
+
+ if ((result >= 0) && (result < mem_length)) {
+ // It fit.
+ dst->append(&mem_buf[0], result);
+ return;
+ }
+ }
+}
+
+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();
+ }
+};
+
+} // namespace
+
+std::string IntToString(int value) {
+ return IntToStringT<std::string, int, unsigned int, true>::IntToString(value);
+}
+std::wstring IntToWString(int value) {
+ return IntToStringT<std::wstring, int, unsigned int, true>::IntToString(
+ value);
+}
+std::string UintToString(unsigned int value) {
+ return IntToStringT<std::string, unsigned int, unsigned int,
+ false>::IntToString(value);
+}
+std::wstring UintToWString(unsigned int value) {
+ return IntToStringT<std::wstring, unsigned int, unsigned int,
+ false>::IntToString(value);
+}
+std::string Int64ToString(int64_t value) {
+ return IntToStringT<std::string, int64_t, uint64_t, true>::IntToString(value);
+}
+std::wstring Int64ToWString(int64_t value) {
+ return IntToStringT<std::wstring, int64_t, uint64_t, true>::IntToString(
+ value);
+}
+std::string Uint64ToString(uint64_t value) {
+ return IntToStringT<std::string, uint64_t, uint64_t, false>::IntToString(
+ value);
+}
+std::wstring Uint64ToWString(uint64_t value) {
+ return IntToStringT<std::wstring, uint64_t, uint64_t, false>::IntToString(
+ value);
+}
+
+// Lower-level routine that takes a va_list and appends to a specified
+// string. All other routines are just convenience wrappers around it.
+static void StringAppendV(std::string* dst, const char* format, va_list ap) {
+ StringAppendVT(dst, format, ap);
+}
+
+static void StringAppendV(std::wstring* dst, const wchar_t* format,
+ va_list ap) {
+ StringAppendVT(dst, format, ap);
+}
+
+std::string StringPrintf(const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ std::string result;
+ StringAppendV(&result, format, ap);
+ va_end(ap);
+ return result;
+}
+
+std::wstring StringPrintf(const wchar_t* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ std::wstring result;
+ StringAppendV(&result, format, ap);
+ va_end(ap);
+ return result;
+}
+
+const std::string& SStringPrintf(std::string* dst, const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ dst->clear();
+ StringAppendV(dst, format, ap);
+ va_end(ap);
+ return *dst;
+}
+
+const std::wstring& SStringPrintf(std::wstring* dst, const wchar_t* format,
+ ...) {
+ va_list ap;
+ va_start(ap, format);
+ dst->clear();
+ StringAppendV(dst, format, ap);
+ va_end(ap);
+ return *dst;
+}
+
+void StringAppendF(std::string* dst, const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ StringAppendV(dst, format, ap);
+ va_end(ap);
+}
+
+void StringAppendF(std::wstring* dst, const wchar_t* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ StringAppendV(dst, format, ap);
+ va_end(ap);
+}
+
+template <typename STR>
+static void SplitStringT(const STR& str, const typename STR::value_type s,
+ bool trim_whitespace, std::vector<STR>* r) {
+ size_t last = 0;
+ size_t i;
+ size_t c = str.size();
+ for (i = 0; i <= c; ++i) {
+ if (i == c || str[i] == s) {
+ size_t len = i - last;
+ STR tmp = str.substr(last, len);
+ if (trim_whitespace) {
+ STR t_tmp;
+ TrimWhitespace(tmp, TRIM_ALL, &t_tmp);
+ r->push_back(t_tmp);
+ } else {
+ r->push_back(tmp);
+ }
+ last = i + 1;
+ }
+ }
+}
+
+void SplitString(const std::wstring& str, wchar_t s,
+ std::vector<std::wstring>* r) {
+ SplitStringT(str, s, true, r);
+}
+
+void SplitString(const std::string& str, char s, std::vector<std::string>* r) {
+ SplitStringT(str, s, true, r);
+}
+
+// For the various *ToInt conversions, there are no *ToIntTraits classes to use
+// because there's no such thing as strtoi. Use *ToLongTraits through a cast
+// instead, requiring that long and int are compatible and equal-width. They
+// are on our target platforms.
+
+// XXX Sigh.
+
+#if !defined(HAVE_64BIT_BUILD)
+bool StringToInt(const std::string& input, int* output) {
+ COMPILE_ASSERT(sizeof(int) == sizeof(long), cannot_strtol_to_int);
+ return StringToNumber<StringToLongTraits>(input,
+ reinterpret_cast<long*>(output));
+}
+
+bool StringToInt(const string16& input, int* output) {
+ COMPILE_ASSERT(sizeof(int) == sizeof(long), cannot_wcstol_to_int);
+ return StringToNumber<String16ToLongTraits>(input,
+ reinterpret_cast<long*>(output));
+}
+
+#else
+bool StringToInt(const std::string& input, int* output) {
+ long tmp;
+ bool ok = StringToNumber<StringToLongTraits>(input, &tmp);
+ if (!ok || tmp > kint32max) {
+ return false;
+ }
+ *output = static_cast<int>(tmp);
+ return true;
+}
+
+bool StringToInt(const string16& input, int* output) {
+ long tmp;
+ bool ok = StringToNumber<String16ToLongTraits>(input, &tmp);
+ if (!ok || tmp > kint32max) {
+ return false;
+ }
+ *output = static_cast<int>(tmp);
+ return true;
+}
+#endif // !defined(HAVE_64BIT_BUILD)
+
+bool StringToInt64(const std::string& input, int64_t* output) {
+ return StringToNumber<StringToInt64Traits>(input, output);
+}
+
+bool StringToInt64(const string16& input, int64_t* output) {
+ return StringToNumber<String16ToInt64Traits>(input, output);
+}
+
+int StringToInt(const std::string& value) {
+ int result;
+ StringToInt(value, &result);
+ return result;
+}
+
+int StringToInt(const string16& value) {
+ int result;
+ StringToInt(value, &result);
+ return result;
+}
+
+int64_t StringToInt64(const std::string& value) {
+ int64_t result;
+ StringToInt64(value, &result);
+ return result;
+}
+
+int64_t StringToInt64(const string16& value) {
+ int64_t result;
+ StringToInt64(value, &result);
+ return result;
+}
+
+// The following code is compatible with the OpenBSD lcpy interface. See:
+// http://www.gratisoft.us/todd/papers/strlcpy.html
+// ftp://ftp.openbsd.org/pub/OpenBSD/src/lib/libc/string/{wcs,str}lcpy.c
+
+namespace {
+
+template <typename CHAR>
+size_t lcpyT(CHAR* dst, const CHAR* src, size_t dst_size) {
+ for (size_t i = 0; i < dst_size; ++i) {
+ if ((dst[i] = src[i]) == 0) // We hit and copied the terminating NULL.
+ return i;
+ }
+
+ // We were left off at dst_size. We over copied 1 byte. Null terminate.
+ if (dst_size != 0) dst[dst_size - 1] = 0;
+
+ // Count the rest of the |src|, and return it's length in characters.
+ while (src[dst_size]) ++dst_size;
+ return dst_size;
+}
+
+} // namespace
+
+size_t base::strlcpy(char* dst, const char* src, size_t dst_size) {
+ return lcpyT<char>(dst, src, dst_size);
+}
+size_t base::wcslcpy(wchar_t* dst, const wchar_t* src, size_t dst_size) {
+ return lcpyT<wchar_t>(dst, src, dst_size);
+}
diff --git a/ipc/chromium/src/base/string_util.h b/ipc/chromium/src/base/string_util.h
new file mode 100644
index 0000000000..b6adcd96d7
--- /dev/null
+++ b/ipc/chromium/src/base/string_util.h
@@ -0,0 +1,229 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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 defines utility functions for working with strings.
+
+#ifndef BASE_STRING_UTIL_H_
+#define BASE_STRING_UTIL_H_
+
+#include <stdarg.h> // va_list
+#include <ctype.h>
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/string16.h"
+#include "base/string_piece.h" // For implicit conversions.
+
+// Safe standard library wrappers for all platforms.
+
+namespace base {
+
+// C standard-library functions like "strncasecmp" and "snprintf" that aren't
+// cross-platform are provided as "base::strncasecmp", and their prototypes
+// are listed below. These functions are then implemented as inline calls
+// to the platform-specific equivalents in the platform-specific headers.
+
+// Compare the two strings s1 and s2 without regard to case using
+// the current locale; returns 0 if they are equal, 1 if s1 > s2, and -1 if
+// s2 > s1 according to a lexicographic comparison.
+int strcasecmp(const char* s1, const char* s2);
+
+// Compare up to count characters of s1 and s2 without regard to case using
+// the current locale; returns 0 if they are equal, 1 if s1 > s2, and -1 if
+// s2 > s1 according to a lexicographic comparison.
+int strncasecmp(const char* s1, const char* s2, size_t count);
+
+// Wrapper for vsnprintf that always null-terminates and always returns the
+// number of characters that would be in an untruncated formatted
+// string, even when truncation occurs.
+int vsnprintf(char* buffer, size_t size, const char* format, va_list arguments);
+
+// vswprintf always null-terminates, but when truncation occurs, it will either
+// return -1 or the number of characters that would be in an untruncated
+// formatted string. The actual return value depends on the underlying
+// C library's vswprintf implementation.
+int vswprintf(wchar_t* buffer, size_t size, const wchar_t* format,
+ va_list arguments);
+
+// Some of these implementations need to be inlined.
+
+inline int snprintf(char* buffer, size_t size, const char* format, ...) {
+ va_list arguments;
+ va_start(arguments, format);
+ int result = vsnprintf(buffer, size, format, arguments);
+ va_end(arguments);
+ return result;
+}
+
+inline int swprintf(wchar_t* buffer, size_t size, const wchar_t* format, ...) {
+ va_list arguments;
+ va_start(arguments, format);
+ int result = vswprintf(buffer, size, format, arguments);
+ va_end(arguments);
+ return result;
+}
+
+// BSD-style safe and consistent string copy functions.
+// Copies |src| to |dst|, where |dst_size| is the total allocated size of |dst|.
+// Copies at most |dst_size|-1 characters, and always NULL terminates |dst|, as
+// long as |dst_size| is not 0. Returns the length of |src| in characters.
+// If the return value is >= dst_size, then the output was truncated.
+// NOTE: All sizes are in number of characters, NOT in bytes.
+size_t strlcpy(char* dst, const char* src, size_t dst_size);
+size_t wcslcpy(wchar_t* dst, const wchar_t* src, size_t dst_size);
+
+// Scan a wprintf format string to determine whether it's portable across a
+// variety of systems. This function only checks that the conversion
+// specifiers used by the format string are supported and have the same meaning
+// on a variety of systems. It doesn't check for other errors that might occur
+// within a format string.
+//
+// Nonportable conversion specifiers for wprintf are:
+// - 's' and 'c' without an 'l' length modifier. %s and %c operate on char
+// data on all systems except Windows, which treat them as wchar_t data.
+// Use %ls and %lc for wchar_t data instead.
+// - 'S' and 'C', which operate on wchar_t data on all systems except Windows,
+// which treat them as char data. Use %ls and %lc for wchar_t data
+// instead.
+// - 'F', which is not identified by Windows wprintf documentation.
+// - 'D', 'O', and 'U', which are deprecated and not available on all systems.
+// Use %ld, %lo, and %lu instead.
+//
+// Note that there is no portable conversion specifier for char data when
+// working with wprintf.
+//
+// This function is intended to be called from base::vswprintf.
+bool IsWprintfFormatPortable(const wchar_t* format);
+
+} // namespace base
+
+#if defined(XP_WIN)
+# include "base/string_util_win.h"
+#else
+# include "base/string_util_posix.h"
+#endif
+
+// Trims any whitespace from either end of the input string. Returns where
+// whitespace was found.
+// The non-wide version has two functions:
+// * TrimWhitespaceASCII()
+// This function is for ASCII strings and only looks for ASCII whitespace;
+// * TrimWhitespaceUTF8()
+// This function is for UTF-8 strings and looks for Unicode whitespace.
+// Please choose the best one according to your usage.
+// NOTE: Safe to use the same variable for both input and output.
+enum TrimPositions {
+ TRIM_NONE = 0,
+ TRIM_LEADING = 1 << 0,
+ TRIM_TRAILING = 1 << 1,
+ TRIM_ALL = TRIM_LEADING | TRIM_TRAILING
+};
+TrimPositions TrimWhitespace(const std::wstring& input, TrimPositions positions,
+ std::wstring* output);
+TrimPositions TrimWhitespaceASCII(const std::string& input,
+ TrimPositions positions, std::string* output);
+
+// Deprecated. This function is only for backward compatibility and calls
+// TrimWhitespaceASCII().
+TrimPositions TrimWhitespace(const std::string& input, TrimPositions positions,
+ std::string* output);
+
+// Searches for CR or LF characters. Removes all contiguous whitespace
+// strings that contain them. This is useful when trying to deal with text
+// copied from terminals.
+// Returns |text, with the following three transformations:
+// (1) Leading and trailing whitespace is trimmed.
+// (2) If |trim_sequences_with_line_breaks| is true, any other whitespace
+// sequences containing a CR or LF are trimmed.
+// (3) All other whitespace sequences are converted to single spaces.
+std::wstring CollapseWhitespace(const std::wstring& text,
+ bool trim_sequences_with_line_breaks);
+
+// These convert between ASCII (7-bit) and Wide/UTF16 strings.
+std::string WideToASCII(const std::wstring& wide);
+std::wstring ASCIIToWide(const std::string& ascii);
+std::string UTF16ToASCII(const string16& utf16);
+string16 ASCIIToUTF16(const std::string& ascii);
+
+// These convert between UTF-8, -16, and -32 strings. They are potentially slow,
+// so avoid unnecessary conversions. The low-level versions return a boolean
+// indicating whether the conversion was 100% valid. In this case, it will still
+// do the best it can and put the result in the output buffer. The versions that
+// return strings ignore this error and just return the best conversion
+// possible.
+bool WideToUTF8(const wchar_t* src, size_t src_len, std::string* output);
+std::string WideToUTF8(const std::wstring& wide);
+bool UTF8ToWide(const char* src, size_t src_len, std::wstring* output);
+std::wstring UTF8ToWide(const ::StringPiece& utf8);
+
+bool IsStringASCII(const std::wstring& str);
+bool IsStringASCII(const std::string& str);
+bool IsStringASCII(const string16& str);
+
+// Specialized string-conversion functions.
+std::string IntToString(int value);
+std::wstring IntToWString(int value);
+std::string UintToString(unsigned int value);
+std::wstring UintToWString(unsigned int value);
+std::string Int64ToString(int64_t value);
+std::wstring Int64ToWString(int64_t value);
+std::string Uint64ToString(uint64_t value);
+std::wstring Uint64ToWString(uint64_t value);
+// The DoubleToString methods convert the double to a string format that
+// ignores the locale. If you want to use locale specific formatting, use ICU.
+std::string DoubleToString(double value);
+std::wstring DoubleToWString(double value);
+
+// 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.
+// - 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.
+bool StringToInt(const std::string& input, int* output);
+bool StringToInt(const string16& input, int* output);
+bool StringToInt64(const std::string& input, int64_t* output);
+bool StringToInt64(const string16& input, int64_t* output);
+
+// Convenience forms of the above, when the caller is uninterested in the
+// boolean return value. These return only the |*output| value from the
+// above conversions: a best-effort conversion when possible, otherwise, 0.
+int StringToInt(const std::string& value);
+int StringToInt(const string16& value);
+int64_t StringToInt64(const std::string& value);
+int64_t StringToInt64(const string16& value);
+
+// Return a C++ string given printf-like input.
+std::string StringPrintf(const char* format, ...);
+std::wstring StringPrintf(const wchar_t* format, ...);
+
+// Store result into a supplied string and return it
+const std::string& SStringPrintf(std::string* dst, const char* format, ...);
+const std::wstring& SStringPrintf(std::wstring* dst, const wchar_t* format,
+ ...);
+
+// Append result to a supplied string
+void StringAppendF(std::string* dst, const char* format, ...);
+void StringAppendF(std::wstring* dst, const wchar_t* format, ...);
+
+//-----------------------------------------------------------------------------
+
+// Splits |str| into a vector of strings delimited by |s|. Append the results
+// into |r| as they appear. If several instances of |s| are contiguous, or if
+// |str| begins with or ends with |s|, then an empty string is inserted.
+//
+// Every substring is trimmed of any leading or trailing white space.
+void SplitString(const std::wstring& str, wchar_t s,
+ std::vector<std::wstring>* r);
+void SplitString(const std::string& str, char s, std::vector<std::string>* r);
+
+#endif // BASE_STRING_UTIL_H_
diff --git a/ipc/chromium/src/base/string_util_posix.h b/ipc/chromium/src/base/string_util_posix.h
new file mode 100644
index 0000000000..02818a6441
--- /dev/null
+++ b/ipc/chromium/src/base/string_util_posix.h
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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_STRING_UTIL_POSIX_H_
+#define BASE_STRING_UTIL_POSIX_H_
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <wchar.h>
+
+#include "base/logging.h"
+
+namespace base {
+
+// Chromium code style is to not use malloc'd strings; this is only for use
+// for interaction with APIs that require it.
+inline char* strdup(const char* str) { return ::strdup(str); }
+
+inline int strcasecmp(const char* string1, const char* string2) {
+ return ::strcasecmp(string1, string2);
+}
+
+inline int strncasecmp(const char* string1, const char* string2, size_t count) {
+ return ::strncasecmp(string1, string2, count);
+}
+
+inline int vsnprintf(char* buffer, size_t size, const char* format,
+ va_list arguments) {
+ return ::vsnprintf(buffer, size, format, arguments);
+}
+
+inline int vswprintf(wchar_t* buffer, size_t size, const wchar_t* format,
+ va_list arguments) {
+ DCHECK(IsWprintfFormatPortable(format));
+ return ::vswprintf(buffer, size, format, arguments);
+}
+
+} // namespace base
+
+#endif // BASE_STRING_UTIL_POSIX_H_
diff --git a/ipc/chromium/src/base/string_util_win.h b/ipc/chromium/src/base/string_util_win.h
new file mode 100644
index 0000000000..7f8586889b
--- /dev/null
+++ b/ipc/chromium/src/base/string_util_win.h
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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_STRING_UTIL_WIN_H_
+#define BASE_STRING_UTIL_WIN_H_
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <wchar.h>
+
+#include "base/logging.h"
+
+namespace base {
+
+// Chromium code style is to not use malloc'd strings; this is only for use
+// for interaction with APIs that require it.
+inline char* strdup(const char* str) { return _strdup(str); }
+
+inline int vsnprintf(char* buffer, size_t size, const char* format,
+ va_list arguments) {
+ int length = vsnprintf_s(buffer, size, size - 1, format, arguments);
+ if (length < 0) return _vscprintf(format, arguments);
+ return length;
+}
+
+inline int vswprintf(wchar_t* buffer, size_t size, const wchar_t* format,
+ va_list arguments) {
+ DCHECK(IsWprintfFormatPortable(format));
+
+ int length = _vsnwprintf_s(buffer, size, size - 1, format, arguments);
+ if (length < 0) return _vscwprintf(format, arguments);
+ return length;
+}
+
+} // namespace base
+
+#endif // BASE_STRING_UTIL_WIN_H_
diff --git a/ipc/chromium/src/base/sys_string_conversions.h b/ipc/chromium/src/base/sys_string_conversions.h
new file mode 100644
index 0000000000..e3a51964a7
--- /dev/null
+++ b/ipc/chromium/src/base/sys_string_conversions.h
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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_SYS_STRING_CONVERSIONS_H_
+#define BASE_SYS_STRING_CONVERSIONS_H_
+
+// Provides system-dependent string type conversions for cases where it's
+// necessary to not use ICU. Generally, you should not need this in Chrome,
+// but it is used in some shared code. Dependencies should be minimal.
+
+#include <string>
+#include "base/basictypes.h"
+#include "base/string16.h"
+
+class StringPiece;
+
+namespace base {
+
+// Converts between wide and UTF-8 representations of a string. On error, the
+// result is system-dependent.
+std::string SysWideToUTF8(const std::wstring& wide);
+std::wstring SysUTF8ToWide(const StringPiece& utf8);
+
+// Converts between wide and the system multi-byte representations of a string.
+// DANGER: This will lose information and can change (on Windows, this can
+// change between reboots).
+std::string SysWideToNativeMB(const std::wstring& wide);
+std::wstring SysNativeMBToWide(const StringPiece& native_mb);
+
+} // namespace base
+
+#endif // BASE_SYS_STRING_CONVERSIONS_H_
diff --git a/ipc/chromium/src/base/sys_string_conversions_mac.mm b/ipc/chromium/src/base/sys_string_conversions_mac.mm
new file mode 100644
index 0000000000..c33ffef6bc
--- /dev/null
+++ b/ipc/chromium/src/base/sys_string_conversions_mac.mm
@@ -0,0 +1,126 @@
+// 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 "base/sys_string_conversions.h"
+
+#import <Foundation/Foundation.h>
+
+#include <vector>
+
+#include "base/scoped_cftyperef.h"
+#include "base/string_piece.h"
+
+namespace base {
+
+namespace {
+
+// Convert the supplied CFString into the specified encoding, and return it as
+// an STL string of the template type. Returns an empty string on failure.
+//
+// Do not assert in this function since it is used by the asssertion code!
+template <typename StringType>
+static StringType CFStringToSTLStringWithEncodingT(CFStringRef cfstring,
+ CFStringEncoding encoding) {
+ CFIndex length = CFStringGetLength(cfstring);
+ if (length == 0) return StringType();
+
+ CFRange whole_string = CFRangeMake(0, length);
+ CFIndex out_size;
+ CFIndex converted = CFStringGetBytes(cfstring, whole_string, encoding,
+ 0, // lossByte
+ false, // isExternalRepresentation
+ NULL, // buffer
+ 0, // maxBufLen
+ &out_size);
+ if (converted == 0 || out_size == 0) return StringType();
+
+ // out_size is the number of UInt8-sized units needed in the destination.
+ // A buffer allocated as UInt8 units might not be properly aligned to
+ // contain elements of StringType::value_type. Use a container for the
+ // proper value_type, and convert out_size by figuring the number of
+ // value_type elements per UInt8. Leave room for a NUL terminator.
+ typename StringType::size_type elements =
+ out_size * sizeof(UInt8) / sizeof(typename StringType::value_type) + 1;
+
+ std::vector<typename StringType::value_type> out_buffer(elements);
+ converted =
+ CFStringGetBytes(cfstring, whole_string, encoding,
+ 0, // lossByte
+ false, // isExternalRepresentation
+ reinterpret_cast<UInt8*>(&out_buffer[0]), out_size,
+ NULL); // usedBufLen
+ if (converted == 0) return StringType();
+
+ out_buffer[elements - 1] = '\0';
+ return StringType(&out_buffer[0], elements - 1);
+}
+
+// Given an STL string |in| with an encoding specified by |in_encoding|,
+// convert it to |out_encoding| and return it as an STL string of the
+// |OutStringType| template type. Returns an empty string on failure.
+//
+// Do not assert in this function since it is used by the asssertion code!
+template <typename InStringType, typename OutStringType>
+static OutStringType STLStringToSTLStringWithEncodingsT(
+ const InStringType& in, CFStringEncoding in_encoding,
+ CFStringEncoding out_encoding) {
+ typename InStringType::size_type in_length = in.length();
+ if (in_length == 0) return OutStringType();
+
+ scoped_cftyperef<CFStringRef> cfstring(CFStringCreateWithBytesNoCopy(
+ NULL, reinterpret_cast<const UInt8*>(in.data()),
+ in_length * sizeof(typename InStringType::value_type), in_encoding, false,
+ kCFAllocatorNull));
+ if (!cfstring) return OutStringType();
+
+ return CFStringToSTLStringWithEncodingT<OutStringType>(cfstring,
+ out_encoding);
+}
+
+// Given an STL string |in| with an encoding specified by |in_encoding|,
+// return it as a CFStringRef. Returns NULL on failure.
+template <typename StringType>
+static CFStringRef STLStringToCFStringWithEncodingsT(
+ const StringType& in, CFStringEncoding in_encoding) {
+ typename StringType::size_type in_length = in.length();
+ if (in_length == 0) return CFSTR("");
+
+ return CFStringCreateWithBytes(
+ kCFAllocatorDefault, reinterpret_cast<const UInt8*>(in.data()),
+ in_length * sizeof(typename StringType::value_type), in_encoding, false);
+}
+
+// Specify the byte ordering explicitly, otherwise CFString will be confused
+// when strings don't carry BOMs, as they typically won't.
+static const CFStringEncoding kNarrowStringEncoding = kCFStringEncodingUTF8;
+
+#ifdef __BIG_ENDIAN__
+static const CFStringEncoding kWideStringEncoding = kCFStringEncodingUTF32BE;
+#elif defined(__LITTLE_ENDIAN__)
+static const CFStringEncoding kWideStringEncoding = kCFStringEncodingUTF32LE;
+#endif // __LITTLE_ENDIAN__
+
+} // namespace
+
+// Do not assert in this function since it is used by the asssertion code!
+std::string SysWideToUTF8(const std::wstring& wide) {
+ return STLStringToSTLStringWithEncodingsT<std::wstring, std::string>(
+ wide, kWideStringEncoding, kNarrowStringEncoding);
+}
+
+// Do not assert in this function since it is used by the asssertion code!
+std::wstring SysUTF8ToWide(const StringPiece& utf8) {
+ return STLStringToSTLStringWithEncodingsT<StringPiece, std::wstring>(
+ utf8, kNarrowStringEncoding, kWideStringEncoding);
+}
+
+std::string SysWideToNativeMB(const std::wstring& wide) {
+ return SysWideToUTF8(wide);
+}
+
+std::wstring SysNativeMBToWide(const StringPiece& native_mb) {
+ return SysUTF8ToWide(native_mb);
+}
+
+} // namespace base
diff --git a/ipc/chromium/src/base/sys_string_conversions_win.cc b/ipc/chromium/src/base/sys_string_conversions_win.cc
new file mode 100644
index 0000000000..148685ca7e
--- /dev/null
+++ b/ipc/chromium/src/base/sys_string_conversions_win.cc
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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 "base/sys_string_conversions.h"
+
+#include <windows.h>
+
+#include "base/string_piece.h"
+
+namespace base {
+
+// Do not assert in this function since it is used by the asssertion code!
+std::wstring SysMultiByteToWide(const StringPiece& mb, uint32_t code_page) {
+ if (mb.empty()) return std::wstring();
+
+ int mb_length = static_cast<int>(mb.length());
+ // Compute the length of the buffer.
+ int charcount =
+ MultiByteToWideChar(code_page, 0, mb.data(), mb_length, NULL, 0);
+ if (charcount == 0) return std::wstring();
+
+ std::wstring wide;
+ wide.resize(charcount);
+ MultiByteToWideChar(code_page, 0, mb.data(), mb_length, &wide[0], charcount);
+
+ return wide;
+}
+
+// Do not assert in this function since it is used by the asssertion code!
+std::string SysWideToMultiByte(const std::wstring& wide, uint32_t code_page) {
+ int wide_length = static_cast<int>(wide.length());
+ if (wide_length == 0) return std::string();
+
+ // Compute the length of the buffer we'll need.
+ int charcount = WideCharToMultiByte(code_page, 0, wide.data(), wide_length,
+ NULL, 0, NULL, NULL);
+ if (charcount == 0) return std::string();
+
+ std::string mb;
+ mb.resize(charcount);
+ WideCharToMultiByte(code_page, 0, wide.data(), wide_length, &mb[0], charcount,
+ NULL, NULL);
+
+ return mb;
+}
+
+// Do not assert in this function since it is used by the asssertion code!
+std::string SysWideToUTF8(const std::wstring& wide) {
+ return SysWideToMultiByte(wide, CP_UTF8);
+}
+
+// Do not assert in this function since it is used by the asssertion code!
+std::wstring SysUTF8ToWide(const StringPiece& utf8) {
+ return SysMultiByteToWide(utf8, CP_UTF8);
+}
+
+std::string SysWideToNativeMB(const std::wstring& wide) {
+ return SysWideToMultiByte(wide, CP_ACP);
+}
+
+std::wstring SysNativeMBToWide(const StringPiece& native_mb) {
+ return SysMultiByteToWide(native_mb, CP_ACP);
+}
+
+} // namespace base
diff --git a/ipc/chromium/src/base/task.h b/ipc/chromium/src/base/task.h
new file mode 100644
index 0000000000..9b1ae7feff
--- /dev/null
+++ b/ipc/chromium/src/base/task.h
@@ -0,0 +1,227 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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_TASK_H_
+#define BASE_TASK_H_
+
+#include "base/revocable_store.h"
+#include "base/tuple.h"
+
+#include "nsISupportsImpl.h"
+#include "nsThreadUtils.h"
+
+#include <type_traits>
+#include <utility>
+
+// Helper functions so that we can call a function a pass it arguments that come
+// from a Tuple.
+
+namespace details {
+
+// Call the given method on the given object. Arguments are passed by move
+// semantics from the given tuple. If the tuple has length N, the sequence must
+// be IndexSequence<0, 1, ..., N-1>.
+template <size_t... Indices, class ObjT, class Method, typename... Args>
+void CallMethod(std::index_sequence<Indices...>, ObjT* obj, Method method,
+ std::tuple<Args...>& arg) {
+ (obj->*method)(std::move(std::get<Indices>(arg))...);
+}
+
+// Same as above, but call a function.
+template <size_t... Indices, typename Function, typename... Args>
+void CallFunction(std::index_sequence<Indices...>, Function function,
+ std::tuple<Args...>& arg) {
+ (*function)(std::move(std::get<Indices>(arg))...);
+}
+
+} // namespace details
+
+// Call a method on the given object. Arguments are passed by move semantics
+// from the given tuple.
+template <class ObjT, class Method, typename... Args>
+void DispatchTupleToMethod(ObjT* obj, Method method, std::tuple<Args...>& arg) {
+ details::CallMethod(std::index_sequence_for<Args...>{}, obj, method, arg);
+}
+
+// Same as above, but call a function.
+template <typename Function, typename... Args>
+void DispatchTupleToFunction(Function function, std::tuple<Args...>& arg) {
+ details::CallFunction(std::index_sequence_for<Args...>{}, function, arg);
+}
+
+// General task implementations ------------------------------------------------
+
+// Task to delete an object
+template <class T>
+class DeleteTask : public mozilla::CancelableRunnable {
+ public:
+ explicit DeleteTask(T* obj)
+ : mozilla::CancelableRunnable("DeleteTask"), obj_(obj) {}
+ NS_IMETHOD Run() override {
+ delete obj_;
+ return NS_OK;
+ }
+ virtual nsresult Cancel() override {
+ obj_ = NULL;
+ return NS_OK;
+ }
+
+ private:
+ T* MOZ_UNSAFE_REF(
+ "The validity of this pointer must be enforced by "
+ "external factors.") obj_;
+};
+
+// RunnableMethodTraits --------------------------------------------------------
+//
+// This traits-class is used by RunnableMethod to manage the lifetime of the
+// callee object. By default, it is assumed that the callee supports AddRef
+// and Release methods. A particular class can specialize this template to
+// define other lifetime management. For example, if the callee is known to
+// live longer than the RunnableMethod object, then a RunnableMethodTraits
+// struct could be defined with empty RetainCallee and ReleaseCallee methods.
+
+template <class T>
+struct RunnableMethodTraits {
+ static void RetainCallee(T* obj) { obj->AddRef(); }
+ static void ReleaseCallee(T* obj) { obj->Release(); }
+};
+
+// This allows using the NewRunnableMethod() functions with a const pointer
+// to the callee object. See the similar support in nsRefPtr for a rationale
+// of why this is reasonable.
+template <class T>
+struct RunnableMethodTraits<const T> {
+ static void RetainCallee(const T* obj) { const_cast<T*>(obj)->AddRef(); }
+ static void ReleaseCallee(const T* obj) { const_cast<T*>(obj)->Release(); }
+};
+
+// RunnableMethod and RunnableFunction -----------------------------------------
+//
+// Runnable methods are a type of task that call a function on an object when
+// they are run. We implement both an object and a set of NewRunnableMethod and
+// NewRunnableFunction functions for convenience. These functions are
+// overloaded and will infer the template types, simplifying calling code.
+//
+// The template definitions all use the following names:
+// T - the class type of the object you're supplying
+// this is not needed for the Static version of the call
+// Method/Function - the signature of a pointer to the method or function you
+// want to call
+// Param - the parameter(s) to the method, possibly packed as a Tuple
+// A - the first parameter (if any) to the method
+// B - the second parameter (if any) to the mathod
+//
+// Put these all together and you get an object that can call a method whose
+// signature is:
+// R T::MyFunction([A[, B]])
+//
+// Usage:
+// PostTask(NewRunnableMethod(object, &Object::method[, a[, b]])
+// PostTask(NewRunnableFunction(&function[, a[, b]])
+
+// RunnableMethod and NewRunnableMethod implementation -------------------------
+
+template <class T, class Method, class Params>
+class RunnableMethod : public mozilla::CancelableRunnable,
+ public RunnableMethodTraits<T> {
+ public:
+ RunnableMethod(T* obj, Method meth, Params&& params)
+ : mozilla::CancelableRunnable("RunnableMethod"),
+ obj_(obj),
+ meth_(meth),
+ params_(std::forward<Params>(params)) {
+ this->RetainCallee(obj_);
+ }
+ ~RunnableMethod() { ReleaseCallee(); }
+
+ NS_IMETHOD Run() override {
+ if (obj_) DispatchTupleToMethod(obj_, meth_, params_);
+ return NS_OK;
+ }
+
+ virtual nsresult Cancel() override {
+ ReleaseCallee();
+ return NS_OK;
+ }
+
+ private:
+ void ReleaseCallee() {
+ if (obj_) {
+ RunnableMethodTraits<T>::ReleaseCallee(obj_);
+ obj_ = nullptr;
+ }
+ }
+
+ // This is owning because of the RetainCallee and ReleaseCallee calls in the
+ // constructor and destructor.
+ T* MOZ_OWNING_REF obj_;
+ Method meth_;
+ Params params_;
+};
+
+namespace dont_add_new_uses_of_this {
+
+// Don't add new uses of this!!!!
+template <class T, class Method, typename... Args>
+inline already_AddRefed<mozilla::Runnable> NewRunnableMethod(T* object,
+ Method method,
+ Args&&... args) {
+ typedef std::tuple<std::decay_t<Args>...> ArgsTuple;
+ RefPtr<mozilla::Runnable> t = new RunnableMethod<T, Method, ArgsTuple>(
+ object, method, std::make_tuple(std::forward<Args>(args)...));
+ return t.forget();
+}
+
+} // namespace dont_add_new_uses_of_this
+
+// RunnableFunction and NewRunnableFunction implementation ---------------------
+
+template <class Function, class Params>
+class RunnableFunction : public mozilla::CancelableRunnable {
+ public:
+ RunnableFunction(const char* name, Function function, Params&& params)
+ : mozilla::CancelableRunnable(name),
+ function_(function),
+ params_(std::forward<Params>(params)) {}
+
+ ~RunnableFunction() {}
+
+ NS_IMETHOD Run() override {
+ if (function_) DispatchTupleToFunction(function_, params_);
+ return NS_OK;
+ }
+
+ virtual nsresult Cancel() override {
+ function_ = nullptr;
+ return NS_OK;
+ }
+
+ Function function_;
+ Params params_;
+};
+
+template <class Function, typename... Args>
+inline already_AddRefed<mozilla::CancelableRunnable>
+NewCancelableRunnableFunction(const char* name, Function function,
+ Args&&... args) {
+ typedef std::tuple<std::decay_t<Args>...> ArgsTuple;
+ RefPtr<mozilla::CancelableRunnable> t =
+ new RunnableFunction<Function, ArgsTuple>(
+ name, function, std::make_tuple(std::forward<Args>(args)...));
+ return t.forget();
+}
+
+template <class Function, typename... Args>
+inline already_AddRefed<mozilla::Runnable> NewRunnableFunction(
+ const char* name, Function function, Args&&... args) {
+ typedef std::tuple<std::decay_t<Args>...> ArgsTuple;
+ RefPtr<mozilla::Runnable> t = new RunnableFunction<Function, ArgsTuple>(
+ name, function, std::make_tuple(std::forward<Args>(args)...));
+ return t.forget();
+}
+
+#endif // BASE_TASK_H_
diff --git a/ipc/chromium/src/base/thread.cc b/ipc/chromium/src/base/thread.cc
new file mode 100644
index 0000000000..c856272162
--- /dev/null
+++ b/ipc/chromium/src/base/thread.cc
@@ -0,0 +1,201 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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 "base/thread.h"
+
+#include "base/string_util.h"
+#include "base/thread_local.h"
+#include "base/waitable_event.h"
+#include "GeckoProfiler.h"
+#include "mozilla/EventQueue.h"
+#include "mozilla/IOInterposer.h"
+#include "mozilla/ThreadEventQueue.h"
+#include "nsThreadUtils.h"
+#include "nsThreadManager.h"
+
+namespace base {
+
+// This task is used to trigger the message loop to exit.
+class ThreadQuitTask : public mozilla::Runnable {
+ public:
+ ThreadQuitTask() : mozilla::Runnable("ThreadQuitTask") {}
+ NS_IMETHOD Run() override {
+ MessageLoop::current()->Quit();
+ Thread::SetThreadWasQuitProperly(true);
+ return NS_OK;
+ }
+};
+
+// 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)
+ : startup_data_(NULL),
+ thread_(0),
+ message_loop_(NULL),
+ thread_id_(0),
+ name_(name) {
+ MOZ_COUNT_CTOR(base::Thread);
+}
+
+Thread::~Thread() {
+ MOZ_COUNT_DTOR(base::Thread);
+ Stop();
+}
+
+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.
+
+static base::ThreadLocalBoolean& get_tls_bool() {
+ static base::ThreadLocalBoolean tls_ptr;
+ return tls_ptr;
+}
+
+} // namespace
+
+void Thread::SetThreadWasQuitProperly(bool flag) { get_tls_bool().Set(flag); }
+
+bool Thread::GetThreadWasQuitProperly() {
+ bool quit_properly = true;
+#ifndef NDEBUG
+ quit_properly = get_tls_bool().Get();
+#endif
+ return quit_properly;
+}
+
+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; // Record that we failed to start.
+ return false;
+ }
+
+ // Wait for the thread to start and initialize message_loop_
+ startup_data.event.Wait();
+
+ DCHECK(message_loop_);
+ return true;
+}
+
+void Thread::Stop() {
+ if (!thread_was_started()) return;
+
+ // We should only be called on the same thread that started us.
+ DCHECK_NE(thread_id_, PlatformThread::CurrentId());
+
+ // StopSoon may have already been called.
+ if (message_loop_) {
+ RefPtr<ThreadQuitTask> task = new ThreadQuitTask();
+ message_loop_->PostTask(task.forget());
+ }
+
+ // Wait for the thread to exit. It should already have terminated but make
+ // sure this assumption is valid.
+ //
+ // 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 can't receive messages anymore.
+ message_loop_ = NULL;
+
+ // The thread no longer needs to be joined.
+ startup_data_ = NULL;
+}
+
+void Thread::StopSoon() {
+ if (!message_loop_) return;
+
+ // We should only be called on the same thread that started us.
+ DCHECK_NE(thread_id_, PlatformThread::CurrentId());
+
+ // We had better have a message loop at this point! If we do not, then it
+ // most likely means that the thread terminated unexpectedly, probably due
+ // to someone calling Quit() on our message loop directly.
+ DCHECK(message_loop_);
+
+ RefPtr<ThreadQuitTask> task = new ThreadQuitTask();
+ message_loop_->PostTask(task.forget());
+}
+
+void Thread::ThreadMain() {
+ nsCOMPtr<nsIThread> xpcomThread;
+ auto loopType = startup_data_->options.message_loop_type;
+ if (loopType == MessageLoop::TYPE_MOZILLA_NONMAINTHREAD ||
+ loopType == MessageLoop::TYPE_MOZILLA_NONMAINUITHREAD) {
+ auto queue = mozilla::MakeRefPtr<mozilla::ThreadEventQueue>(
+ mozilla::MakeUnique<mozilla::EventQueue>());
+ xpcomThread = nsThreadManager::get().CreateCurrentThread(queue);
+ } else {
+ xpcomThread = NS_GetCurrentThread();
+ }
+
+ AUTO_PROFILER_REGISTER_THREAD(name_.c_str());
+ mozilla::IOInterposer::RegisterCurrentThread();
+
+ // The message loop for this thread.
+ MessageLoop message_loop(startup_data_->options.message_loop_type,
+ xpcomThread);
+
+ xpcomThread = nullptr;
+
+ // Complete the initialization of our Thread object.
+ thread_id_ = PlatformThread::CurrentId();
+ PlatformThread::SetName(name_.c_str());
+ NS_SetCurrentThreadName(name_.c_str());
+ message_loop.set_thread_name(name_);
+ message_loop.set_hang_timeouts(startup_data_->options.transient_hang_timeout,
+ startup_data_->options.permanent_hang_timeout);
+ 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.
+
+ message_loop.Run();
+
+ // Let the thread do extra cleanup.
+ CleanUp();
+
+ // Assert that MessageLoop::Quit was called by ThreadQuitTask.
+ DCHECK(GetThreadWasQuitProperly());
+
+ mozilla::IOInterposer::UnregisterCurrentThread();
+
+ // We can't receive messages anymore.
+ message_loop_ = NULL;
+ thread_id_ = 0;
+}
+
+} // namespace base
diff --git a/ipc/chromium/src/base/thread.h b/ipc/chromium/src/base/thread.h
new file mode 100644
index 0000000000..7b9a5975d3
--- /dev/null
+++ b/ipc/chromium/src/base/thread.h
@@ -0,0 +1,176 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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_THREAD_H_
+#define BASE_THREAD_H_
+
+#include <stdint.h>
+#include <string>
+
+#include "base/message_loop.h"
+#include "base/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.
+class Thread : PlatformThread::Delegate {
+ public:
+ struct Options {
+ // 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;
+
+ // Specifies the transient and permanent hang timeouts for background hang
+ // monitoring. A value of 0 indicates there is no timeout.
+ uint32_t transient_hang_timeout;
+ uint32_t permanent_hang_timeout;
+
+ Options()
+ : message_loop_type(MessageLoop::TYPE_DEFAULT),
+ stack_size(0),
+ transient_hang_timeout(0),
+ permanent_hang_timeout(0) {}
+ Options(MessageLoop::Type type, size_t size)
+ : message_loop_type(type),
+ stack_size(size),
+ transient_hang_timeout(0),
+ permanent_hang_timeout(0) {}
+ };
+
+ // 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_; }
+
+ // 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_; }
+
+ // Reset thread ID as current thread.
+ PlatformThreadId reset_thread_id() {
+ thread_id_ = PlatformThread::CurrentId();
+ return thread_id_;
+ }
+
+ // Returns true if the thread has been started, and not yet stopped.
+ // When a thread is running, the thread_id_ is non-zero.
+ bool IsRunning() const { return thread_id_ != 0; }
+
+ protected:
+ // Called just prior to starting the message loop
+ virtual void Init() {}
+
+ // Called just after the message loop ends
+ virtual void CleanUp() {}
+
+ static void SetThreadWasQuitProperly(bool flag);
+ static bool GetThreadWasQuitProperly();
+
+ private:
+ // PlatformThread::Delegate methods:
+ virtual void ThreadMain() override;
+
+ // We piggy-back on the startup_data_ member to know if we successfully
+ // started the thread. This way we know that we need to call Join.
+ bool thread_was_started() const { return startup_data_ != NULL; }
+
+ // 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/ipc/chromium/src/base/thread_local.h b/ipc/chromium/src/base/thread_local.h
new file mode 100644
index 0000000000..c031875d01
--- /dev/null
+++ b/ipc/chromium/src/base/thread_local.h
@@ -0,0 +1,121 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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.
+
+// WARNING: Thread local storage is a bit tricky to get right. Please make
+// sure that this is really the proper solution for what you're trying to
+// achieve. Don't prematurely optimize, most likely you can just use a Lock.
+//
+// These classes implement a warpper around the platform's TLS storage
+// mechanism. On construction, they will allocate a TLS slot, and free the
+// TLS slot on destruction. No memory management (creation or destruction) is
+// handled. This means for uses of ThreadLocalPointer, you must correctly
+// manage the memory yourself, these classes will not destroy the pointer for
+// you. There are no at-thread-exit actions taken by these classes.
+//
+// ThreadLocalPointer<Type> wraps a Type*. It performs no creation or
+// destruction, so memory management must be handled elsewhere. The first call
+// to Get() on a thread will return NULL. You can update the pointer with a
+// call to Set().
+//
+// ThreadLocalBoolean wraps a bool. It will default to false if it has never
+// been set otherwise with Set().
+//
+// Thread Safety: An instance of ThreadLocalStorage is completely thread safe
+// once it has been created. If you want to dynamically create an instance,
+// you must of course properly deal with safety and race conditions. This
+// means a function-level static initializer is generally inappropiate.
+//
+// Example usage:
+// // My class is logically attached to a single thread. We cache a pointer
+// // on the thread it was created on, so we can implement current().
+// MyClass::MyClass() {
+// DCHECK(Singleton<ThreadLocalPointer<MyClass> >::get()->Get() == NULL);
+// Singleton<ThreadLocalPointer<MyClass> >::get()->Set(this);
+// }
+//
+// MyClass::~MyClass() {
+// DCHECK(Singleton<ThreadLocalPointer<MyClass> >::get()->Get() != NULL);
+// Singleton<ThreadLocalPointer<MyClass> >::get()->Set(NULL);
+// }
+//
+// // Return the current MyClass associated with the calling thread, can be
+// // NULL if there isn't a MyClass associated.
+// MyClass* MyClass::current() {
+// return Singleton<ThreadLocalPointer<MyClass> >::get()->Get();
+// }
+
+#ifndef BASE_THREAD_LOCAL_H_
+#define BASE_THREAD_LOCAL_H_
+
+#include "base/basictypes.h"
+
+#if defined(XP_WIN)
+# include <windows.h>
+#else
+# include <pthread.h>
+#endif
+
+namespace base {
+
+// Helper functions that abstract the cross-platform APIs. Do not use directly.
+struct ThreadLocalPlatform {
+#if defined(XP_WIN)
+ typedef DWORD SlotType;
+#else
+ typedef pthread_key_t SlotType;
+#endif
+
+ static void AllocateSlot(SlotType& slot);
+ static void FreeSlot(SlotType& slot);
+ static void* GetValueFromSlot(SlotType& slot);
+ static void SetValueInSlot(SlotType& slot, void* value);
+};
+
+template <typename Type>
+class ThreadLocalPointer {
+ public:
+ ThreadLocalPointer() : slot_() { ThreadLocalPlatform::AllocateSlot(slot_); }
+
+ ThreadLocalPointer(const ThreadLocalPointer&) = delete;
+ ThreadLocalPointer& operator=(const ThreadLocalPointer&) = delete;
+
+ ~ThreadLocalPointer() { ThreadLocalPlatform::FreeSlot(slot_); }
+
+ Type* Get() {
+ return static_cast<Type*>(ThreadLocalPlatform::GetValueFromSlot(slot_));
+ }
+
+ void Set(Type* ptr) { ThreadLocalPlatform::SetValueInSlot(slot_, ptr); }
+
+ private:
+ typedef ThreadLocalPlatform::SlotType SlotType;
+
+ SlotType slot_;
+};
+
+class ThreadLocalBoolean {
+ public:
+ ThreadLocalBoolean() {}
+
+ ThreadLocalBoolean(const ThreadLocalBoolean&) = delete;
+ ThreadLocalBoolean& operator=(const ThreadLocalBoolean&) = delete;
+
+ ~ThreadLocalBoolean() {}
+
+ bool Get() { return tlp_.Get() != NULL; }
+
+ void Set(bool val) {
+ uintptr_t intVal = val ? 1 : 0;
+ tlp_.Set(reinterpret_cast<void*>(intVal));
+ }
+
+ private:
+ ThreadLocalPointer<void> tlp_;
+};
+
+} // namespace base
+
+#endif // BASE_THREAD_LOCAL_H_
diff --git a/ipc/chromium/src/base/thread_local_posix.cc b/ipc/chromium/src/base/thread_local_posix.cc
new file mode 100644
index 0000000000..050a6e4b92
--- /dev/null
+++ b/ipc/chromium/src/base/thread_local_posix.cc
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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 "base/thread_local.h"
+
+#include <pthread.h>
+
+#include "base/logging.h"
+
+namespace base {
+
+// static
+void ThreadLocalPlatform::AllocateSlot(SlotType& slot) {
+ int error = pthread_key_create(&slot, NULL);
+ CHECK(error == 0);
+}
+
+// static
+void ThreadLocalPlatform::FreeSlot(SlotType& slot) {
+ int error = pthread_key_delete(slot);
+ DCHECK(error == 0);
+}
+
+// static
+void* ThreadLocalPlatform::GetValueFromSlot(SlotType& slot) {
+ return pthread_getspecific(slot);
+}
+
+// static
+void ThreadLocalPlatform::SetValueInSlot(SlotType& slot, void* value) {
+ int error = pthread_setspecific(slot, value);
+ CHECK(error == 0);
+}
+
+} // namespace base
diff --git a/ipc/chromium/src/base/thread_local_storage.h b/ipc/chromium/src/base/thread_local_storage.h
new file mode 100644
index 0000000000..1134aa6ad9
--- /dev/null
+++ b/ipc/chromium/src/base/thread_local_storage.h
@@ -0,0 +1,95 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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_THREAD_LOCAL_STORAGE_H_
+#define BASE_THREAD_LOCAL_STORAGE_H_
+
+#include "base/basictypes.h"
+
+#if defined(XP_UNIX)
+# include <pthread.h>
+#endif
+
+// Wrapper for thread local storage. This class doesn't do much except provide
+// an API for portability.
+class ThreadLocalStorage {
+ public:
+ // Prototype for the TLS destructor function, which can be optionally used to
+ // cleanup thread local storage on thread exit. 'value' is the data that is
+ // stored in thread local storage.
+ typedef void (*TLSDestructorFunc)(void* value);
+
+ // A key representing one value stored in TLS.
+ class Slot {
+ public:
+ explicit Slot(TLSDestructorFunc destructor = NULL);
+
+ // This constructor should be used for statics.
+ // It returns an uninitialized Slot.
+ explicit Slot(base::LinkerInitialized x) {}
+
+ // Set up the TLS slot. Called by the constructor.
+ // 'destructor' is a pointer to a function to perform per-thread cleanup of
+ // this object. If set to NULL, no cleanup is done for this TLS slot.
+ // Returns false on error.
+ bool Initialize(TLSDestructorFunc destructor);
+
+ // Free a previously allocated TLS 'slot'.
+ // If a destructor was set for this slot, removes
+ // the destructor so that remaining threads exiting
+ // will not free data.
+ void Free();
+
+ // Get the thread-local value stored in slot 'slot'.
+ // Values are guaranteed to initially be zero.
+ void* Get() const;
+
+ // Set the thread-local value stored in slot 'slot' to
+ // value 'value'.
+ void Set(void* value);
+
+ bool initialized() const { return initialized_; }
+
+ private:
+ // The internals of this struct should be considered private.
+ bool initialized_;
+#if defined(XP_WIN)
+ int slot_;
+#else
+ pthread_key_t key_;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(Slot);
+ };
+
+#if defined(XP_WIN)
+ // Function called when on thread exit to call TLS
+ // destructor functions. This function is used internally.
+ static void ThreadExit();
+
+ private:
+ // Function to lazily initialize our thread local storage.
+ static void** Initialize();
+
+ private:
+ // The maximum number of 'slots' in our thread local storage stack.
+ // For now, this is fixed. We could either increase statically, or
+ // we could make it dynamic in the future.
+ static const int kThreadLocalStorageSize = 64;
+
+ static long tls_key_;
+ static long tls_max_;
+ static TLSDestructorFunc tls_destructors_[kThreadLocalStorageSize];
+#endif // XP_WIN
+
+ DISALLOW_COPY_AND_ASSIGN(ThreadLocalStorage);
+};
+
+// Temporary backwards-compatible name.
+// TODO(evanm): replace all usage of TLSSlot.
+typedef ThreadLocalStorage::Slot TLSSlot;
+
+#endif // BASE_THREAD_LOCAL_STORAGE_H_
diff --git a/ipc/chromium/src/base/thread_local_win.cc b/ipc/chromium/src/base/thread_local_win.cc
new file mode 100644
index 0000000000..2eb68e63b3
--- /dev/null
+++ b/ipc/chromium/src/base/thread_local_win.cc
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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 "base/thread_local.h"
+
+#include <windows.h>
+
+#include "base/logging.h"
+
+namespace base {
+
+// static
+void ThreadLocalPlatform::AllocateSlot(SlotType& slot) {
+ slot = TlsAlloc();
+ CHECK(slot != TLS_OUT_OF_INDEXES);
+}
+
+// static
+void ThreadLocalPlatform::FreeSlot(SlotType& slot) {
+ if (!TlsFree(slot)) {
+ NOTREACHED() << "Failed to deallocate tls slot with TlsFree().";
+ }
+}
+
+// static
+void* ThreadLocalPlatform::GetValueFromSlot(SlotType& slot) {
+ return TlsGetValue(slot);
+}
+
+// static
+void ThreadLocalPlatform::SetValueInSlot(SlotType& slot, void* value) {
+ if (!TlsSetValue(slot, value)) {
+ CHECK(false)
+ << "Failed to TlsSetValue().";
+ }
+}
+
+} // namespace base
diff --git a/ipc/chromium/src/base/time.cc b/ipc/chromium/src/base/time.cc
new file mode 100644
index 0000000000..2d76878005
--- /dev/null
+++ b/ipc/chromium/src/base/time.cc
@@ -0,0 +1,97 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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 "base/time.h"
+#include "base/string_util.h"
+#include "base/sys_string_conversions.h"
+#include "prtime.h"
+
+#include "base/logging.h"
+
+namespace base {
+
+// TimeDelta ------------------------------------------------------------------
+
+int TimeDelta::InDays() const {
+ return static_cast<int>(delta_ / Time::kMicrosecondsPerDay);
+}
+
+int TimeDelta::InHours() const {
+ return static_cast<int>(delta_ / Time::kMicrosecondsPerHour);
+}
+
+int TimeDelta::InMinutes() const {
+ return static_cast<int>(delta_ / Time::kMicrosecondsPerMinute);
+}
+
+double TimeDelta::InSecondsF() const {
+ return static_cast<double>(delta_) / Time::kMicrosecondsPerSecond;
+}
+
+int64_t TimeDelta::InSeconds() const {
+ return delta_ / Time::kMicrosecondsPerSecond;
+}
+
+double TimeDelta::InMillisecondsF() const {
+ return static_cast<double>(delta_) / Time::kMicrosecondsPerMillisecond;
+}
+
+int64_t TimeDelta::InMilliseconds() const {
+ return delta_ / Time::kMicrosecondsPerMillisecond;
+}
+
+int64_t TimeDelta::InMicroseconds() const { return delta_; }
+
+// Time -----------------------------------------------------------------------
+
+// static
+Time Time::FromTimeT(time_t tt) {
+ if (tt == 0) return Time(); // Preserve 0 so we can tell it doesn't exist.
+ return Time((tt * kMicrosecondsPerSecond) + kTimeTToMicrosecondsOffset);
+}
+
+time_t Time::ToTimeT() const {
+ if (us_ == 0) return 0; // Preserve 0 so we can tell it doesn't exist.
+ return (us_ - kTimeTToMicrosecondsOffset) / kMicrosecondsPerSecond;
+}
+
+// static
+Time Time::FromDoubleT(double dt) {
+ return Time((dt * static_cast<double>(kMicrosecondsPerSecond)) +
+ kTimeTToMicrosecondsOffset);
+}
+
+double Time::ToDoubleT() const {
+ if (us_ == 0) return 0; // Preserve 0 so we can tell it doesn't exist.
+ return (static_cast<double>(us_ - kTimeTToMicrosecondsOffset) /
+ static_cast<double>(kMicrosecondsPerSecond));
+}
+
+Time Time::LocalMidnight() const {
+ Exploded exploded;
+ LocalExplode(&exploded);
+ exploded.hour = 0;
+ exploded.minute = 0;
+ exploded.second = 0;
+ exploded.millisecond = 0;
+ return FromLocalExploded(exploded);
+}
+
+// static
+bool Time::FromString(const wchar_t* time_string, Time* parsed_time) {
+ DCHECK((time_string != NULL) && (parsed_time != NULL));
+ std::string ascii_time_string = SysWideToUTF8(time_string);
+ if (ascii_time_string.length() == 0) return false;
+ PRTime result_time = 0;
+ PRStatus result =
+ PR_ParseTimeString(ascii_time_string.c_str(), PR_FALSE, &result_time);
+ if (PR_SUCCESS != result) return false;
+ result_time += kTimeTToMicrosecondsOffset;
+ *parsed_time = Time(result_time);
+ return true;
+}
+
+} // namespace base
diff --git a/ipc/chromium/src/base/time.h b/ipc/chromium/src/base/time.h
new file mode 100644
index 0000000000..cc9bc8e30e
--- /dev/null
+++ b/ipc/chromium/src/base/time.h
@@ -0,0 +1,392 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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.
+
+// 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_
+
+#include <time.h>
+
+#include "base/basictypes.h"
+
+namespace base {
+
+class Time;
+class TimeTicks;
+
+// This unit test does a lot of manual time manipulation.
+class PageLoadTrackerUnitTest;
+
+// TimeDelta ------------------------------------------------------------------
+
+class TimeDelta {
+ public:
+ TimeDelta() : delta_(0) {}
+
+ // Converts units of time to TimeDeltas.
+ static TimeDelta FromDays(int64_t days);
+ static TimeDelta FromHours(int64_t hours);
+ static TimeDelta FromMinutes(int64_t minutes);
+ static TimeDelta FromSeconds(int64_t secs);
+ static TimeDelta FromMilliseconds(int64_t ms);
+ static TimeDelta FromMicroseconds(int64_t 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_t ToInternalValue() const { return delta_; }
+
+ // Returns the time delta in some unit. The F versions return a floating
+ // point value, the "regular" versions return a rounded-down value.
+ int InDays() const;
+ int InHours() const;
+ int InMinutes() const;
+ double InSecondsF() const;
+ int64_t InSeconds() const;
+ double InMillisecondsF() const;
+ int64_t InMilliseconds() const;
+ int64_t 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_t a) const { return TimeDelta(delta_ * a); }
+ TimeDelta operator/(int64_t a) const { return TimeDelta(delta_ / a); }
+ TimeDelta& operator*=(int64_t a) {
+ delta_ *= a;
+ return *this;
+ }
+ TimeDelta& operator/=(int64_t a) {
+ delta_ /= a;
+ return *this;
+ }
+ int64_t 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_t 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_t delta_us) : delta_(delta_us) {}
+
+ // Delta in microseconds.
+ int64_t delta_;
+};
+
+inline TimeDelta operator*(int64_t a, TimeDelta td) {
+ return TimeDelta(a * td.delta_);
+}
+
+// Time -----------------------------------------------------------------------
+
+// Represents a wall clock time.
+class Time {
+ public:
+ static const int64_t kMillisecondsPerSecond = 1000;
+ static const int64_t kMicrosecondsPerMillisecond = 1000;
+ static const int64_t kMicrosecondsPerSecond =
+ kMicrosecondsPerMillisecond * kMillisecondsPerSecond;
+ static const int64_t kMicrosecondsPerMinute = kMicrosecondsPerSecond * 60;
+ static const int64_t kMicrosecondsPerHour = kMicrosecondsPerMinute * 60;
+ static const int64_t kMicrosecondsPerDay = kMicrosecondsPerHour * 24;
+ static const int64_t kMicrosecondsPerWeek = kMicrosecondsPerDay * 7;
+ static const int64_t kNanosecondsPerMicrosecond = 1000;
+ static const int64_t kNanosecondsPerSecond =
+ kNanosecondsPerMicrosecond * kMicrosecondsPerSecond;
+
+ // 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 Exploded {
+ int year; // Four digit year "2007"
+ signed char month; // 1-based month (values 1 = January, etc.)
+ signed char day_of_week; // 0-based day of week (0 = Sunday, etc.)
+ signed char day_of_month; // 1-based day of month (1-31)
+ signed char hour; // Hour within the current day (0-23)
+ signed char minute; // Minute within the current hour (0-59)
+ signed char 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)
+ };
+
+ // 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 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.
+ static Time FromDoubleT(double dt);
+ double ToDoubleT() const;
+
+ // 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_t 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 wchar_t* 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_t 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;
+
+ // 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);
+
+ explicit Time(int64_t us) : us_(us) {}
+
+ // The representation of Jan 1, 1970 UTC in microseconds since the
+ // platform-dependent epoch.
+ static const int64_t kTimeTToMicrosecondsOffset;
+
+ // Time in microseconds in UTC.
+ int64_t us_;
+};
+
+inline Time TimeDelta::operator+(Time t) const { return Time(t.us_ + delta_); }
+
+// Inline the TimeDelta factory methods, for fast TimeDelta construction.
+
+// static
+inline TimeDelta TimeDelta::FromDays(int64_t days) {
+ return TimeDelta(days * Time::kMicrosecondsPerDay);
+}
+
+// static
+inline TimeDelta TimeDelta::FromHours(int64_t hours) {
+ return TimeDelta(hours * Time::kMicrosecondsPerHour);
+}
+
+// static
+inline TimeDelta TimeDelta::FromMinutes(int64_t minutes) {
+ return TimeDelta(minutes * Time::kMicrosecondsPerMinute);
+}
+
+// static
+inline TimeDelta TimeDelta::FromSeconds(int64_t secs) {
+ return TimeDelta(secs * Time::kMicrosecondsPerSecond);
+}
+
+// static
+inline TimeDelta TimeDelta::FromMilliseconds(int64_t ms) {
+ return TimeDelta(ms * Time::kMicrosecondsPerMillisecond);
+}
+
+// static
+inline TimeDelta TimeDelta::FromMicroseconds(int64_t us) {
+ return TimeDelta(us);
+}
+
+// TimeTicks ------------------------------------------------------------------
+
+class TimeTicks {
+ public:
+ TimeTicks() : ticks_(0) {}
+ TimeTicks(const TimeTicks&) = default;
+
+ // 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 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_t 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;
+ friend class PageLoadTrackerUnitTest;
+
+ // Please use Now() to create a new object. This is for internal use
+ // and testing. Ticks is in microseconds.
+ explicit TimeTicks(int64_t ticks) : ticks_(ticks) {}
+
+ // Tick count in microseconds.
+ int64_t ticks_;
+};
+
+inline TimeTicks TimeDelta::operator+(TimeTicks t) const {
+ return TimeTicks(t.ticks_ + delta_);
+}
+
+} // namespace base
+
+#endif // BASE_TIME_H_
diff --git a/ipc/chromium/src/base/time_mac.cc b/ipc/chromium/src/base/time_mac.cc
new file mode 100644
index 0000000000..6ab1515601
--- /dev/null
+++ b/ipc/chromium/src/base/time_mac.cc
@@ -0,0 +1,122 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// Copyright (c) 2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/time.h"
+
+#include <CoreFoundation/CFDate.h>
+#include <CoreFoundation/CFTimeZone.h>
+#include <mach/mach_time.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/scoped_cftyperef.h"
+
+namespace base {
+
+// The Time routines in this file use Mach and CoreFoundation APIs, since the
+// POSIX definition of time_t in Mac OS X wraps around after 2038--and
+// there are already cookie expiration dates, etc., past that time out in
+// the field. Using CFDate prevents that problem, and using mach_absolute_time
+// for TimeTicks gives us nice high-resolution interval timing.
+
+// Time -----------------------------------------------------------------------
+
+// The internal representation of Time uses a 64-bit microsecond count
+// from 1970-01-01 00:00:00 UTC. Core Foundation uses a double second count
+// since 2001-01-01 00:00:00 UTC.
+
+// Some functions in time.cc use time_t directly, so we provide a zero offset
+// for them. The epoch is 1970-01-01 00:00:00 UTC.
+// static
+const int64_t Time::kTimeTToMicrosecondsOffset = GG_INT64_C(0);
+
+// static
+Time Time::Now() {
+ CFAbsoluteTime now =
+ CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970;
+ return Time(static_cast<int64_t>(now * kMicrosecondsPerSecond));
+}
+
+// static
+Time Time::NowFromSystemTime() {
+ // Just use Now() because Now() returns the system time.
+ return Now();
+}
+
+// static
+Time Time::FromExploded(bool is_local, const Exploded& exploded) {
+ CFGregorianDate date;
+ date.second =
+ exploded.second +
+ exploded.millisecond / static_cast<double>(kMillisecondsPerSecond);
+ date.minute = exploded.minute;
+ date.hour = exploded.hour;
+ date.day = exploded.day_of_month;
+ date.month = exploded.month;
+ date.year = exploded.year;
+
+ scoped_cftyperef<CFTimeZoneRef> time_zone(is_local ? CFTimeZoneCopySystem()
+ : NULL);
+ CFAbsoluteTime seconds = CFGregorianDateGetAbsoluteTime(date, time_zone) +
+ kCFAbsoluteTimeIntervalSince1970;
+ return Time(static_cast<int64_t>(seconds * kMicrosecondsPerSecond));
+}
+
+void Time::Explode(bool is_local, Exploded* exploded) const {
+ CFAbsoluteTime seconds = (static_cast<double>(us_) / kMicrosecondsPerSecond) -
+ kCFAbsoluteTimeIntervalSince1970;
+
+ scoped_cftyperef<CFTimeZoneRef> time_zone(is_local ? CFTimeZoneCopySystem()
+ : NULL);
+ CFGregorianDate date = CFAbsoluteTimeGetGregorianDate(seconds, time_zone);
+
+ exploded->year = date.year;
+ exploded->month = date.month;
+ exploded->day_of_month = date.day;
+ exploded->hour = date.hour;
+ exploded->minute = date.minute;
+ exploded->second = date.second;
+ exploded->millisecond =
+ static_cast<int>(date.second * kMillisecondsPerSecond) %
+ kMillisecondsPerSecond;
+}
+
+// TimeTicks ------------------------------------------------------------------
+
+// static
+TimeTicks TimeTicks::Now() {
+ uint64_t absolute_micro;
+
+ static mach_timebase_info_data_t timebase_info;
+ if (timebase_info.denom == 0) {
+ // Zero-initialization of statics guarantees that denom will be 0 before
+ // calling mach_timebase_info. mach_timebase_info will never set denom to
+ // 0 as that would be invalid, so the zero-check can be used to determine
+ // whether mach_timebase_info has already been called. This is
+ // recommended by Apple's QA1398.
+ kern_return_t kr = mach_timebase_info(&timebase_info);
+ DCHECK(kr == KERN_SUCCESS);
+ }
+
+ // mach_absolute_time is it when it comes to ticks on the Mac. Other calls
+ // with less precision (such as TickCount) just call through to
+ // mach_absolute_time.
+
+ // timebase_info converts absolute time tick units into nanoseconds. Convert
+ // to microseconds up front to stave off overflows.
+ absolute_micro = mach_absolute_time() / Time::kNanosecondsPerMicrosecond *
+ timebase_info.numer / timebase_info.denom;
+
+ // Don't bother with the rollover handling that the Windows version does.
+ // With numer and denom = 1 (the expected case), the 64-bit absolute time
+ // reported in nanoseconds is enough to last nearly 585 years.
+
+ return TimeTicks(absolute_micro);
+}
+
+} // namespace base
diff --git a/ipc/chromium/src/base/time_posix.cc b/ipc/chromium/src/base/time_posix.cc
new file mode 100644
index 0000000000..1f122bb698
--- /dev/null
+++ b/ipc/chromium/src/base/time_posix.cc
@@ -0,0 +1,200 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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 "base/time.h"
+
+#ifdef XP_DARWIN
+# include <mach/mach_time.h>
+#endif
+#include <sys/time.h>
+#if defined(ANDROID) && !defined(__LP64__)
+# include <time64.h>
+#else
+# include <time.h>
+#endif
+#if defined(ANDROID) || defined(XP_UNIX)
+# include <unistd.h>
+#endif
+
+#include <limits>
+#include <cstdint>
+
+#include "base/logging.h"
+
+namespace base {
+
+// The Time routines in this file use standard POSIX routines, or almost-
+// standard routines in the case of timegm. We need to use a Mach-specific
+// function for TimeTicks::Now() on Mac OS X.
+
+// Time -----------------------------------------------------------------------
+
+// Some functions in time.cc use time_t directly, so we provide a zero offset
+// for them. The epoch is 1970-01-01 00:00:00 UTC.
+// static
+const int64_t Time::kTimeTToMicrosecondsOffset = GG_INT64_C(0);
+
+// static
+Time Time::Now() {
+ struct timeval tv;
+ struct timezone tz = {0, 0}; // UTC
+ if (gettimeofday(&tv, &tz) != 0) {
+ DCHECK(0) << "Could not determine time of day";
+ }
+ // Combine seconds and microseconds in a 64-bit field containing microseconds
+ // since the epoch. That's enough for nearly 600 centuries.
+ return Time(tv.tv_sec * kMicrosecondsPerSecond + tv.tv_usec);
+}
+
+// static
+Time Time::NowFromSystemTime() {
+ // Just use Now() because Now() returns the system time.
+ return Now();
+}
+
+// static
+Time Time::FromExploded(bool is_local, const Exploded& exploded) {
+ struct tm timestruct;
+ timestruct.tm_sec = exploded.second;
+ timestruct.tm_min = exploded.minute;
+ timestruct.tm_hour = exploded.hour;
+ timestruct.tm_mday = exploded.day_of_month;
+ timestruct.tm_mon = exploded.month - 1;
+ timestruct.tm_year = exploded.year - 1900;
+ timestruct.tm_wday = exploded.day_of_week; // mktime/timegm ignore this
+ timestruct.tm_yday = 0; // mktime/timegm ignore this
+ timestruct.tm_isdst = -1; // attempt to figure it out
+#ifndef XP_SOLARIS
+ timestruct.tm_gmtoff = 0; // not a POSIX field, so mktime/timegm ignore
+ timestruct.tm_zone = NULL; // not a POSIX field, so mktime/timegm ignore
+#endif
+
+ time_t seconds;
+#ifdef ANDROID
+ seconds = mktime(&timestruct);
+#else
+ if (is_local)
+ seconds = mktime(&timestruct);
+ else
+ seconds = timegm(&timestruct);
+#endif
+
+ int64_t milliseconds;
+ // Handle overflow. Clamping the range to what mktime and timegm might
+ // return is the best that can be done here. It's not ideal, but it's better
+ // than failing here or ignoring the overflow case and treating each time
+ // overflow as one second prior to the epoch.
+ if (seconds == -1 && (exploded.year < 1969 || exploded.year > 1970)) {
+ // If exploded.year is 1969 or 1970, take -1 as correct, with the
+ // time indicating 1 second prior to the epoch. (1970 is allowed to handle
+ // time zone and DST offsets.) Otherwise, return the most future or past
+ // time representable. Assumes the time_t epoch is 1970-01-01 00:00:00 UTC.
+ //
+ // The minimum and maximum representible times that mktime and timegm could
+ // return are used here instead of values outside that range to allow for
+ // proper round-tripping between exploded and counter-type time
+ // representations in the presence of possible truncation to time_t by
+ // division and use with other functions that accept time_t.
+ //
+ // When representing the most distant time in the future, add in an extra
+ // 999ms to avoid the time being less than any other possible value that
+ // this function can return.
+
+ // Take care to avoid overflows when time_t is int64_t.
+ if (exploded.year < 1969) {
+ int64_t min_seconds = (sizeof(time_t) < sizeof(int64_t))
+ ? std::numeric_limits<time_t>::min()
+ : std::numeric_limits<int32_t>::min();
+ milliseconds = min_seconds * kMillisecondsPerSecond;
+ } else {
+ int64_t max_seconds = (sizeof(time_t) < sizeof(int64_t))
+ ? std::numeric_limits<time_t>::max()
+ : std::numeric_limits<int32_t>::max();
+ milliseconds = max_seconds * kMillisecondsPerSecond;
+ milliseconds += kMillisecondsPerSecond - 1;
+ }
+ } else {
+ milliseconds = seconds * kMillisecondsPerSecond + exploded.millisecond;
+ }
+
+ return Time(milliseconds * kMicrosecondsPerMillisecond);
+}
+
+void Time::Explode(bool is_local, Exploded* exploded) const {
+ // Time stores times with microsecond resolution, but Exploded only carries
+ // millisecond resolution, so begin by being lossy.
+ int64_t milliseconds = us_ / kMicrosecondsPerMillisecond;
+ time_t seconds = milliseconds / kMillisecondsPerSecond;
+
+ struct tm timestruct;
+ if (is_local)
+ localtime_r(&seconds, &timestruct);
+ else
+ gmtime_r(&seconds, &timestruct);
+
+ exploded->year = timestruct.tm_year + 1900;
+ exploded->month = timestruct.tm_mon + 1;
+ exploded->day_of_week = timestruct.tm_wday;
+ exploded->day_of_month = timestruct.tm_mday;
+ exploded->hour = timestruct.tm_hour;
+ exploded->minute = timestruct.tm_min;
+ exploded->second = timestruct.tm_sec;
+ exploded->millisecond = milliseconds % kMillisecondsPerSecond;
+}
+
+// TimeTicks ------------------------------------------------------------------
+
+// static
+TimeTicks TimeTicks::Now() {
+ uint64_t absolute_micro;
+
+#if defined(XP_DARWIN)
+ static mach_timebase_info_data_t timebase_info;
+ if (timebase_info.denom == 0) {
+ // Zero-initialization of statics guarantees that denom will be 0 before
+ // calling mach_timebase_info. mach_timebase_info will never set denom to
+ // 0 as that would be invalid, so the zero-check can be used to determine
+ // whether mach_timebase_info has already been called. This is
+ // recommended by Apple's QA1398.
+ kern_return_t kr = mach_timebase_info(&timebase_info);
+ DCHECK(kr == KERN_SUCCESS);
+ }
+
+ // mach_absolute_time is it when it comes to ticks on the Mac. Other calls
+ // with less precision (such as TickCount) just call through to
+ // mach_absolute_time.
+
+ // timebase_info converts absolute time tick units into nanoseconds. Convert
+ // to microseconds up front to stave off overflows.
+ absolute_micro = mach_absolute_time() / Time::kNanosecondsPerMicrosecond *
+ timebase_info.numer / timebase_info.denom;
+
+ // Don't bother with the rollover handling that the Windows version does.
+ // With numer and denom = 1 (the expected case), the 64-bit absolute time
+ // reported in nanoseconds is enough to last nearly 585 years.
+
+#elif defined(XP_OPENBSD) || defined(XP_UNIX) && \
+ defined(_POSIX_MONOTONIC_CLOCK) && \
+ _POSIX_MONOTONIC_CLOCK >= 0
+
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
+ NOTREACHED() << "clock_gettime(CLOCK_MONOTONIC) failed.";
+ return TimeTicks();
+ }
+
+ absolute_micro =
+ (static_cast<int64_t>(ts.tv_sec) * Time::kMicrosecondsPerSecond) +
+ (static_cast<int64_t>(ts.tv_nsec) / Time::kNanosecondsPerMicrosecond);
+
+#else // _POSIX_MONOTONIC_CLOCK
+# error No usable tick clock function on this platform.
+#endif // _POSIX_MONOTONIC_CLOCK
+
+ return TimeTicks(absolute_micro);
+}
+
+} // namespace base
diff --git a/ipc/chromium/src/base/time_win.cc b/ipc/chromium/src/base/time_win.cc
new file mode 100644
index 0000000000..d39416cd6d
--- /dev/null
+++ b/ipc/chromium/src/base/time_win.cc
@@ -0,0 +1,263 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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.
+
+// Windows Timer Primer
+//
+// A good article: http://www.ddj.com/windows/184416651
+// A good mozilla bug: http://bugzilla.mozilla.org/show_bug.cgi?id=363258
+//
+// The default windows timer, GetSystemTimeAsFileTime is not very precise.
+// It is only good to ~15.5ms.
+//
+// QueryPerformanceCounter is the logical choice for a high-precision timer.
+// However, it is known to be buggy on some hardware. Specifically, it can
+// sometimes "jump". On laptops, QPC can also be very expensive to call.
+// It's 3-4x slower than timeGetTime() on desktops, but can be 10x slower
+// on laptops. A unittest exists which will show the relative cost of various
+// timers on any system.
+//
+// The next logical choice is timeGetTime(). timeGetTime has a precision of
+// 1ms, but only if you call APIs (timeBeginPeriod()) which affect all other
+// applications on the system. By default, precision is only 15.5ms.
+// Unfortunately, we don't want to call timeBeginPeriod because we don't
+// want to affect other applications. Further, on mobile platforms, use of
+// faster multimedia timers can hurt battery life. See the intel
+// article about this here:
+// http://softwarecommunity.intel.com/articles/eng/1086.htm
+//
+// To work around all this, we're going to generally use timeGetTime(). We
+// will only increase the system-wide timer if we're not running on battery
+// power. Using timeBeginPeriod(1) is a requirement in order to make our
+// message loop waits have the same resolution that our time measurements
+// do. Otherwise, WaitForSingleObject(..., 1) will no less than 15ms when
+// there is nothing else to waken the Wait.
+
+#include "base/time.h"
+
+#ifndef __MINGW32__
+# pragma comment(lib, "winmm.lib")
+#endif
+#include <windows.h>
+#include <mmsystem.h>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "mozilla/Casting.h"
+#include "mozilla/StaticMutex.h"
+
+using base::Time;
+using base::TimeDelta;
+using base::TimeTicks;
+using mozilla::BitwiseCast;
+
+namespace {
+
+// From MSDN, FILETIME "Contains a 64-bit value representing the number of
+// 100-nanosecond intervals since January 1, 1601 (UTC)."
+int64_t FileTimeToMicroseconds(const FILETIME& ft) {
+ // Need to BitwiseCast to fix alignment, then divide by 10 to convert
+ // 100-nanoseconds to milliseconds. This only works on little-endian
+ // machines.
+ return BitwiseCast<int64_t>(ft) / 10;
+}
+
+void MicrosecondsToFileTime(int64_t us, FILETIME* ft) {
+ DCHECK(us >= 0) << "Time is less than 0, negative values are not "
+ "representable in FILETIME";
+
+ // Multiply by 10 to convert milliseconds to 100-nanoseconds. BitwiseCast will
+ // handle alignment problems. This only works on little-endian machines.
+ *ft = BitwiseCast<FILETIME>(us * 10);
+}
+
+int64_t CurrentWallclockMicroseconds() {
+ FILETIME ft;
+ ::GetSystemTimeAsFileTime(&ft);
+ return FileTimeToMicroseconds(ft);
+}
+
+// Time between resampling the un-granular clock for this API. 60 seconds.
+const int kMaxMillisecondsToAvoidDrift = 60 * Time::kMillisecondsPerSecond;
+
+int64_t initial_time = 0;
+TimeTicks initial_ticks;
+
+void InitializeClock() {
+ initial_ticks = TimeTicks::Now();
+ initial_time = CurrentWallclockMicroseconds();
+}
+
+} // namespace
+
+// Time -----------------------------------------------------------------------
+
+// The internal representation of Time uses FILETIME, whose epoch is 1601-01-01
+// 00:00:00 UTC. ((1970-1601)*365+89)*24*60*60*1000*1000, where 89 is the
+// number of leap year days between 1601 and 1970: (1970-1601)/4 excluding
+// 1700, 1800, and 1900.
+// static
+const int64_t Time::kTimeTToMicrosecondsOffset = GG_INT64_C(11644473600000000);
+
+// static
+Time Time::Now() {
+ if (initial_time == 0) InitializeClock();
+
+ // We implement time using the high-resolution timers so that we can get
+ // timeouts which are smaller than 10-15ms. If we just used
+ // CurrentWallclockMicroseconds(), we'd have the less-granular timer.
+ //
+ // To make this work, we initialize the clock (initial_time) and the
+ // counter (initial_ctr). To compute the initial time, we can check
+ // the number of ticks that have elapsed, and compute the delta.
+ //
+ // To avoid any drift, we periodically resync the counters to the system
+ // clock.
+ while (true) {
+ TimeTicks ticks = TimeTicks::Now();
+
+ // Calculate the time elapsed since we started our timer
+ TimeDelta elapsed = ticks - initial_ticks;
+
+ // Check if enough time has elapsed that we need to resync the clock.
+ if (elapsed.InMilliseconds() > kMaxMillisecondsToAvoidDrift) {
+ InitializeClock();
+ continue;
+ }
+
+ return Time(elapsed + Time(initial_time));
+ }
+}
+
+// static
+Time Time::NowFromSystemTime() {
+ // Force resync.
+ InitializeClock();
+ return Time(initial_time);
+}
+
+// static
+Time Time::FromExploded(bool is_local, const Exploded& exploded) {
+ // Create the system struct representing our exploded time. It will either be
+ // in local time or UTC.
+ SYSTEMTIME st;
+ st.wYear = exploded.year;
+ st.wMonth = exploded.month;
+ st.wDayOfWeek = exploded.day_of_week;
+ st.wDay = exploded.day_of_month;
+ st.wHour = exploded.hour;
+ st.wMinute = exploded.minute;
+ st.wSecond = exploded.second;
+ st.wMilliseconds = exploded.millisecond;
+
+ // Convert to FILETIME.
+ FILETIME ft;
+ if (!SystemTimeToFileTime(&st, &ft)) {
+ NOTREACHED() << "Unable to convert time";
+ return Time(0);
+ }
+
+ // Ensure that it's in UTC.
+ if (is_local) {
+ FILETIME utc_ft;
+ LocalFileTimeToFileTime(&ft, &utc_ft);
+ return Time(FileTimeToMicroseconds(utc_ft));
+ }
+ return Time(FileTimeToMicroseconds(ft));
+}
+
+void Time::Explode(bool is_local, Exploded* exploded) const {
+ // FILETIME in UTC.
+ FILETIME utc_ft;
+ MicrosecondsToFileTime(us_, &utc_ft);
+
+ // FILETIME in local time if necessary.
+ BOOL success = TRUE;
+ FILETIME ft;
+ if (is_local)
+ success = FileTimeToLocalFileTime(&utc_ft, &ft);
+ else
+ ft = utc_ft;
+
+ // FILETIME in SYSTEMTIME (exploded).
+ SYSTEMTIME st;
+ if (!success || !FileTimeToSystemTime(&ft, &st)) {
+ NOTREACHED() << "Unable to convert time, don't know why";
+ ZeroMemory(exploded, sizeof(*exploded));
+ return;
+ }
+
+ exploded->year = st.wYear;
+ exploded->month = st.wMonth;
+ exploded->day_of_week = st.wDayOfWeek;
+ exploded->day_of_month = st.wDay;
+ exploded->hour = st.wHour;
+ exploded->minute = st.wMinute;
+ exploded->second = st.wSecond;
+ exploded->millisecond = st.wMilliseconds;
+}
+
+// TimeTicks ------------------------------------------------------------------
+namespace {
+
+// We define a wrapper to adapt between the __stdcall and __cdecl call of the
+// mock function, and to avoid a static constructor. Assigning an import to a
+// function pointer directly would require setup code to fetch from the IAT.
+DWORD timeGetTimeWrapper() { return timeGetTime(); }
+
+DWORD (*tick_function)(void) = &timeGetTimeWrapper;
+
+// This setup is a little gross: the `now` instance lives until libxul is
+// unloaded, but leak checking runs prior to that, and would see a Mutex
+// instance contained in NowSingleton as still live. Said instance would
+// be reported as a leak...but it's not, really. To avoid that, we need
+// to use StaticMutex (which is not leak-checked), but StaticMutex can't
+// be a member variable. So we have to have this separate static variable.
+static mozilla::StaticMutex sNowSingletonLock;
+
+// We use timeGetTime() to implement TimeTicks::Now(). This can be problematic
+// because it returns the number of milliseconds since Windows has started,
+// which will roll over the 32-bit value every ~49 days. We try to track
+// rollover ourselves, which works if TimeTicks::Now() is called at least every
+// 49 days.
+class NowSingleton {
+ public:
+ TimeDelta Now() {
+ mozilla::StaticMutexAutoLock locked(sNowSingletonLock);
+ // We should hold the lock while calling tick_function to make sure that
+ // we keep our last_seen_ stay correctly in sync.
+ DWORD now = tick_function();
+ if (now < last_seen_)
+ rollover_ +=
+ TimeDelta::FromMilliseconds(GG_LONGLONG(0x100000000)); // ~49.7 days.
+ last_seen_ = now;
+ return TimeDelta::FromMilliseconds(now) + rollover_;
+ }
+
+ static NowSingleton& instance() {
+ static NowSingleton now;
+ return now;
+ }
+
+ private:
+ explicit NowSingleton()
+ : rollover_(TimeDelta::FromMilliseconds(0)), last_seen_(0) {}
+ ~NowSingleton() = default;
+
+ TimeDelta rollover_ MOZ_GUARDED_BY(
+ sNowSingletonLock); // Accumulation of time lost due to rollover.
+ DWORD last_seen_
+ MOZ_GUARDED_BY(sNowSingletonLock); // The last timeGetTime value we saw,
+ // to detect rollover.
+
+ DISALLOW_COPY_AND_ASSIGN(NowSingleton);
+};
+
+} // namespace
+
+// static
+TimeTicks TimeTicks::Now() {
+ return TimeTicks() + NowSingleton::instance().Now();
+}
diff --git a/ipc/chromium/src/base/timer.cc b/ipc/chromium/src/base/timer.cc
new file mode 100644
index 0000000000..b2d880797a
--- /dev/null
+++ b/ipc/chromium/src/base/timer.cc
@@ -0,0 +1,31 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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 "base/timer.h"
+
+#include "base/message_loop.h"
+
+namespace base {
+
+void BaseTimer_Helper::OrphanDelayedTask() {
+ if (delayed_task_) {
+ delayed_task_->timer_ = nullptr;
+ delayed_task_ = nullptr;
+ }
+}
+
+void BaseTimer_Helper::InitiateDelayedTask(TimerTask* timer_task) {
+ OrphanDelayedTask();
+
+ delayed_task_ = timer_task;
+ delayed_task_->timer_ = this;
+ RefPtr<TimerTask> addrefedTask = timer_task;
+ MessageLoop::current()->PostDelayedTask(
+ addrefedTask.forget(),
+ static_cast<int>(timer_task->delay_.InMilliseconds()));
+}
+
+} // namespace base
diff --git a/ipc/chromium/src/base/timer.h b/ipc/chromium/src/base/timer.h
new file mode 100644
index 0000000000..eceea8d23b
--- /dev/null
+++ b/ipc/chromium/src/base/timer.h
@@ -0,0 +1,261 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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.
+
+// OneShotTimer and RepeatingTimer provide a simple timer API. As the names
+// suggest, OneShotTimer calls you back once after a time delay expires.
+// RepeatingTimer on the other hand calls you back periodically with the
+// prescribed time interval.
+//
+// OneShotTimer and RepeatingTimer both cancel the timer when they go out of
+// scope, which makes it easy to ensure that you do not get called when your
+// object has gone out of scope. Just instantiate a OneShotTimer or
+// RepeatingTimer as a member variable of the class for which you wish to
+// receive timer events.
+//
+// Sample RepeatingTimer usage:
+//
+// class MyClass {
+// public:
+// void StartDoingStuff() {
+// timer_.Start(TimeDelta::FromSeconds(1), this, &MyClass::DoStuff);
+// }
+// void StopDoingStuff() {
+// timer_.Stop();
+// }
+// private:
+// void DoStuff() {
+// // This method is called every second to do stuff.
+// ...
+// }
+// base::RepeatingTimer<MyClass> timer_;
+// };
+//
+// Both OneShotTimer and RepeatingTimer also support a Reset method, which
+// allows you to easily defer the timer event until the timer delay passes once
+// again. So, in the above example, if 0.5 seconds have already passed,
+// calling Reset on timer_ would postpone DoStuff by another 1 second. In
+// other words, Reset is shorthand for calling Stop and then Start again with
+// the same arguments.
+
+#ifndef BASE_TIMER_H_
+#define BASE_TIMER_H_
+
+// IMPORTANT: If you change timer code, make sure that all tests (including
+// disabled ones) from timer_unittests.cc pass locally. Some are disabled
+// because they're flaky on the buildbot, but when you run them locally you
+// should be able to tell the difference.
+
+#include "base/logging.h"
+#include "base/task.h"
+#include "base/time.h"
+
+class MessageLoop;
+
+namespace base {
+
+//-----------------------------------------------------------------------------
+// This class is an implementation detail of OneShotTimer and RepeatingTimer.
+// Please do not use this class directly.
+//
+// This class exists to share code between BaseTimer<T> template instantiations.
+//
+class BaseTimer_Helper {
+ public:
+ // Stops the timer.
+ ~BaseTimer_Helper() { OrphanDelayedTask(); }
+
+ // Returns true if the timer is running (i.e., not stopped).
+ bool IsRunning() const { return !!delayed_task_; }
+
+ // Returns the current delay for this timer. May only call this method when
+ // the timer is running!
+ TimeDelta GetCurrentDelay() const {
+ DCHECK(IsRunning());
+ return delayed_task_->delay_;
+ }
+
+ protected:
+ BaseTimer_Helper() {}
+
+ // We have access to the timer_ member so we can orphan this task.
+ class TimerTask : public mozilla::Runnable {
+ public:
+ explicit TimerTask(TimeDelta delay)
+ : mozilla::Runnable("base::BaseTimer_Helper::TimerTask"),
+ delay_(delay) {
+ // timer_ is set in InitiateDelayedTask.
+ }
+ virtual ~TimerTask() {}
+ BaseTimer_Helper* timer_;
+ TimeDelta delay_;
+ };
+
+ // Used to orphan delayed_task_ so that when it runs it does nothing.
+ void OrphanDelayedTask();
+
+ // Used to initiated a new delayed task. This has the side-effect of
+ // orphaning delayed_task_ if it is non-null.
+ void InitiateDelayedTask(TimerTask* timer_task);
+
+ RefPtr<TimerTask> delayed_task_;
+
+ DISALLOW_COPY_AND_ASSIGN(BaseTimer_Helper);
+};
+
+//-----------------------------------------------------------------------------
+// This class is an implementation detail of OneShotTimer and RepeatingTimer.
+// Please do not use this class directly.
+template <class Receiver, bool kIsRepeating>
+class BaseTimer : public BaseTimer_Helper {
+ public:
+ typedef void (Receiver::*ReceiverMethod)();
+
+ // Call this method to start the timer. It is an error to call this method
+ // while the timer is already running.
+ void Start(TimeDelta delay, Receiver* receiver, ReceiverMethod method) {
+ DCHECK(!IsRunning());
+ InitiateDelayedTask(new TimerTask(delay, receiver, method));
+ }
+
+ // Call this method to stop the timer. It is a no-op if the timer is not
+ // running.
+ void Stop() { OrphanDelayedTask(); }
+
+ // Call this method to reset the timer delay of an already running timer.
+ void Reset() {
+ DCHECK(IsRunning());
+ InitiateDelayedTask(static_cast<TimerTask*>(delayed_task_.get())->Clone());
+ }
+
+ private:
+ typedef BaseTimer<Receiver, kIsRepeating> SelfType;
+
+ class TimerTask : public BaseTimer_Helper::TimerTask {
+ public:
+ TimerTask(TimeDelta delay, Receiver* receiver, ReceiverMethod method)
+ : BaseTimer_Helper::TimerTask(delay),
+ receiver_(receiver),
+ method_(method) {}
+
+ virtual ~TimerTask() {
+ // This task may be getting cleared because the MessageLoop has been
+ // destructed. If so, don't leave the Timer with a dangling pointer
+ // to this now-defunct task.
+ ClearBaseTimer();
+ }
+
+ NS_IMETHOD Run() override {
+ if (!timer_) // timer_ is null if we were orphaned.
+ return NS_OK;
+ if (kIsRepeating)
+ ResetBaseTimer();
+ else
+ ClearBaseTimer();
+ DispatchToMethod(receiver_, method_, Tuple0());
+ return NS_OK;
+ }
+
+ TimerTask* Clone() const {
+ return new TimerTask(delay_, receiver_, method_);
+ }
+
+ private:
+ // Inform the Base that the timer is no longer active.
+ void ClearBaseTimer() {
+ if (timer_) {
+ SelfType* self = static_cast<SelfType*>(timer_);
+ // It is possible that the Timer has already been reset, and that this
+ // Task is old. So, if the Timer points to a different task, assume
+ // that the Timer has already taken care of properly setting the task.
+ if (self->delayed_task_ == this) self->delayed_task_ = nullptr;
+ // By now the delayed_task_ in the Timer does not point to us anymore.
+ // We should reset our own timer_ because the Timer can not do this
+ // for us in its destructor.
+ timer_ = NULL;
+ }
+ }
+
+ // Inform the Base that we're resetting the timer.
+ void ResetBaseTimer() {
+ DCHECK(timer_);
+ DCHECK(kIsRepeating);
+ SelfType* self = static_cast<SelfType*>(timer_);
+ self->Reset();
+ }
+
+ Receiver* receiver_;
+ ReceiverMethod method_;
+ };
+};
+
+//-----------------------------------------------------------------------------
+// A simple, one-shot timer. See usage notes at the top of the file.
+template <class Receiver>
+class OneShotTimer : public BaseTimer<Receiver, false> {};
+
+//-----------------------------------------------------------------------------
+// A simple, repeating timer. See usage notes at the top of the file.
+template <class Receiver>
+class RepeatingTimer : public BaseTimer<Receiver, true> {};
+
+//-----------------------------------------------------------------------------
+// A Delay timer is like The Button from Lost. Once started, you have to keep
+// calling Reset otherwise it will call the given method in the MessageLoop
+// thread.
+//
+// Once created, it is inactive until Reset is called. Once |delay| seconds have
+// passed since the last call to Reset, the callback is made. Once the callback
+// has been made, it's inactive until Reset is called again.
+//
+// If destroyed, the timeout is canceled and will not occur even if already
+// inflight.
+template <class Receiver>
+class DelayTimer {
+ public:
+ typedef void (Receiver::*ReceiverMethod)();
+
+ DelayTimer(TimeDelta delay, Receiver* receiver, ReceiverMethod method)
+ : receiver_(receiver), method_(method), delay_(delay) {}
+
+ void Reset() { DelayFor(delay_); }
+
+ private:
+ void DelayFor(TimeDelta delay) {
+ trigger_time_ = Time::Now() + delay;
+
+ // If we already have a timer that will expire at or before the given delay,
+ // then we have nothing more to do now.
+ if (timer_.IsRunning() && timer_.GetCurrentDelay() <= delay) return;
+
+ // The timer isn't running, or will expire too late, so restart it.
+ timer_.Stop();
+ timer_.Start(delay, this, &DelayTimer<Receiver>::Check);
+ }
+
+ void Check() {
+ if (trigger_time_.is_null()) return;
+
+ // If we have not waited long enough, then wait some more.
+ const Time now = Time::Now();
+ if (now < trigger_time_) {
+ DelayFor(trigger_time_ - now);
+ return;
+ }
+
+ (receiver_->*method_)();
+ }
+
+ Receiver* const receiver_;
+ const ReceiverMethod method_;
+ const TimeDelta delay_;
+
+ OneShotTimer<DelayTimer<Receiver> > timer_;
+ Time trigger_time_;
+};
+
+} // namespace base
+
+#endif // BASE_TIMER_H_
diff --git a/ipc/chromium/src/base/tuple.h b/ipc/chromium/src/base/tuple.h
new file mode 100644
index 0000000000..62655784d4
--- /dev/null
+++ b/ipc/chromium/src/base/tuple.h
@@ -0,0 +1,838 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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__
+
+// 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;
+};
+
+// 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;
+};
+
+template <class A>
+struct Tuple1 {
+ public:
+ typedef A TypeA;
+ typedef Tuple1<typename TupleTraits<A>::ValueType> ValueTuple;
+ typedef Tuple1<typename TupleTraits<A>::RefType> RefTuple;
+
+ Tuple1() {}
+ explicit Tuple1(typename TupleTraits<A>::ParamType aA) : a(aA) {}
+
+ A a;
+};
+
+template <class A, class B>
+struct Tuple2 {
+ public:
+ typedef A TypeA;
+ typedef B TypeB;
+ typedef Tuple2<typename TupleTraits<A>::ValueType,
+ typename TupleTraits<B>::ValueType>
+ ValueTuple;
+ typedef Tuple2<typename TupleTraits<A>::RefType,
+ typename TupleTraits<B>::RefType>
+ RefTuple;
+
+ Tuple2() {}
+ Tuple2(typename TupleTraits<A>::ParamType aA,
+ typename TupleTraits<B>::ParamType aB)
+ : a(aA), b(aB) {}
+
+ A a;
+ B b;
+};
+
+template <class A, class B, class C>
+struct Tuple3 {
+ public:
+ typedef A TypeA;
+ typedef B TypeB;
+ typedef C TypeC;
+ 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;
+
+ Tuple3() {}
+ Tuple3(typename TupleTraits<A>::ParamType aA,
+ typename TupleTraits<B>::ParamType aB,
+ typename TupleTraits<C>::ParamType aC)
+ : a(aA), b(aB), c(aC) {}
+
+ 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;
+ 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;
+
+ Tuple4() {}
+ Tuple4(typename TupleTraits<A>::ParamType aA,
+ typename TupleTraits<B>::ParamType aB,
+ typename TupleTraits<C>::ParamType aC,
+ typename TupleTraits<D>::ParamType aD)
+ : a(aA), b(aB), c(aC), d(aD) {}
+
+ 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;
+ 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;
+
+ Tuple5() {}
+ Tuple5(typename TupleTraits<A>::ParamType aA,
+ typename TupleTraits<B>::ParamType aB,
+ typename TupleTraits<C>::ParamType aC,
+ typename TupleTraits<D>::ParamType aD,
+ typename TupleTraits<E>::ParamType aE)
+ : a(aA), b(aB), c(aC), d(aD), e(aE) {}
+
+ 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;
+ 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;
+
+ Tuple6() {}
+ Tuple6(typename TupleTraits<A>::ParamType aA,
+ typename TupleTraits<B>::ParamType aB,
+ typename TupleTraits<C>::ParamType aC,
+ typename TupleTraits<D>::ParamType aD,
+ typename TupleTraits<E>::ParamType aE,
+ typename TupleTraits<F>::ParamType aF)
+ : a(aA), b(aB), c(aC), d(aD), e(aE), f(aF) {}
+
+ 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;
+ 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;
+
+ Tuple7() {}
+ Tuple7(typename TupleTraits<A>::ParamType aA,
+ typename TupleTraits<B>::ParamType aB,
+ typename TupleTraits<C>::ParamType aC,
+ typename TupleTraits<D>::ParamType aD,
+ typename TupleTraits<E>::ParamType aE,
+ typename TupleTraits<F>::ParamType aF,
+ typename TupleTraits<G>::ParamType aG)
+ : a(aA), b(aB), c(aC), d(aD), e(aE), f(aF), g(aG) {}
+
+ A a;
+ B b;
+ C c;
+ D d;
+ E e;
+ F f;
+ G g;
+};
+
+// Tuple creators -------------------------------------------------------------
+//
+// Helper functions for constructing tuples while inferring the template
+// argument types.
+
+namespace base {
+
+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);
+}
+
+} // end namespace base
+
+// 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);
+}
+
+// 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);
+}
+
+// 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);
+}
+
+// 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/ipc/chromium/src/base/waitable_event.h b/ipc/chromium/src/base/waitable_event.h
new file mode 100644
index 0000000000..7c85435804
--- /dev/null
+++ b/ipc/chromium/src/base/waitable_event.h
@@ -0,0 +1,173 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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_WAITABLE_EVENT_H_
+#define BASE_WAITABLE_EVENT_H_
+
+#include "base/basictypes.h"
+
+#if defined(XP_WIN)
+# include <windows.h>
+#endif
+
+#if defined(XP_UNIX)
+# include <list>
+# include <utility>
+# include "base/condition_variable.h"
+# include "base/lock.h"
+# include "nsISupportsImpl.h"
+#endif
+
+#include "base/message_loop.h"
+
+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 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);
+
+ ~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(XP_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;
+ };
+
+ private:
+ friend class WaitableEventWatcher;
+
+#if defined(XP_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 final {
+ public:
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WaitableEventKernel)
+ WaitableEventKernel(bool manual_reset, bool initially_signaled)
+ : manual_reset_(manual_reset), signaled_(initially_signaled) {}
+
+ bool Dequeue(Waiter* waiter, void* tag);
+
+ Lock lock_;
+ const bool manual_reset_;
+ bool signaled_;
+ std::list<Waiter*> waiters_;
+
+ protected:
+ ~WaitableEventKernel() {}
+ };
+
+ RefPtr<WaitableEventKernel> kernel_;
+
+ bool SignalAll();
+ bool SignalOne();
+ void Enqueue(Waiter* waiter);
+
+ // 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.
+ typedef std::pair<WaitableEvent*, size_t> WaiterAndIndex;
+ static size_t EnqueueMany(WaiterAndIndex* waitables, size_t count,
+ Waiter* waiter);
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(WaitableEvent);
+};
+
+} // namespace base
+
+#endif // BASE_WAITABLE_EVENT_H_
diff --git a/ipc/chromium/src/base/waitable_event_posix.cc b/ipc/chromium/src/base/waitable_event_posix.cc
new file mode 100644
index 0000000000..ad63876016
--- /dev/null
+++ b/ipc/chromium/src/base/waitable_event_posix.cc
@@ -0,0 +1,362 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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 "base/waitable_event.h"
+
+#include "base/condition_variable.h"
+#include "base/lock.h"
+#include "base/message_loop.h"
+
+// -----------------------------------------------------------------------------
+// A WaitableEvent on POSIX is implemented as a wait-list. Currently we don't
+// support cross-process events (where one process can signal an event which
+// others are waiting on). Because of this, we can avoid having one thread per
+// listener in several cases.
+//
+// The WaitableEvent maintains a list of waiters, protected by a lock. Each
+// waiter is either an async wait, in which case we have a Task and the
+// MessageLoop to run it on, or a blocking wait, in which case we have the
+// condition variable to signal.
+//
+// Waiting involves grabbing the lock and adding oneself to the wait list. Async
+// waits can be canceled, which means grabbing the lock and removing oneself
+// from the list.
+//
+// Waiting on multiple events is handled by adding a single, synchronous wait to
+// the wait-list of many events. An event passes a pointer to itself when
+// firing a waiter and so we can store that pointer to find out which event
+// triggered.
+// -----------------------------------------------------------------------------
+
+namespace base {
+
+// -----------------------------------------------------------------------------
+// This is just an abstract base class for waking the two types of waiters
+// -----------------------------------------------------------------------------
+WaitableEvent::WaitableEvent(bool manual_reset, bool initially_signaled)
+ : kernel_(new WaitableEventKernel(manual_reset, initially_signaled)) {}
+
+WaitableEvent::~WaitableEvent() {}
+
+void WaitableEvent::Reset() {
+ AutoLock locked(kernel_->lock_);
+ kernel_->signaled_ = false;
+}
+
+void WaitableEvent::Signal() {
+ AutoLock locked(kernel_->lock_);
+
+ if (kernel_->signaled_) return;
+
+ if (kernel_->manual_reset_) {
+ SignalAll();
+ kernel_->signaled_ = true;
+ } else {
+ // In the case of auto reset, if no waiters were woken, we remain
+ // signaled.
+ if (!SignalOne()) kernel_->signaled_ = true;
+ }
+}
+
+bool WaitableEvent::IsSignaled() {
+ AutoLock locked(kernel_->lock_);
+
+ const bool result = kernel_->signaled_;
+ if (result && !kernel_->manual_reset_) kernel_->signaled_ = false;
+ return result;
+}
+
+// -----------------------------------------------------------------------------
+// Synchronous waits
+
+// -----------------------------------------------------------------------------
+// This is an synchronous waiter. The thread is waiting on the given condition
+// variable and the fired flag in this object.
+// -----------------------------------------------------------------------------
+class SyncWaiter : public WaitableEvent::Waiter {
+ public:
+ SyncWaiter(ConditionVariable* cv, Lock* lock)
+ : fired_(false), cv_(cv), lock_(lock), signaling_event_(NULL) {}
+
+ bool Fire(WaitableEvent* signaling_event) override {
+ lock_->Acquire();
+ const bool previous_value = fired_;
+ fired_ = true;
+ if (!previous_value) signaling_event_ = signaling_event;
+ lock_->Release();
+
+ if (previous_value) return false;
+
+ cv_->Broadcast();
+
+ // SyncWaiters are stack allocated on the stack of the blocking thread.
+ return true;
+ }
+
+ WaitableEvent* signaled_event() const { return signaling_event_; }
+
+ // ---------------------------------------------------------------------------
+ // These waiters are always stack allocated and don't delete themselves. Thus
+ // there's no problem and the ABA tag is the same as the object pointer.
+ // ---------------------------------------------------------------------------
+ bool Compare(void* tag) override { return this == tag; }
+
+ // ---------------------------------------------------------------------------
+ // Called with lock held.
+ // ---------------------------------------------------------------------------
+ bool fired() const { return fired_; }
+
+ // ---------------------------------------------------------------------------
+ // During a TimedWait, we need a way to make sure that an auto-reset
+ // WaitableEvent doesn't think that this event has been signaled between
+ // unlocking it and removing it from the wait-list. Called with lock held.
+ // ---------------------------------------------------------------------------
+ void Disable() { fired_ = true; }
+
+ private:
+ bool fired_;
+ ConditionVariable* const cv_;
+ Lock* const lock_;
+ WaitableEvent* signaling_event_; // The WaitableEvent which woke us
+};
+
+bool WaitableEvent::TimedWait(const TimeDelta& max_time) {
+ const TimeTicks end_time(TimeTicks::Now() + max_time);
+ const bool finite_time = max_time.ToInternalValue() >= 0;
+
+ kernel_->lock_.Acquire();
+ if (kernel_->signaled_) {
+ if (!kernel_->manual_reset_) {
+ // In this case we were signaled when we had no waiters. Now that
+ // someone has waited upon us, we can automatically reset.
+ kernel_->signaled_ = false;
+ }
+
+ kernel_->lock_.Release();
+ return true;
+ }
+
+ Lock lock;
+ lock.Acquire();
+ ConditionVariable cv(&lock);
+ SyncWaiter sw(&cv, &lock);
+
+ Enqueue(&sw);
+ kernel_->lock_.Release();
+ // We are violating locking order here by holding the SyncWaiter lock but not
+ // the WaitableEvent lock. However, this is safe because we don't lock @lock_
+ // again before unlocking it.
+
+ for (;;) {
+ const TimeTicks current_time(TimeTicks::Now());
+
+ if (sw.fired() || (finite_time && current_time >= end_time)) {
+ const bool return_value = sw.fired();
+
+ // We can't acquire @lock_ before releasing @lock (because of locking
+ // order), however, inbetween the two a signal could be fired and @sw
+ // would accept it, however we will still return false, so the signal
+ // would be lost on an auto-reset WaitableEvent. Thus we call Disable
+ // which makes sw::Fire return false.
+ sw.Disable();
+ lock.Release();
+
+ kernel_->lock_.Acquire();
+ kernel_->Dequeue(&sw, &sw);
+ kernel_->lock_.Release();
+
+ return return_value;
+ }
+
+ if (finite_time) {
+ const TimeDelta max_wait(end_time - current_time);
+ cv.TimedWait(max_wait);
+ } else {
+ cv.Wait();
+ }
+ }
+}
+
+bool WaitableEvent::Wait() { return TimedWait(TimeDelta::FromSeconds(-1)); }
+
+// -----------------------------------------------------------------------------
+
+// -----------------------------------------------------------------------------
+// Synchronous waiting on multiple objects.
+
+static bool // StrictWeakOrdering
+cmp_fst_addr(const std::pair<WaitableEvent*, unsigned>& a,
+ const std::pair<WaitableEvent*, unsigned>& b) {
+ return a.first < b.first;
+}
+
+// static
+size_t WaitableEvent::WaitMany(WaitableEvent** raw_waitables, size_t count) {
+ DCHECK(count) << "Cannot wait on no events";
+
+ // We need to acquire the locks in a globally consistent order. Thus we sort
+ // the array of waitables by address. We actually sort a pairs so that we can
+ // map back to the original index values later.
+ std::vector<std::pair<WaitableEvent*, size_t> > waitables;
+ waitables.reserve(count);
+ for (size_t i = 0; i < count; ++i)
+ waitables.push_back(std::make_pair(raw_waitables[i], i));
+
+ DCHECK_EQ(count, waitables.size());
+
+ sort(waitables.begin(), waitables.end(), cmp_fst_addr);
+
+ // The set of waitables must be distinct. Since we have just sorted by
+ // address, we can check this cheaply by comparing pairs of consecutive
+ // elements.
+ for (size_t i = 0; i < waitables.size() - 1; ++i) {
+ DCHECK(waitables[i].first != waitables[i + 1].first);
+ }
+
+ Lock lock;
+ ConditionVariable cv(&lock);
+ SyncWaiter sw(&cv, &lock);
+
+ const size_t r = EnqueueMany(&waitables[0], count, &sw);
+ if (r) {
+ // One of the events is already signaled. The SyncWaiter has not been
+ // enqueued anywhere. EnqueueMany returns the count of remaining waitables
+ // when the signaled one was seen, so the index of the signaled event is
+ // @count - @r.
+ return waitables[count - r].second;
+ }
+
+ // At this point, we hold the locks on all the WaitableEvents and we have
+ // enqueued our waiter in them all.
+ lock.Acquire();
+ // Release the WaitableEvent locks in the reverse order
+ for (size_t i = 0; i < count; ++i) {
+ waitables[count - (1 + i)].first->kernel_->lock_.Release();
+ }
+
+ for (;;) {
+ if (sw.fired()) break;
+
+ cv.Wait();
+ }
+ lock.Release();
+
+ // The address of the WaitableEvent which fired is stored in the SyncWaiter.
+ WaitableEvent* const signaled_event = sw.signaled_event();
+ // This will store the index of the raw_waitables which fired.
+ size_t signaled_index = 0;
+
+ // Take the locks of each WaitableEvent in turn (except the signaled one) and
+ // remove our SyncWaiter from the wait-list
+ for (size_t i = 0; i < count; ++i) {
+ if (raw_waitables[i] != signaled_event) {
+ raw_waitables[i]->kernel_->lock_.Acquire();
+ // There's no possible ABA issue with the address of the SyncWaiter here
+ // because it lives on the stack. Thus the tag value is just the pointer
+ // value again.
+ raw_waitables[i]->kernel_->Dequeue(&sw, &sw);
+ raw_waitables[i]->kernel_->lock_.Release();
+ } else {
+ signaled_index = i;
+ }
+ }
+
+ return signaled_index;
+}
+
+// -----------------------------------------------------------------------------
+// If return value == 0:
+// The locks of the WaitableEvents have been taken in order and the Waiter has
+// been enqueued in the wait-list of each. None of the WaitableEvents are
+// currently signaled
+// else:
+// None of the WaitableEvent locks are held. The Waiter has not been enqueued
+// in any of them and the return value is the index of the first WaitableEvent
+// which was signaled, from the end of the array.
+// -----------------------------------------------------------------------------
+// static
+size_t WaitableEvent::EnqueueMany(std::pair<WaitableEvent*, size_t>* waitables,
+ size_t count, Waiter* waiter) {
+ if (!count) return 0;
+
+ waitables[0].first->kernel_->lock_.Acquire();
+ if (waitables[0].first->kernel_->signaled_) {
+ if (!waitables[0].first->kernel_->manual_reset_)
+ waitables[0].first->kernel_->signaled_ = false;
+ waitables[0].first->kernel_->lock_.Release();
+ return count;
+ }
+
+ const size_t r = EnqueueMany(waitables + 1, count - 1, waiter);
+ if (r) {
+ waitables[0].first->kernel_->lock_.Release();
+ } else {
+ waitables[0].first->Enqueue(waiter);
+ }
+
+ return r;
+}
+
+// -----------------------------------------------------------------------------
+
+// -----------------------------------------------------------------------------
+// Private functions...
+
+// -----------------------------------------------------------------------------
+// Wake all waiting waiters. Called with lock held.
+// -----------------------------------------------------------------------------
+bool WaitableEvent::SignalAll() {
+ bool signaled_at_least_one = false;
+
+ for (std::list<Waiter*>::iterator i = kernel_->waiters_.begin();
+ i != kernel_->waiters_.end(); ++i) {
+ if ((*i)->Fire(this)) signaled_at_least_one = true;
+ }
+
+ kernel_->waiters_.clear();
+ return signaled_at_least_one;
+}
+
+// ---------------------------------------------------------------------------
+// Try to wake a single waiter. Return true if one was woken. Called with lock
+// held.
+// ---------------------------------------------------------------------------
+bool WaitableEvent::SignalOne() {
+ for (;;) {
+ if (kernel_->waiters_.empty()) return false;
+
+ const bool r = (*kernel_->waiters_.begin())->Fire(this);
+ kernel_->waiters_.pop_front();
+ if (r) return true;
+ }
+}
+
+// -----------------------------------------------------------------------------
+// Add a waiter to the list of those waiting. Called with lock held.
+// -----------------------------------------------------------------------------
+void WaitableEvent::Enqueue(Waiter* waiter) {
+ kernel_->waiters_.push_back(waiter);
+}
+
+// -----------------------------------------------------------------------------
+// Remove a waiter from the list of those waiting. Return true if the waiter was
+// actually removed. Called with lock held.
+// -----------------------------------------------------------------------------
+bool WaitableEvent::WaitableEventKernel::Dequeue(Waiter* waiter, void* tag) {
+ for (std::list<Waiter*>::iterator i = waiters_.begin(); i != waiters_.end();
+ ++i) {
+ if (*i == waiter && (*i)->Compare(tag)) {
+ waiters_.erase(i);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// -----------------------------------------------------------------------------
+
+} // namespace base
diff --git a/ipc/chromium/src/base/waitable_event_win.cc b/ipc/chromium/src/base/waitable_event_win.cc
new file mode 100644
index 0000000000..ca94c5cdd9
--- /dev/null
+++ b/ipc/chromium/src/base/waitable_event_win.cc
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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 "base/waitable_event.h"
+
+#include <math.h>
+#include <windows.h>
+
+#include "base/logging.h"
+#include "base/time.h"
+
+namespace base {
+
+WaitableEvent::WaitableEvent(bool manual_reset, bool signaled)
+ : handle_(CreateEvent(NULL, manual_reset, signaled, NULL)) {
+ // We're probably going to crash anyways if this is ever NULL, so we might as
+ // well make our stack reports more informative by crashing here.
+ CHECK(handle_);
+}
+
+WaitableEvent::~WaitableEvent() { CloseHandle(handle_); }
+
+void WaitableEvent::Reset() { ResetEvent(handle_); }
+
+void WaitableEvent::Signal() { SetEvent(handle_); }
+
+bool WaitableEvent::IsSignaled() {
+ return TimedWait(TimeDelta::FromMilliseconds(0));
+}
+
+bool WaitableEvent::Wait() {
+ DWORD result = WaitForSingleObject(handle_, INFINITE);
+ // It is most unexpected that this should ever fail. Help consumers learn
+ // about it if it should ever fail.
+ DCHECK(result == WAIT_OBJECT_0) << "WaitForSingleObject failed";
+ return result == WAIT_OBJECT_0;
+}
+
+bool WaitableEvent::TimedWait(const TimeDelta& max_time) {
+ DCHECK(max_time >= TimeDelta::FromMicroseconds(0));
+ // Be careful here. TimeDelta has a precision of microseconds, but this API
+ // is in milliseconds. If there are 5.5ms left, should the delay be 5 or 6?
+ // It should be 6 to avoid returning too early.
+ double timeout = ceil(max_time.InMillisecondsF());
+ DWORD result = WaitForSingleObject(handle_, static_cast<DWORD>(timeout));
+ switch (result) {
+ case WAIT_OBJECT_0:
+ return true;
+ case WAIT_TIMEOUT:
+ return false;
+ }
+ // It is most unexpected that this should ever fail. Help consumers learn
+ // about it if it should ever fail.
+ NOTREACHED() << "WaitForSingleObject failed";
+ return false;
+}
+
+// static
+size_t WaitableEvent::WaitMany(WaitableEvent** events, size_t count) {
+ HANDLE handles[MAXIMUM_WAIT_OBJECTS];
+ CHECK(count <= MAXIMUM_WAIT_OBJECTS)
+ << "Can only wait on " << MAXIMUM_WAIT_OBJECTS << " with WaitMany";
+
+ for (size_t i = 0; i < count; ++i) handles[i] = events[i]->handle();
+
+ DWORD result =
+ WaitForMultipleObjects(count, handles,
+ FALSE, // don't wait for all the objects
+ INFINITE); // no timeout
+ if (result >= WAIT_OBJECT_0 + count) {
+ NOTREACHED() << "WaitForMultipleObjects failed: " << GetLastError();
+ return 0;
+ }
+
+ return result - WAIT_OBJECT_0;
+}
+
+} // namespace base
diff --git a/ipc/chromium/src/base/win_util.cc b/ipc/chromium/src/base/win_util.cc
new file mode 100644
index 0000000000..611603f56e
--- /dev/null
+++ b/ipc/chromium/src/base/win_util.cc
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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 "base/win_util.h"
+
+#include <map>
+#include <sddl.h>
+
+#include "base/logging.h"
+#include "base/string_util.h"
+
+namespace win_util {
+
+std::wstring FormatMessage(unsigned messageid) {
+ wchar_t* string_buffer = NULL;
+ ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, messageid, 0,
+ reinterpret_cast<wchar_t*>(&string_buffer), 0, NULL);
+
+ std::wstring formatted_string;
+ if (string_buffer) {
+ formatted_string = string_buffer;
+ LocalFree(reinterpret_cast<HLOCAL>(string_buffer));
+ } else {
+ // The formating failed. simply convert the message value into a string.
+ SStringPrintf(&formatted_string, L"message number %d", messageid);
+ }
+ return formatted_string;
+}
+
+std::wstring FormatLastWin32Error() { return FormatMessage(GetLastError()); }
+
+} // namespace win_util
diff --git a/ipc/chromium/src/base/win_util.h b/ipc/chromium/src/base/win_util.h
new file mode 100644
index 0000000000..b37411f60d
--- /dev/null
+++ b/ipc/chromium/src/base/win_util.h
@@ -0,0 +1,22 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+// 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_WIN_UTIL_H__
+#define BASE_WIN_UTIL_H__
+
+#include <windows.h>
+#include <aclapi.h>
+
+#include <string>
+
+namespace win_util {
+
+// Uses the last Win32 error to generate a human readable message string.
+std::wstring FormatLastWin32Error();
+
+} // namespace win_util
+
+#endif // BASE_WIN_UTIL_H__