Bug 1337331 Part 1: Update security/sandbox/chromium/ to commit b169b9a1cc402573843e8c952af14c4e43487e91. r=jld, r=aklotz, r=jimm

Also inclues follow-up to remove mitigations that require Windows 10 SDK.

MozReview-Commit-ID: HwqM4noIHmy
This commit is contained in:
Bob Owen 2017-03-29 14:23:17 +01:00
parent 85b254f54b
commit 94bf554716
238 changed files with 12410 additions and 6514 deletions

View File

@ -1,25 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=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 http://mozilla.org/MPL/2.0/. */
#ifndef security_sandbox_MissingBasicTypes_h__
#define security_sandbox_MissingBasicTypes_h__
#include <stdint.h>
// These types are still used by the Chromium sandbox code. When referencing
// Chromium sandbox code from Gecko we can't use the normal base/basictypes.h as
// it clashes with the one from ipc/chromium/src/base/. These types have been
// removed from the one in ipc/chromium/src/base/.
typedef int8_t int8;
typedef uint8_t uint8;
typedef int16_t int16;
typedef uint16_t uint16;
typedef int32_t int32;
typedef uint32_t uint32;
typedef int64_t int64;
typedef uint64_t uint64;
#endif // security_sandbox_MissingBasicTypes_h__

View File

@ -0,0 +1,56 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=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 http://mozilla.org/MPL/2.0/. */
// This is a dummy version of Chromium source file base/debug/activity_tracker.h.
// To provide a class required in base/synchronization/lock_impl_win.cc
// ScopedLockAcquireActivity. We don't use activity tracking.
#ifndef BASE_DEBUG_ACTIVITY_TRACKER_H_
#define BASE_DEBUG_ACTIVITY_TRACKER_H_
#include "base/base_export.h"
#include "base/compiler_specific.h"
#include "base/macros.h"
namespace base {
class PlatformThreadHandle;
class WaitableEvent;
namespace internal {
class LockImpl;
}
namespace debug {
class BASE_EXPORT ScopedLockAcquireActivity
{
public:
ALWAYS_INLINE
explicit ScopedLockAcquireActivity(const base::internal::LockImpl* lock) {}
DISALLOW_COPY_AND_ASSIGN(ScopedLockAcquireActivity);
};
class BASE_EXPORT ScopedEventWaitActivity
{
public:
ALWAYS_INLINE
explicit ScopedEventWaitActivity(const base::WaitableEvent* event) {}
DISALLOW_COPY_AND_ASSIGN(ScopedEventWaitActivity);
};
class BASE_EXPORT ScopedThreadJoinActivity
{
public:
ALWAYS_INLINE
explicit ScopedThreadJoinActivity(const base::PlatformThreadHandle* thread) {}
DISALLOW_COPY_AND_ASSIGN(ScopedThreadJoinActivity);
};
} // namespace debug
} // namespace base
#endif // BASE_DEBUG_ACTIVITY_TRACKER_H_

View File

@ -0,0 +1,24 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=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 http://mozilla.org/MPL/2.0/. */
// This is a dummy version of Chromium source file base/debug/stack_trace.h.
// To provide a dummy class StackTrace required in base/win/scoped_handle.cc.
#ifndef BASE_DEBUG_STACK_TRACE_H_
#define BASE_DEBUG_STACK_TRACE_H_
namespace base {
namespace debug {
class BASE_EXPORT StackTrace {
public:
StackTrace() {};
};
} // namespace debug
} // namespace base
#endif // BASE_DEBUG_STACK_TRACE_H_

View File

@ -11,6 +11,8 @@
#ifndef BASE_FILE_VERSION_INFO_WIN_H_
#define BASE_FILE_VERSION_INFO_WIN_H_
#include "mozilla/Assertions.h"
struct tagVS_FIXEDFILEINFO;
typedef tagVS_FIXEDFILEINFO VS_FIXEDFILEINFO;
@ -21,9 +23,9 @@ class FilePath;
class FileVersionInfoWin {
public:
static FileVersionInfoWin*
CreateFileVersionInfo(const base::FilePath& file_path) { return nullptr; }
CreateFileVersionInfo(const base::FilePath& file_path) { MOZ_CRASH(); }
VS_FIXEDFILEINFO* fixed_file_info() { return nullptr; }
VS_FIXEDFILEINFO* fixed_file_info() { MOZ_CRASH(); }
};
#endif // BASE_FILE_VERSION_INFO_WIN_H_

View File

@ -8,9 +8,12 @@
#include "base/files/file_path.h"
#include "mozilla/Assertions.h"
namespace base {
FilePath::FilePath(FilePath::StringPieceType path) {
MOZ_CRASH();
}
FilePath::~FilePath() {

View File

@ -0,0 +1,11 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=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 http://mozilla.org/MPL/2.0/. */
// This is a cut down version of Chromium source file base/files/file_util.h
// This is included in base/memory/shared_memory.h, but it only actually
// requires the include for base/files/file_path.h.
#include "base/files/file_path.h"

View File

@ -4,6 +4,9 @@
* 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_GTEST_PROD_UTIL_H_
#define BASE_GTEST_PROD_UTIL_H_
#ifndef FRIEND_TEST
#define FRIEND_TEST(A, B)
#endif
@ -15,3 +18,5 @@
#ifndef FORWARD_DECLARE_TEST
#define FORWARD_DECLARE_TEST(test_case_name, test_name)
#endif
#endif // BASE_GTEST_PROD_UTIL_H_

View File

@ -28,6 +28,8 @@
#include <algorithm>
#include "mozilla/Unused.h"
namespace logging {
namespace {
@ -127,6 +129,7 @@ Win32ErrorLogMessage::Win32ErrorLogMessage(const char* file,
SystemErrorCode err)
: err_(err),
log_message_(file, line, severity) {
mozilla::Unused << err_;
}
Win32ErrorLogMessage::~Win32ErrorLogMessage() {
@ -138,6 +141,7 @@ ErrnoLogMessage::ErrnoLogMessage(const char* file,
SystemErrorCode err)
: err_(err),
log_message_(file, line, severity) {
mozilla::Unused << err_;
}
ErrnoLogMessage::~ErrnoLogMessage() {

View File

@ -0,0 +1,18 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=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 http://mozilla.org/MPL/2.0/. */
// This is a dummy version of Chromium source file base/metrics/histogram_macros.h.
// To provide to histogram macros required in base/memory/shared_memory_win.cc
// UMA_HISTOGRAM_ENUMERATION and UMA_HISTOGRAM_SPARSE_SLOWLY.
// We don't require Chromiums histogram collection code.
#ifndef BASE_METRICS_HISTOGRAM_MACROS_H_
#define BASE_METRICS_HISTOGRAM_MACROS_H_
#define UMA_HISTOGRAM_ENUMERATION(name, sample, enum_max) do { } while (0)
#define UMA_HISTOGRAM_SPARSE_SLOWLY(name, sample) do { } while (0)
#endif // BASE_METRICS_HISTOGRAM_MACROS_H_

View File

@ -0,0 +1,31 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=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 http://mozilla.org/MPL/2.0/. */
// This is a cut down version of Chromium source file base/scoped_native_library.h
// The chromium sandbox only requires ScopedNativeLibrary class to automatically
// unload the library, which we can achieve with UniquePtr.
#ifndef BASE_SCOPED_NATIVE_LIBRARY_H_
#define BASE_SCOPED_NATIVE_LIBRARY_H_
#include "mozilla/UniquePtr.h"
namespace base {
struct HModuleFreePolicy
{
typedef HMODULE pointer;
void operator()(pointer hModule)
{
::FreeLibrary(hModule);
}
};
typedef mozilla::UniquePtr<HMODULE, HModuleFreePolicy> ScopedNativeLibrary;
} // namespace base
#endif // BASE_SCOPED_NATIVE_LIBRARY_H_

View File

@ -0,0 +1,64 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=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 http://mozilla.org/MPL/2.0/. */
// This is a cut down version of Chromium source file base/threading/platform_thread_linux.h
// with only the functions required. It also has a dummy implementation of
// SetCurrentThreadPriorityForPlatform, which should not be called.
#include "base/threading/platform_thread.h"
#include "base/threading/platform_thread_internal_posix.h"
#include "mozilla/Assertions.h"
namespace base {
namespace internal {
namespace {
const struct sched_param kRealTimePrio = {8};
} // namespace
const ThreadPriorityToNiceValuePair kThreadPriorityToNiceValueMap[4] = {
{ThreadPriority::BACKGROUND, 10},
{ThreadPriority::NORMAL, 0},
{ThreadPriority::DISPLAY, -8},
{ThreadPriority::REALTIME_AUDIO, -10},
};
bool SetCurrentThreadPriorityForPlatform(ThreadPriority priority) {
MOZ_CRASH();
}
bool GetCurrentThreadPriorityForPlatform(ThreadPriority* priority) {
int maybe_sched_rr = 0;
struct sched_param maybe_realtime_prio = {0};
if (pthread_getschedparam(pthread_self(), &maybe_sched_rr,
&maybe_realtime_prio) == 0 &&
maybe_sched_rr == SCHED_RR &&
maybe_realtime_prio.sched_priority == kRealTimePrio.sched_priority) {
*priority = ThreadPriority::REALTIME_AUDIO;
return true;
}
return false;
}
} // namespace internal
void InitThreading() {}
void TerminateOnThread() {}
size_t GetDefaultThreadStackSize(const pthread_attr_t& attributes) {
#if !defined(THREAD_SANITIZER)
return 0;
#else
// ThreadSanitizer bloats the stack heavily. Evidence has been that the
// default stack size isn't enough for some browser tests.
return 2 * (1 << 23); // 2 times 8192K (the default stack size on Linux).
#endif
}
} // namespace base

View File

@ -0,0 +1,32 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=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 http://mozilla.org/MPL/2.0/. */
// This is a dummy version of Chromium source file base/trace_event/heap_profiler_allocation_context_tracker.h.
// To provide a function required in base/threading/thread_id_name_manager.cc
// SetCurrentThreadName. We don't use the heap profiler.
#ifndef BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_TRACKER_H_
#define BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_TRACKER_H_
namespace base {
namespace trace_event {
// The allocation context tracker keeps track of thread-local context for heap
// profiling. It includes a pseudo stack of trace events. On every allocation
// the tracker provides a snapshot of its context in the form of an
// |AllocationContext| that is to be stored together with the allocation
// details.
class BASE_EXPORT AllocationContextTracker {
public:
static void SetCurrentThreadName(const char* name) {}
DISALLOW_COPY_AND_ASSIGN(AllocationContextTracker);
};
} // namespace trace_event
} // namespace base
#endif // BASE_TRACE_EVENT_HEAP_PROFILER_ALLOCATION_CONTEXT_TRACKER_H_

View File

@ -6,6 +6,9 @@
#ifndef _SECURITY_SANDBOX_TRACKED_OBJECTS_H_
#define _SECURITY_SANDBOX_TRACKED_OBJECTS_H_
#include "mozilla/Assertions.h"
namespace tracked_objects
{
class ThreadData
@ -13,6 +16,7 @@ namespace tracked_objects
public:
static void InitializeThreadContext(const std::string& name)
{
MOZ_CRASH();
}
};
}

View File

@ -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: */
/* 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/. */
// This is a dummy version of a file that is generated by the chromium build
// from base/win/BUILD.gn.
#ifndef BASE_WIN_BASE_FEATURES_H_
#define BASE_WIN_BASE_FEATURES_H_
#include "build/buildflag.h"
#define BUILDFLAG_INTERNAL_SINGLE_MODULE_MODE_HANDLE_VERIFIER() (false)
#endif // BASE_WIN_BASE_FEATURES_H_

View File

@ -7,21 +7,35 @@
// This is a stripped down version of Chromium source file base/win/registry.h
// Within our copy of Chromium files this is only used in base/win/windows_version.cc
// in OSInfo::processor_model_name, which we don't use.
// It is also used in GetUBR, which is used as the VersionNumber.patch, which
// again is not needed by the sandbox.
#ifndef BASE_WIN_REGISTRY_H_
#define BASE_WIN_REGISTRY_H_
#include <winerror.h>
namespace base {
namespace win {
class BASE_EXPORT RegKey {
public:
RegKey() {};
RegKey(HKEY rootkey, const wchar_t* subkey, REGSAM access) {}
~RegKey() {}
LONG Open(HKEY rootkey, const wchar_t* subkey, REGSAM access) {
return ERROR_CANTOPEN;
}
LONG ReadValueDW(const wchar_t* name, DWORD* out_value) const
{
return ERROR_CANTREAD;
}
LONG ReadValue(const wchar_t* name, std::wstring* out_value) const
{
return 0;
return ERROR_CANTREAD;
}
private:

View File

@ -188,4 +188,58 @@ typedef struct _PROCESS_MITIGATION_EXTENSION_POINT_DISABLE_POLICY {
#endif // NTDDI_WIN8
#endif // (_WIN32_WINNT < 0x0602)
#if (_WIN32_WINNT < 0x0A00)
//
// Define Font Disable Policy. When enabled, this option will
// block loading Non System Fonts.
//
#define PROCESS_CREATION_MITIGATION_POLICY_FONT_DISABLE_MASK (0x00000003ui64 << 48)
#define PROCESS_CREATION_MITIGATION_POLICY_FONT_DISABLE_DEFER (0x00000000ui64 << 48)
#define PROCESS_CREATION_MITIGATION_POLICY_FONT_DISABLE_ALWAYS_ON (0x00000001ui64 << 48)
#define PROCESS_CREATION_MITIGATION_POLICY_FONT_DISABLE_ALWAYS_OFF (0x00000002ui64 << 48)
#define PROCESS_CREATION_MITIGATION_POLICY_AUDIT_NONSYSTEM_FONTS (0x00000003ui64 << 48)
//
// Define remote image load options. When enabled, this option will
// block mapping of images from remote devices.
//
#define PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_REMOTE_MASK (0x00000003ui64 << 52)
#define PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_REMOTE_DEFER (0x00000000ui64 << 52)
#define PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_REMOTE_ALWAYS_ON (0x00000001ui64 << 52)
#define PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_REMOTE_ALWAYS_OFF (0x00000002ui64 << 52)
#define PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_REMOTE_RESERVED (0x00000003ui64 << 52)
//
// Define low IL image load options. When enabled, this option will
// block mapping of images that have the low mandatory label.
//
#define PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_LOW_LABEL_MASK (0x00000003ui64 << 56)
#define PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_LOW_LABEL_DEFER (0x00000000ui64 << 56)
#define PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_LOW_LABEL_ALWAYS_ON (0x00000001ui64 << 56)
#define PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_LOW_LABEL_ALWAYS_OFF (0x00000002ui64 << 56)
#define PROCESS_CREATION_MITIGATION_POLICY_IMAGE_LOAD_NO_LOW_LABEL_RESERVED (0x00000003ui64 << 56)
//
// Define Attribute to disable creation of child process
//
#define PROCESS_CREATION_CHILD_PROCESS_RESTRICTED 0x01
#define PROCESS_CREATION_CHILD_PROCESS_OVERRIDE 0x02
//
// Define Attribute for Desktop Appx Overide.
//
#define PROCESS_CREATION_DESKTOP_APPX_OVERRIDE 0x04
#define ProcThreadAttributeChildProcessPolicy 14
#define PROC_THREAD_ATTRIBUTE_CHILD_PROCESS_POLICY \
ProcThreadAttributeValue (ProcThreadAttributeChildProcessPolicy, FALSE, TRUE, FALSE)
#endif // (_WIN32_WINNT >= 0x0A00)
#endif // _SECURITY_SANDBOX_BASE_SHIM_SDKDECLS_H_

View File

@ -6,6 +6,7 @@
#include <stddef.h>
#include <ostream>
#include <utility>
#include "base/bind.h"
#include "base/callback.h"
@ -21,7 +22,8 @@ namespace base {
// this for thread-safe access, since it will only be modified in testing.
static AtExitManager* g_top_manager = NULL;
AtExitManager::AtExitManager() : next_manager_(g_top_manager) {
AtExitManager::AtExitManager()
: processing_callbacks_(false), next_manager_(g_top_manager) {
// If multiple modules instantiate AtExitManagers they'll end up living in this
// module... they have to coexist.
#if !defined(COMPONENT_BUILD)
@ -55,7 +57,8 @@ void AtExitManager::RegisterTask(base::Closure task) {
}
AutoLock lock(g_top_manager->lock_);
g_top_manager->stack_.push(task);
DCHECK(!g_top_manager->processing_callbacks_);
g_top_manager->stack_.push(std::move(task));
}
// static
@ -65,16 +68,28 @@ void AtExitManager::ProcessCallbacksNow() {
return;
}
AutoLock lock(g_top_manager->lock_);
while (!g_top_manager->stack_.empty()) {
base::Closure task = g_top_manager->stack_.top();
task.Run();
g_top_manager->stack_.pop();
// Callbacks may try to add new callbacks, so run them without holding
// |lock_|. This is an error and caught by the DCHECK in RegisterTask(), but
// handle it gracefully in release builds so we don't deadlock.
std::stack<base::Closure> tasks;
{
AutoLock lock(g_top_manager->lock_);
tasks.swap(g_top_manager->stack_);
g_top_manager->processing_callbacks_ = true;
}
while (!tasks.empty()) {
base::Closure task = tasks.top();
task.Run();
tasks.pop();
}
// Expect that all callbacks have been run.
DCHECK(g_top_manager->stack_.empty());
}
AtExitManager::AtExitManager(bool shadow) : next_manager_(g_top_manager) {
AtExitManager::AtExitManager(bool shadow)
: processing_callbacks_(false), next_manager_(g_top_manager) {
DCHECK(shadow || !g_top_manager);
g_top_manager = this;
}

View File

@ -59,6 +59,7 @@ class BASE_EXPORT AtExitManager {
private:
base::Lock lock_;
std::stack<base::Closure> stack_;
bool processing_callbacks_;
AtExitManager* next_manager_; // Stack of managers to allow shadowing.
DISALLOW_COPY_AND_ASSIGN(AtExitManager);

View File

@ -12,7 +12,7 @@
namespace base {
typedef subtle::Atomic32 AtomicRefCount;
typedef subtle::AtomicWord AtomicRefCount;
// Increment a reference count by "increment", which must exceed 0.
inline void AtomicRefCountIncN(volatile AtomicRefCount *ptr,

View File

@ -32,9 +32,8 @@ enum BasePathKey {
DIR_MODULE, // Directory containing FILE_MODULE.
DIR_TEMP, // Temporary directory.
DIR_HOME, // User's root home directory. On Windows this will look
// like "C:\Users\you" (or on XP
// "C:\Document and Settings\you") which isn't necessarily
// a great place to put files.
// like "C:\Users\<user>" which isn't necessarily a great
// place to put files.
FILE_EXE, // Path and filename of the current executable.
FILE_MODULE, // Path and filename of the module containing the code for
// the PathService (which could differ from FILE_EXE if the

View File

@ -25,26 +25,25 @@ enum {
DIR_PROGRAM_FILESX86, // See table above.
DIR_PROGRAM_FILES6432, // See table above.
DIR_IE_INTERNET_CACHE, // Temporary Internet Files directory.
DIR_COMMON_START_MENU, // Usually "C:\Documents and Settings\All Users\
// Start Menu\Programs"
DIR_START_MENU, // Usually "C:\Documents and Settings\<user>\
// Start Menu\Programs"
DIR_APP_DATA, // Application Data directory under the user profile.
DIR_LOCAL_APP_DATA, // "Local Settings\Application Data" directory under
// the user profile.
DIR_COMMON_APP_DATA, // W2K, XP, W2K3: "C:\Documents and Settings\
// All Users\Application Data".
// Vista, W2K8 and above: "C:\ProgramData".
DIR_APP_SHORTCUTS, // Where tiles on the start screen are stored, only
// for Windows 8. Maps to "Local\AppData\Microsoft\
// Windows\Application Shortcuts\".
DIR_COMMON_DESKTOP, // Directory for the common desktop (visible
// on all user's Desktop).
DIR_USER_QUICK_LAUNCH, // Directory for the quick launch shortcuts.
DIR_TASKBAR_PINS, // Directory for the shortcuts pinned to taskbar
// (Win7-8) via base::win::PinShortcutToTaskbar().
DIR_WINDOWS_FONTS, // Usually C:\Windows\Fonts.
DIR_IE_INTERNET_CACHE, // Temporary Internet Files directory.
DIR_COMMON_START_MENU, // Usually "C:\ProgramData\Microsoft\Windows\
// Start Menu\Programs"
DIR_START_MENU, // Usually "C:\Users\<user>\AppData\Roaming\
// Microsoft\Windows\Start Menu\Programs"
DIR_APP_DATA, // Application Data directory under the user
// profile.
DIR_LOCAL_APP_DATA, // "Local Settings\Application Data" directory
// under the user profile.
DIR_COMMON_APP_DATA, // Usually "C:\ProgramData".
DIR_APP_SHORTCUTS, // Where tiles on the start screen are stored,
// only for Windows 8. Maps to "Local\AppData\
// Microsoft\Windows\Application Shortcuts\".
DIR_COMMON_DESKTOP, // Directory for the common desktop (visible
// on all user's Desktop).
DIR_USER_QUICK_LAUNCH, // Directory for the quick launch shortcuts.
DIR_TASKBAR_PINS, // Directory for the shortcuts pinned to taskbar.
DIR_IMPLICIT_APP_SHORTCUTS, // The implicit user pinned shortcut directory.
DIR_WINDOWS_FONTS, // Usually C:\Windows\Fonts.
PATH_WIN_END
};

View File

@ -20,6 +20,10 @@ const char kEnableCrashReporter[] = "enable-crash-reporter";
// the memory-infra category is enabled.
const char kEnableHeapProfiling[] = "enable-heap-profiling";
// Report native (walk the stack) allocation traces. By default pseudo stacks
// derived from trace events are reported.
const char kEnableHeapProfilingModeNative[] = "native";
// Generates full memory crash dump.
const char kFullMemoryCrashReport[] = "full-memory-crash-report";
@ -46,6 +50,11 @@ const char kNoErrorDialogs[] = "noerrdialogs";
// to the test framework that the current process is a child process.
const char kTestChildProcess[] = "test-child-process";
// When running certain tests that spawn child processes, this switch indicates
// to the test framework that the current process should not initialize ICU to
// avoid creating any scoped handles too early in startup.
const char kTestDoNotInitializeIcu[] = "test-do-not-initialize-icu";
// Gives the default maximal active V-logging level; 0 is the default.
// Normally positive values are used for V-logging levels.
const char kV[] = "v";
@ -80,6 +89,16 @@ const char kProfilerTiming[] = "profiler-timing";
// chrome://profiler.
const char kProfilerTimingDisabledValue[] = "0";
// Specifies a location for profiling output. This will only work if chrome has
// been built with the gyp variable profiling=1 or gn arg enable_profiling=true.
//
// {pid} if present will be replaced by the pid of the process.
// {count} if present will be incremented each time a profile is generated
// for this process.
// The default is chrome-profile-{pid} for the browser and test-profile-{pid}
// for tests.
const char kProfilingFile[] = "profiling-file";
#if defined(OS_WIN)
// Disables the USB keyboard detection for blocking the OSK on Win8+.
const char kDisableUsbKeyboardDetect[] = "disable-usb-keyboard-detect";

View File

@ -15,13 +15,16 @@ extern const char kDisableBreakpad[];
extern const char kDisableLowEndDeviceMode[];
extern const char kEnableCrashReporter[];
extern const char kEnableHeapProfiling[];
extern const char kEnableHeapProfilingModeNative[];
extern const char kEnableLowEndDeviceMode[];
extern const char kForceFieldTrials[];
extern const char kFullMemoryCrashReport[];
extern const char kNoErrorDialogs[];
extern const char kProfilerTiming[];
extern const char kProfilerTimingDisabledValue[];
extern const char kProfilingFile[];
extern const char kTestChildProcess[];
extern const char kTestDoNotInitializeIcu[];
extern const char kTraceToFile[];
extern const char kTraceToFileName[];
extern const char kV[];

View File

@ -6,13 +6,12 @@
#define BASE_BIND_H_
#include "base/bind_internal.h"
#include "base/callback_internal.h"
// -----------------------------------------------------------------------------
// Usage documentation
// -----------------------------------------------------------------------------
//
// See base/callback.h for documentation.
// See //docs/callback.md for documentation.
//
//
// -----------------------------------------------------------------------------
@ -22,78 +21,61 @@
// If you're reading the implementation, before proceeding further, you should
// read the top comment of base/bind_internal.h for a definition of common
// terms and concepts.
//
// RETURN TYPES
//
// Though Bind()'s result is meant to be stored in a Callback<> type, it
// cannot actually return the exact type without requiring a large amount
// of extra template specializations. The problem is that in order to
// discern the correct specialization of Callback<>, Bind would need to
// unwrap the function signature to determine the signature's arity, and
// whether or not it is a method.
//
// Each unique combination of (arity, function_type, num_prebound) where
// function_type is one of {function, method, const_method} would require
// one specialization. We eventually have to do a similar number of
// specializations anyways in the implementation (see the Invoker<>,
// classes). However, it is avoidable in Bind if we return the result
// via an indirection like we do below.
//
// TODO(ajwong): We might be able to avoid this now, but need to test.
//
// It is possible to move most of the static_assert into BindState<>, but it
// feels a little nicer to have the asserts here so people do not need to crack
// open bind_internal.h. On the other hand, it makes Bind() harder to read.
namespace base {
// Bind as OnceCallback.
template <typename Functor, typename... Args>
base::Callback<
typename internal::BindState<
typename internal::FunctorTraits<Functor>::RunnableType,
typename internal::FunctorTraits<Functor>::RunType,
typename internal::CallbackParamTraits<Args>::StorageType...>
::UnboundRunType>
Bind(Functor functor, const Args&... args) {
// Type aliases for how to store and run the functor.
using RunnableType = typename internal::FunctorTraits<Functor>::RunnableType;
using RunType = typename internal::FunctorTraits<Functor>::RunType;
inline OnceCallback<MakeUnboundRunType<Functor, Args...>>
BindOnce(Functor&& functor, Args&&... args) {
using BindState = internal::MakeBindStateType<Functor, Args...>;
using UnboundRunType = MakeUnboundRunType<Functor, Args...>;
using Invoker = internal::Invoker<BindState, UnboundRunType>;
using CallbackType = OnceCallback<UnboundRunType>;
// Use RunnableType::RunType instead of RunType above because our
// checks below for bound references need to know what the actual
// functor is going to interpret the argument as.
using BoundRunType = typename RunnableType::RunType;
// Store the invoke func into PolymorphicInvoke before casting it to
// InvokeFuncStorage, so that we can ensure its type matches to
// PolymorphicInvoke, to which CallbackType will cast back.
using PolymorphicInvoke = typename CallbackType::PolymorphicInvoke;
PolymorphicInvoke invoke_func = &Invoker::RunOnce;
using BoundArgs =
internal::TakeTypeListItem<sizeof...(Args),
internal::ExtractArgs<BoundRunType>>;
using InvokeFuncStorage = internal::BindStateBase::InvokeFuncStorage;
return CallbackType(new BindState(
reinterpret_cast<InvokeFuncStorage>(invoke_func),
std::forward<Functor>(functor),
std::forward<Args>(args)...));
}
// Do not allow binding a non-const reference parameter. Non-const reference
// parameters are disallowed by the Google style guide. Also, binding a
// non-const reference parameter can make for subtle bugs because the
// invoked function will receive a reference to the stored copy of the
// argument and not the original.
static_assert(!internal::HasNonConstReferenceItem<BoundArgs>::value,
"do not bind functions with nonconst ref");
// Bind as RepeatingCallback.
template <typename Functor, typename... Args>
inline RepeatingCallback<MakeUnboundRunType<Functor, Args...>>
BindRepeating(Functor&& functor, Args&&... args) {
using BindState = internal::MakeBindStateType<Functor, Args...>;
using UnboundRunType = MakeUnboundRunType<Functor, Args...>;
using Invoker = internal::Invoker<BindState, UnboundRunType>;
using CallbackType = RepeatingCallback<UnboundRunType>;
const bool is_method = internal::HasIsMethodTag<RunnableType>::value;
// Store the invoke func into PolymorphicInvoke before casting it to
// InvokeFuncStorage, so that we can ensure its type matches to
// PolymorphicInvoke, to which CallbackType will cast back.
using PolymorphicInvoke = typename CallbackType::PolymorphicInvoke;
PolymorphicInvoke invoke_func = &Invoker::Run;
// For methods, we need to be careful for parameter 1. We do not require
// a scoped_refptr because BindState<> itself takes care of AddRef() for
// methods. We also disallow binding of an array as the method's target
// object.
static_assert(!internal::BindsArrayToFirstArg<is_method, Args...>::value,
"first bound argument to method cannot be array");
static_assert(
!internal::HasRefCountedParamAsRawPtr<is_method, Args...>::value,
"a parameter is a refcounted type and needs scoped_refptr");
using InvokeFuncStorage = internal::BindStateBase::InvokeFuncStorage;
return CallbackType(new BindState(
reinterpret_cast<InvokeFuncStorage>(invoke_func),
std::forward<Functor>(functor),
std::forward<Args>(args)...));
}
using BindState = internal::BindState<
RunnableType, RunType,
typename internal::CallbackParamTraits<Args>::StorageType...>;
return Callback<typename BindState::UnboundRunType>(
new BindState(internal::MakeRunnable(functor), args...));
// Unannotated Bind.
// TODO(tzik): Deprecate this and migrate to OnceCallback and
// RepeatingCallback, once they get ready.
template <typename Functor, typename... Args>
inline Callback<MakeUnboundRunType<Functor, Args...>>
Bind(Functor&& functor, Args&&... args) {
return BindRepeating(std::forward<Functor>(functor),
std::forward<Args>(args)...);
}
} // namespace base

View File

@ -28,6 +28,9 @@
// argument will CHECK() because the first invocation would have already
// transferred ownership to the target function.
//
// RetainedRef() accepts a ref counted object and retains a reference to it.
// When the callback is called, the object is passed as a raw pointer.
//
// ConstRef() allows binding a constant reference to an argument rather
// than a copy.
//
@ -71,6 +74,19 @@
// Without Owned(), someone would have to know to delete |pn| when the last
// reference to the Callback is deleted.
//
// EXAMPLE OF RetainedRef():
//
// void foo(RefCountedBytes* bytes) {}
//
// scoped_refptr<RefCountedBytes> bytes = ...;
// Closure callback = Bind(&foo, base::RetainedRef(bytes));
// callback.Run();
//
// Without RetainedRef, the scoped_refptr would try to implicitly convert to
// a raw pointer and fail compilation:
//
// Closure callback = Bind(&foo, bytes); // ERROR!
//
//
// EXAMPLE OF ConstRef():
//
@ -105,10 +121,11 @@
//
// EXAMPLE OF Passed():
//
// void TakesOwnership(scoped_ptr<Foo> arg) { }
// scoped_ptr<Foo> CreateFoo() { return scoped_ptr<Foo>(new Foo()); }
// void TakesOwnership(std::unique_ptr<Foo> arg) { }
// std::unique_ptr<Foo> CreateFoo() { return std::unique_ptr<Foo>(new Foo());
// }
//
// scoped_ptr<Foo> f(new Foo());
// std::unique_ptr<Foo> f(new Foo());
//
// // |cb| is given ownership of Foo(). |f| is now NULL.
// // You can use std::move(f) in place of &f, but it's more verbose.
@ -150,150 +167,18 @@
#include "base/callback.h"
#include "base/memory/weak_ptr.h"
#include "base/template_util.h"
#include "build/build_config.h"
namespace base {
template <typename T>
struct IsWeakReceiver;
template <typename>
struct BindUnwrapTraits;
namespace internal {
// Use the Substitution Failure Is Not An Error (SFINAE) trick to inspect T
// for the existence of AddRef() and Release() functions of the correct
// signature.
//
// http://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error
// http://stackoverflow.com/questions/257288/is-it-possible-to-write-a-c-template-to-check-for-a-functions-existence
// http://stackoverflow.com/questions/4358584/sfinae-approach-comparison
// http://stackoverflow.com/questions/1966362/sfinae-to-check-for-inherited-member-functions
//
// The last link in particular show the method used below.
//
// For SFINAE to work with inherited methods, we need to pull some extra tricks
// with multiple inheritance. In the more standard formulation, the overloads
// of Check would be:
//
// template <typename C>
// Yes NotTheCheckWeWant(Helper<&C::TargetFunc>*);
//
// template <typename C>
// No NotTheCheckWeWant(...);
//
// static const bool value = sizeof(NotTheCheckWeWant<T>(0)) == sizeof(Yes);
//
// The problem here is that template resolution will not match
// C::TargetFunc if TargetFunc does not exist directly in C. That is, if
// TargetFunc in inherited from an ancestor, &C::TargetFunc will not match,
// |value| will be false. This formulation only checks for whether or
// not TargetFunc exist directly in the class being introspected.
//
// To get around this, we play a dirty trick with multiple inheritance.
// First, We create a class BaseMixin that declares each function that we
// want to probe for. Then we create a class Base that inherits from both T
// (the class we wish to probe) and BaseMixin. Note that the function
// signature in BaseMixin does not need to match the signature of the function
// we are probing for; thus it's easiest to just use void().
//
// Now, if TargetFunc exists somewhere in T, then &Base::TargetFunc has an
// ambiguous resolution between BaseMixin and T. This lets us write the
// following:
//
// template <typename C>
// No GoodCheck(Helper<&C::TargetFunc>*);
//
// template <typename C>
// Yes GoodCheck(...);
//
// static const bool value = sizeof(GoodCheck<Base>(0)) == sizeof(Yes);
//
// Notice here that the variadic version of GoodCheck() returns Yes here
// instead of No like the previous one. Also notice that we calculate |value|
// by specializing GoodCheck() on Base instead of T.
//
// We've reversed the roles of the variadic, and Helper overloads.
// GoodCheck(Helper<&C::TargetFunc>*), when C = Base, fails to be a valid
// substitution if T::TargetFunc exists. Thus GoodCheck<Base>(0) will resolve
// to the variadic version if T has TargetFunc. If T::TargetFunc does not
// exist, then &C::TargetFunc is not ambiguous, and the overload resolution
// will prefer GoodCheck(Helper<&C::TargetFunc>*).
//
// This method of SFINAE will correctly probe for inherited names, but it cannot
// typecheck those names. It's still a good enough sanity check though.
//
// Works on gcc-4.2, gcc-4.4, and Visual Studio 2008.
//
// TODO(ajwong): Move to ref_counted.h or template_util.h when we've vetted
// this works well.
//
// TODO(ajwong): Make this check for Release() as well.
// See http://crbug.com/82038.
template <typename T>
class SupportsAddRefAndRelease {
using Yes = char[1];
using No = char[2];
struct BaseMixin {
void AddRef();
};
// MSVC warns when you try to use Base if T has a private destructor, the
// common pattern for refcounted types. It does this even though no attempt to
// instantiate Base is made. We disable the warning for this definition.
#if defined(OS_WIN)
#pragma warning(push)
#pragma warning(disable:4624)
#endif
struct Base : public T, public BaseMixin {
};
#if defined(OS_WIN)
#pragma warning(pop)
#endif
template <void(BaseMixin::*)()> struct Helper {};
template <typename C>
static No& Check(Helper<&C::AddRef>*);
template <typename >
static Yes& Check(...);
public:
enum { value = sizeof(Check<Base>(0)) == sizeof(Yes) };
};
// Helpers to assert that arguments of a recounted type are bound with a
// scoped_refptr.
template <bool IsClasstype, typename T>
struct UnsafeBindtoRefCountedArgHelper : false_type {
};
template <typename T>
struct UnsafeBindtoRefCountedArgHelper<true, T>
: integral_constant<bool, SupportsAddRefAndRelease<T>::value> {
};
template <typename T>
struct UnsafeBindtoRefCountedArg : false_type {
};
template <typename T>
struct UnsafeBindtoRefCountedArg<T*>
: UnsafeBindtoRefCountedArgHelper<is_class<T>::value, T> {
};
template <typename T>
class HasIsMethodTag {
using Yes = char[1];
using No = char[2];
template <typename U>
static Yes& Check(typename U::IsMethod*);
template <typename U>
static No& Check(...);
public:
enum { value = sizeof(Check<T>(0)) == sizeof(Yes) };
};
template <typename T>
class UnretainedWrapper {
public:
@ -312,23 +197,27 @@ class ConstRefWrapper {
const T* ptr_;
};
template <typename T>
class RetainedRefWrapper {
public:
explicit RetainedRefWrapper(T* o) : ptr_(o) {}
explicit RetainedRefWrapper(scoped_refptr<T> o) : ptr_(std::move(o)) {}
T* get() const { return ptr_.get(); }
private:
scoped_refptr<T> ptr_;
};
template <typename T>
struct IgnoreResultHelper {
explicit IgnoreResultHelper(T functor) : functor_(functor) {}
explicit IgnoreResultHelper(T functor) : functor_(std::move(functor)) {}
explicit operator bool() const { return !!functor_; }
T functor_;
};
template <typename T>
struct IgnoreResultHelper<Callback<T> > {
explicit IgnoreResultHelper(const Callback<T>& functor) : functor_(functor) {}
const Callback<T>& functor_;
};
// An alternate implementation is to avoid the destructive copy, and instead
// specialize ParamTraits<> for OwnedWrapper<> to change the StorageType to
// a class that is essentially a scoped_ptr<>.
// a class that is essentially a std::unique_ptr<>.
//
// The current implementation has the benefit though of leaving ParamTraits<>
// fully in callback_internal.h as well as avoiding type conversions during
@ -339,7 +228,7 @@ class OwnedWrapper {
explicit OwnedWrapper(T* o) : ptr_(o) {}
~OwnedWrapper() { delete ptr_; }
T* get() const { return ptr_; }
OwnedWrapper(const OwnedWrapper& other) {
OwnedWrapper(OwnedWrapper&& other) {
ptr_ = other.ptr_;
other.ptr_ = NULL;
}
@ -376,9 +265,9 @@ class PassedWrapper {
public:
explicit PassedWrapper(T&& scoper)
: is_valid_(true), scoper_(std::move(scoper)) {}
PassedWrapper(const PassedWrapper& other)
PassedWrapper(PassedWrapper&& other)
: is_valid_(other.is_valid_), scoper_(std::move(other.scoper_)) {}
T Pass() const {
T Take() const {
CHECK(is_valid_);
is_valid_ = false;
return std::move(scoper_);
@ -389,100 +278,13 @@ class PassedWrapper {
mutable T scoper_;
};
// Unwrap the stored parameters for the wrappers above.
template <typename T>
struct UnwrapTraits {
using ForwardType = const T&;
static ForwardType Unwrap(const T& o) { return o; }
};
using Unwrapper = BindUnwrapTraits<typename std::decay<T>::type>;
template <typename T>
struct UnwrapTraits<UnretainedWrapper<T> > {
using ForwardType = T*;
static ForwardType Unwrap(UnretainedWrapper<T> unretained) {
return unretained.get();
}
};
template <typename T>
struct UnwrapTraits<ConstRefWrapper<T> > {
using ForwardType = const T&;
static ForwardType Unwrap(ConstRefWrapper<T> const_ref) {
return const_ref.get();
}
};
template <typename T>
struct UnwrapTraits<scoped_refptr<T> > {
using ForwardType = T*;
static ForwardType Unwrap(const scoped_refptr<T>& o) { return o.get(); }
};
template <typename T>
struct UnwrapTraits<WeakPtr<T> > {
using ForwardType = const WeakPtr<T>&;
static ForwardType Unwrap(const WeakPtr<T>& o) { return o; }
};
template <typename T>
struct UnwrapTraits<OwnedWrapper<T> > {
using ForwardType = T*;
static ForwardType Unwrap(const OwnedWrapper<T>& o) {
return o.get();
}
};
template <typename T>
struct UnwrapTraits<PassedWrapper<T> > {
using ForwardType = T;
static T Unwrap(PassedWrapper<T>& o) {
return o.Pass();
}
};
// Utility for handling different refcounting semantics in the Bind()
// function.
template <bool is_method, typename... T>
struct MaybeScopedRefPtr;
template <bool is_method>
struct MaybeScopedRefPtr<is_method> {
MaybeScopedRefPtr() {}
};
template <typename T, typename... Rest>
struct MaybeScopedRefPtr<false, T, Rest...> {
MaybeScopedRefPtr(const T&, const Rest&...) {}
};
template <typename T, size_t n, typename... Rest>
struct MaybeScopedRefPtr<false, T[n], Rest...> {
MaybeScopedRefPtr(const T*, const Rest&...) {}
};
template <typename T, typename... Rest>
struct MaybeScopedRefPtr<true, T, Rest...> {
MaybeScopedRefPtr(const T& o, const Rest&...) {}
};
template <typename T, typename... Rest>
struct MaybeScopedRefPtr<true, T*, Rest...> {
MaybeScopedRefPtr(T* o, const Rest&...) : ref_(o) {}
scoped_refptr<T> ref_;
};
// No need to additionally AddRef() and Release() since we are storing a
// scoped_refptr<> inside the storage object already.
template <typename T, typename... Rest>
struct MaybeScopedRefPtr<true, scoped_refptr<T>, Rest...> {
MaybeScopedRefPtr(const scoped_refptr<T>&, const Rest&...) {}
};
template <typename T, typename... Rest>
struct MaybeScopedRefPtr<true, const T*, Rest...> {
MaybeScopedRefPtr(const T* o, const Rest&...) : ref_(o) {}
scoped_refptr<const T> ref_;
};
auto Unwrap(T&& o) -> decltype(Unwrapper<T>::Unwrap(std::forward<T>(o))) {
return Unwrapper<T>::Unwrap(std::forward<T>(o));
}
// IsWeakMethod is a helper that determine if we are binding a WeakPtr<> to a
// method. It is used internally by Bind() to select the correct
@ -491,16 +293,11 @@ struct MaybeScopedRefPtr<true, const T*, Rest...> {
//
// The first argument should be the type of the object that will be received by
// the method.
template <bool IsMethod, typename... Args>
struct IsWeakMethod : public false_type {};
template <bool is_method, typename... Args>
struct IsWeakMethod : std::false_type {};
template <typename T, typename... Args>
struct IsWeakMethod<true, WeakPtr<T>, Args...> : public true_type {};
template <typename T, typename... Args>
struct IsWeakMethod<true, ConstRefWrapper<WeakPtr<T>>, Args...>
: public true_type {};
struct IsWeakMethod<true, T, Args...> : IsWeakReceiver<T> {};
// Packs a list of types to hold them in a single type.
template <typename... Types>
@ -583,19 +380,25 @@ struct MakeFunctionTypeImpl<R, TypeList<Args...>> {
template <typename R, typename ArgList>
using MakeFunctionType = typename MakeFunctionTypeImpl<R, ArgList>::Type;
// Used for ExtractArgs.
// Used for ExtractArgs and ExtractReturnType.
template <typename Signature>
struct ExtractArgsImpl;
template <typename R, typename... Args>
struct ExtractArgsImpl<R(Args...)> {
using Type = TypeList<Args...>;
using ReturnType = R;
using ArgsList = TypeList<Args...>;
};
// A type-level function that extracts function arguments into a TypeList.
// E.g. ExtractArgs<R(A, B, C)> is evaluated to TypeList<A, B, C>.
template <typename Signature>
using ExtractArgs = typename ExtractArgsImpl<Signature>::Type;
using ExtractArgs = typename ExtractArgsImpl<Signature>::ArgsList;
// A type-level function that extracts the return type of a function.
// E.g. ExtractReturnType<R(A, B, C)> is evaluated to R.
template <typename Signature>
using ExtractReturnType = typename ExtractArgsImpl<Signature>::ReturnType;
} // namespace internal
@ -604,6 +407,16 @@ static inline internal::UnretainedWrapper<T> Unretained(T* o) {
return internal::UnretainedWrapper<T>(o);
}
template <typename T>
static inline internal::RetainedRefWrapper<T> RetainedRef(T* o) {
return internal::RetainedRefWrapper<T>(o);
}
template <typename T>
static inline internal::RetainedRefWrapper<T> RetainedRef(scoped_refptr<T> o) {
return internal::RetainedRefWrapper<T>(std::move(o));
}
template <typename T>
static inline internal::ConstRefWrapper<T> ConstRef(const T& o) {
return internal::ConstRefWrapper<T>(o);
@ -622,28 +435,19 @@ static inline internal::OwnedWrapper<T> Owned(T* o) {
// Both versions of Passed() prevent T from being an lvalue reference. The first
// via use of enable_if, and the second takes a T* which will not bind to T&.
template <typename T,
typename std::enable_if<internal::IsMoveOnlyType<T>::value &&
!std::is_lvalue_reference<T>::value>::type* =
typename std::enable_if<!std::is_lvalue_reference<T>::value>::type* =
nullptr>
static inline internal::PassedWrapper<T> Passed(T&& scoper) {
return internal::PassedWrapper<T>(std::move(scoper));
}
template <typename T,
typename std::enable_if<internal::IsMoveOnlyType<T>::value>::type* =
nullptr>
template <typename T>
static inline internal::PassedWrapper<T> Passed(T* scoper) {
return internal::PassedWrapper<T>(std::move(*scoper));
}
template <typename T>
static inline internal::IgnoreResultHelper<T> IgnoreResult(T data) {
return internal::IgnoreResultHelper<T>(data);
}
template <typename T>
static inline internal::IgnoreResultHelper<Callback<T> >
IgnoreResult(const Callback<T>& data) {
return internal::IgnoreResultHelper<Callback<T> >(data);
return internal::IgnoreResultHelper<T>(std::move(data));
}
BASE_EXPORT void DoNothing();
@ -653,6 +457,70 @@ void DeletePointer(T* obj) {
delete obj;
}
// An injection point to control |this| pointer behavior on a method invocation.
// If IsWeakReceiver<> is true_type for |T| and |T| is used for a receiver of a
// method, base::Bind cancels the method invocation if the receiver is tested as
// false.
// E.g. Foo::bar() is not called:
// struct Foo : base::SupportsWeakPtr<Foo> {
// void bar() {}
// };
//
// WeakPtr<Foo> oo = nullptr;
// base::Bind(&Foo::bar, oo).Run();
template <typename T>
struct IsWeakReceiver : std::false_type {};
template <typename T>
struct IsWeakReceiver<internal::ConstRefWrapper<T>> : IsWeakReceiver<T> {};
template <typename T>
struct IsWeakReceiver<WeakPtr<T>> : std::true_type {};
// An injection point to control how bound objects passed to the target
// function. BindUnwrapTraits<>::Unwrap() is called for each bound objects right
// before the target function is invoked.
template <typename>
struct BindUnwrapTraits {
template <typename T>
static T&& Unwrap(T&& o) { return std::forward<T>(o); }
};
template <typename T>
struct BindUnwrapTraits<internal::UnretainedWrapper<T>> {
static T* Unwrap(const internal::UnretainedWrapper<T>& o) {
return o.get();
}
};
template <typename T>
struct BindUnwrapTraits<internal::ConstRefWrapper<T>> {
static const T& Unwrap(const internal::ConstRefWrapper<T>& o) {
return o.get();
}
};
template <typename T>
struct BindUnwrapTraits<internal::RetainedRefWrapper<T>> {
static T* Unwrap(const internal::RetainedRefWrapper<T>& o) {
return o.get();
}
};
template <typename T>
struct BindUnwrapTraits<internal::OwnedWrapper<T>> {
static T* Unwrap(const internal::OwnedWrapper<T>& o) {
return o.get();
}
};
template <typename T>
struct BindUnwrapTraits<internal::PassedWrapper<T>> {
static T Unwrap(const internal::PassedWrapper<T>& o) {
return o.Take();
}
};
} // namespace base
#endif // BASE_BIND_HELPERS_H_

View File

@ -7,6 +7,7 @@
#include <stddef.h>
#include <tuple>
#include <type_traits>
#include "base/bind_helpers.h"
@ -17,10 +18,6 @@
#include "base/tuple.h"
#include "build/build_config.h"
#if defined(OS_WIN)
#include "base/bind_internal_win.h"
#endif
namespace base {
namespace internal {
@ -28,63 +25,87 @@ namespace internal {
//
//
// CONCEPTS:
// Runnable -- A type (really a type class) that has a single Run() method
// and a RunType typedef that corresponds to the type of Run().
// A Runnable can declare that it should treated like a method
// call by including a typedef named IsMethod. The value of
// this typedef is NOT inspected, only the existence. When a
// Runnable declares itself a method, Bind() will enforce special
// refcounting + WeakPtr handling semantics for the first
// parameter which is expected to be an object.
// Functor -- A copyable type representing something that should be called.
// All function pointers, Callback<>, and Runnables are functors
// even if the invocation syntax differs.
// Functor -- A movable type representing something that should be called.
// All function pointers and Callback<> are functors even if the
// invocation syntax differs.
// RunType -- A function type (as opposed to function _pointer_ type) for
// a Run() function. Usually just a convenience typedef.
// a Callback<>::Run(). Usually just a convenience typedef.
// (Bound)Args -- A set of types that stores the arguments.
//
// Types:
// RunnableAdapter<> -- Wraps the various "function" pointer types into an
// object that adheres to the Runnable interface.
// ForceVoidReturn<> -- Helper class for translating function signatures to
// equivalent forms with a "void" return type.
// FunctorTraits<> -- Type traits used determine the correct RunType and
// RunnableType for a Functor. This is where function
// FunctorTraits<> -- Type traits used to determine the correct RunType and
// invocation manner for a Functor. This is where function
// signature adapters are applied.
// MakeRunnable<> -- Takes a Functor and returns an object in the Runnable
// type class that represents the underlying Functor.
// InvokeHelper<> -- Take a Runnable + arguments and actully invokes it.
// InvokeHelper<> -- Take a Functor + arguments and actully invokes it.
// Handle the differing syntaxes needed for WeakPtr<>
// support, and for ignoring return values. This is separate
// from Invoker to avoid creating multiple version of
// Invoker<>.
// Invoker<> -- Unwraps the curried parameters and executes the Runnable.
// support. This is separate from Invoker to avoid creating
// multiple version of Invoker<>.
// Invoker<> -- Unwraps the curried parameters and executes the Functor.
// BindState<> -- Stores the curried parameters, and is the main entry point
// into the Bind() system, doing most of the type resolution.
// There are ARITY BindState types.
// into the Bind() system.
// HasNonConstReferenceParam selects true_type when any of the parameters in
// |Sig| is a non-const reference.
// Implementation note: This non-specialized case handles zero-arity case only.
// Non-zero-arity cases should be handled by the specialization below.
template <typename List>
struct HasNonConstReferenceItem : false_type {};
template <typename...>
struct make_void {
using type = void;
};
// Implementation note: Select true_type if the first parameter is a non-const
// reference. Otherwise, skip the first parameter and check rest of parameters
// recursively.
template <typename T, typename... Args>
struct HasNonConstReferenceItem<TypeList<T, Args...>>
: std::conditional<is_non_const_reference<T>::value,
true_type,
HasNonConstReferenceItem<TypeList<Args...>>>::type {};
// A clone of C++17 std::void_t.
// Unlike the original version, we need |make_void| as a helper struct to avoid
// a C++14 defect.
// ref: http://en.cppreference.com/w/cpp/types/void_t
// ref: http://open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#1558
template <typename... Ts>
using void_t = typename make_void<Ts...>::type;
template <typename Callable,
typename Signature = decltype(&Callable::operator())>
struct ExtractCallableRunTypeImpl;
template <typename Callable, typename R, typename... Args>
struct ExtractCallableRunTypeImpl<Callable, R(Callable::*)(Args...) const> {
using Type = R(Args...);
};
// Evaluated to RunType of the given callable type.
// Example:
// auto f = [](int, char*) { return 0.1; };
// ExtractCallableRunType<decltype(f)>
// is evaluated to
// double(int, char*);
template <typename Callable>
using ExtractCallableRunType =
typename ExtractCallableRunTypeImpl<Callable>::Type;
// IsConvertibleToRunType<Functor> is std::true_type if |Functor| has operator()
// and convertible to the corresponding function pointer. Otherwise, it's
// std::false_type.
// Example:
// IsConvertibleToRunType<void(*)()>::value is false.
//
// struct Foo {};
// IsConvertibleToRunType<void(Foo::*)()>::value is false.
//
// auto f = []() {};
// IsConvertibleToRunType<decltype(f)>::value is true.
//
// int i = 0;
// auto g = [i]() {};
// IsConvertibleToRunType<decltype(g)>::value is false.
template <typename Functor, typename SFINAE = void>
struct IsConvertibleToRunType : std::false_type {};
template <typename Callable>
struct IsConvertibleToRunType<Callable, void_t<decltype(&Callable::operator())>>
: std::is_convertible<Callable, ExtractCallableRunType<Callable>*> {};
// HasRefCountedTypeAsRawPtr selects true_type when any of the |Args| is a raw
// pointer to a RefCounted type.
// Implementation note: This non-specialized case handles zero-arity case only.
// Non-zero-arity cases should be handled by the specialization below.
template <typename... Args>
struct HasRefCountedTypeAsRawPtr : false_type {};
struct HasRefCountedTypeAsRawPtr : std::false_type {};
// Implementation note: Select true_type if the first parameter is a raw pointer
// to a RefCounted type. Otherwise, skip the first parameter and check rest of
@ -92,117 +113,9 @@ struct HasRefCountedTypeAsRawPtr : false_type {};
template <typename T, typename... Args>
struct HasRefCountedTypeAsRawPtr<T, Args...>
: std::conditional<NeedsScopedRefptrButGetsRawPtr<T>::value,
true_type,
std::true_type,
HasRefCountedTypeAsRawPtr<Args...>>::type {};
// BindsArrayToFirstArg selects true_type when |is_method| is true and the first
// item of |Args| is an array type.
// Implementation note: This non-specialized case handles !is_method case and
// zero-arity case only. Other cases should be handled by the specialization
// below.
template <bool is_method, typename... Args>
struct BindsArrayToFirstArg : false_type {};
template <typename T, typename... Args>
struct BindsArrayToFirstArg<true, T, Args...> : is_array<T> {};
// HasRefCountedParamAsRawPtr is the same to HasRefCountedTypeAsRawPtr except
// when |is_method| is true HasRefCountedParamAsRawPtr skips the first argument.
// Implementation note: This non-specialized case handles !is_method case and
// zero-arity case only. Other cases should be handled by the specialization
// below.
template <bool is_method, typename... Args>
struct HasRefCountedParamAsRawPtr : HasRefCountedTypeAsRawPtr<Args...> {};
template <typename T, typename... Args>
struct HasRefCountedParamAsRawPtr<true, T, Args...>
: HasRefCountedTypeAsRawPtr<Args...> {};
// RunnableAdapter<>
//
// The RunnableAdapter<> templates provide a uniform interface for invoking
// a function pointer, method pointer, or const method pointer. The adapter
// exposes a Run() method with an appropriate signature. Using this wrapper
// allows for writing code that supports all three pointer types without
// undue repetition. Without it, a lot of code would need to be repeated 3
// times.
//
// For method pointers and const method pointers the first argument to Run()
// is considered to be the received of the method. This is similar to STL's
// mem_fun().
//
// This class also exposes a RunType typedef that is the function type of the
// Run() function.
//
// If and only if the wrapper contains a method or const method pointer, an
// IsMethod typedef is exposed. The existence of this typedef (NOT the value)
// marks that the wrapper should be considered a method wrapper.
template <typename Functor>
class RunnableAdapter;
// Function.
template <typename R, typename... Args>
class RunnableAdapter<R(*)(Args...)> {
public:
// MSVC 2013 doesn't support Type Alias of function types.
// Revisit this after we update it to newer version.
typedef R RunType(Args...);
explicit RunnableAdapter(R(*function)(Args...))
: function_(function) {
}
R Run(typename CallbackParamTraits<Args>::ForwardType... args) {
return function_(CallbackForward(args)...);
}
private:
R (*function_)(Args...);
};
// Method.
template <typename R, typename T, typename... Args>
class RunnableAdapter<R(T::*)(Args...)> {
public:
// MSVC 2013 doesn't support Type Alias of function types.
// Revisit this after we update it to newer version.
typedef R RunType(T*, Args...);
using IsMethod = true_type;
explicit RunnableAdapter(R(T::*method)(Args...))
: method_(method) {
}
R Run(T* object, typename CallbackParamTraits<Args>::ForwardType... args) {
return (object->*method_)(CallbackForward(args)...);
}
private:
R (T::*method_)(Args...);
};
// Const Method.
template <typename R, typename T, typename... Args>
class RunnableAdapter<R(T::*)(Args...) const> {
public:
using RunType = R(const T*, Args...);
using IsMethod = true_type;
explicit RunnableAdapter(R(T::*method)(Args...) const)
: method_(method) {
}
R Run(const T* object,
typename CallbackParamTraits<Args>::ForwardType... args) {
return (object->*method_)(CallbackForward(args)...);
}
private:
R (T::*method_)(Args...) const;
};
// ForceVoidReturn<>
//
// Set of templates that support forcing the function return type to void.
@ -211,215 +124,435 @@ struct ForceVoidReturn;
template <typename R, typename... Args>
struct ForceVoidReturn<R(Args...)> {
// MSVC 2013 doesn't support Type Alias of function types.
// Revisit this after we update it to newer version.
typedef void RunType(Args...);
using RunType = void(Args...);
};
// FunctorTraits<>
//
// See description at top of file.
template <typename T>
struct FunctorTraits {
using RunnableType = RunnableAdapter<T>;
using RunType = typename RunnableType::RunType;
template <typename Functor, typename SFINAE = void>
struct FunctorTraits;
// For a callable type that is convertible to the corresponding function type.
// This specialization is intended to allow binding captureless lambdas by
// base::Bind(), based on the fact that captureless lambdas can be convertible
// to the function type while capturing lambdas can't.
template <typename Functor>
struct FunctorTraits<
Functor,
typename std::enable_if<IsConvertibleToRunType<Functor>::value>::type> {
using RunType = ExtractCallableRunType<Functor>;
static constexpr bool is_method = false;
static constexpr bool is_nullable = false;
template <typename... RunArgs>
static ExtractReturnType<RunType>
Invoke(const Functor& functor, RunArgs&&... args) {
return functor(std::forward<RunArgs>(args)...);
}
};
// For functions.
template <typename R, typename... Args>
struct FunctorTraits<R (*)(Args...)> {
using RunType = R(Args...);
static constexpr bool is_method = false;
static constexpr bool is_nullable = true;
template <typename... RunArgs>
static R Invoke(R (*function)(Args...), RunArgs&&... args) {
return function(std::forward<RunArgs>(args)...);
}
};
#if defined(OS_WIN) && !defined(ARCH_CPU_X86_64)
// For functions.
template <typename R, typename... Args>
struct FunctorTraits<R(__stdcall*)(Args...)> {
using RunType = R(Args...);
static constexpr bool is_method = false;
static constexpr bool is_nullable = true;
template <typename... RunArgs>
static R Invoke(R(__stdcall* function)(Args...), RunArgs&&... args) {
return function(std::forward<RunArgs>(args)...);
}
};
// For functions.
template <typename R, typename... Args>
struct FunctorTraits<R(__fastcall*)(Args...)> {
using RunType = R(Args...);
static constexpr bool is_method = false;
static constexpr bool is_nullable = true;
template <typename... RunArgs>
static R Invoke(R(__fastcall* function)(Args...), RunArgs&&... args) {
return function(std::forward<RunArgs>(args)...);
}
};
#endif // defined(OS_WIN) && !defined(ARCH_CPU_X86_64)
// For methods.
template <typename R, typename Receiver, typename... Args>
struct FunctorTraits<R (Receiver::*)(Args...)> {
using RunType = R(Receiver*, Args...);
static constexpr bool is_method = true;
static constexpr bool is_nullable = true;
template <typename ReceiverPtr, typename... RunArgs>
static R Invoke(R (Receiver::*method)(Args...),
ReceiverPtr&& receiver_ptr,
RunArgs&&... args) {
// Clang skips CV qualifier check on a method pointer invocation when the
// receiver is a subclass. Store the receiver into a const reference to
// T to ensure the CV check works.
// https://llvm.org/bugs/show_bug.cgi?id=27037
Receiver& receiver = *receiver_ptr;
return (receiver.*method)(std::forward<RunArgs>(args)...);
}
};
// For const methods.
template <typename R, typename Receiver, typename... Args>
struct FunctorTraits<R (Receiver::*)(Args...) const> {
using RunType = R(const Receiver*, Args...);
static constexpr bool is_method = true;
static constexpr bool is_nullable = true;
template <typename ReceiverPtr, typename... RunArgs>
static R Invoke(R (Receiver::*method)(Args...) const,
ReceiverPtr&& receiver_ptr,
RunArgs&&... args) {
// Clang skips CV qualifier check on a method pointer invocation when the
// receiver is a subclass. Store the receiver into a const reference to
// T to ensure the CV check works.
// https://llvm.org/bugs/show_bug.cgi?id=27037
const Receiver& receiver = *receiver_ptr;
return (receiver.*method)(std::forward<RunArgs>(args)...);
}
};
// For IgnoreResults.
template <typename T>
struct FunctorTraits<IgnoreResultHelper<T>> {
using RunnableType = typename FunctorTraits<T>::RunnableType;
struct FunctorTraits<IgnoreResultHelper<T>> : FunctorTraits<T> {
using RunType =
typename ForceVoidReturn<typename RunnableType::RunType>::RunType;
typename ForceVoidReturn<typename FunctorTraits<T>::RunType>::RunType;
template <typename IgnoreResultType, typename... RunArgs>
static void Invoke(IgnoreResultType&& ignore_result_helper,
RunArgs&&... args) {
FunctorTraits<T>::Invoke(
std::forward<IgnoreResultType>(ignore_result_helper).functor_,
std::forward<RunArgs>(args)...);
}
};
template <typename T>
struct FunctorTraits<Callback<T>> {
using RunnableType = Callback<T> ;
using RunType = typename Callback<T>::RunType;
// For Callbacks.
template <typename R, typename... Args,
CopyMode copy_mode, RepeatMode repeat_mode>
struct FunctorTraits<Callback<R(Args...), copy_mode, repeat_mode>> {
using RunType = R(Args...);
static constexpr bool is_method = false;
static constexpr bool is_nullable = true;
template <typename CallbackType, typename... RunArgs>
static R Invoke(CallbackType&& callback, RunArgs&&... args) {
DCHECK(!callback.is_null());
return std::forward<CallbackType>(callback).Run(
std::forward<RunArgs>(args)...);
}
};
// MakeRunnable<>
//
// Converts a passed in functor to a RunnableType using type inference.
template <typename T>
typename FunctorTraits<T>::RunnableType MakeRunnable(const T& t) {
return RunnableAdapter<T>(t);
}
template <typename T>
typename FunctorTraits<T>::RunnableType
MakeRunnable(const IgnoreResultHelper<T>& t) {
return MakeRunnable(t.functor_);
}
template <typename T>
const typename FunctorTraits<Callback<T>>::RunnableType&
MakeRunnable(const Callback<T>& t) {
DCHECK(!t.is_null());
return t;
}
// InvokeHelper<>
//
// There are 3 logical InvokeHelper<> specializations: normal, void-return,
// WeakCalls.
// There are 2 logical InvokeHelper<> specializations: normal, WeakCalls.
//
// The normal type just calls the underlying runnable.
//
// We need a InvokeHelper to handle void return types in order to support
// IgnoreResult(). Normally, if the Runnable's RunType had a void return,
// the template system would just accept "return functor.Run()" ignoring
// the fact that a void function is being used with return. This piece of
// sugar breaks though when the Runnable's RunType is not void. Thus, we
// need a partial specialization to change the syntax to drop the "return"
// from the invocation call.
//
// WeakCalls similarly need special syntax that is applied to the first
// argument to check if they should no-op themselves.
template <bool IsWeakCall, typename ReturnType, typename Runnable,
typename ArgsType>
// WeakCalls need special syntax that is applied to the first argument to check
// if they should no-op themselves.
template <bool is_weak_call, typename ReturnType>
struct InvokeHelper;
template <typename ReturnType, typename Runnable, typename... Args>
struct InvokeHelper<false, ReturnType, Runnable, TypeList<Args...>> {
static ReturnType MakeItSo(Runnable runnable, Args... args) {
return runnable.Run(CallbackForward(args)...);
template <typename ReturnType>
struct InvokeHelper<false, ReturnType> {
template <typename Functor, typename... RunArgs>
static inline ReturnType MakeItSo(Functor&& functor, RunArgs&&... args) {
using Traits = FunctorTraits<typename std::decay<Functor>::type>;
return Traits::Invoke(std::forward<Functor>(functor),
std::forward<RunArgs>(args)...);
}
};
template <typename Runnable, typename... Args>
struct InvokeHelper<false, void, Runnable, TypeList<Args...>> {
static void MakeItSo(Runnable runnable, Args... args) {
runnable.Run(CallbackForward(args)...);
}
};
template <typename Runnable, typename BoundWeakPtr, typename... Args>
struct InvokeHelper<true, void, Runnable, TypeList<BoundWeakPtr, Args...>> {
static void MakeItSo(Runnable runnable, BoundWeakPtr weak_ptr, Args... args) {
if (!weak_ptr.get()) {
return;
}
runnable.Run(weak_ptr.get(), CallbackForward(args)...);
}
};
#if !defined(_MSC_VER)
template <typename ReturnType, typename Runnable, typename ArgsType>
struct InvokeHelper<true, ReturnType, Runnable, ArgsType> {
template <typename ReturnType>
struct InvokeHelper<true, ReturnType> {
// WeakCalls are only supported for functions with a void return type.
// Otherwise, the function result would be undefined if the the WeakPtr<>
// is invalidated.
static_assert(is_void<ReturnType>::value,
static_assert(std::is_void<ReturnType>::value,
"weak_ptrs can only bind to methods without return values");
};
#endif
template <typename Functor, typename BoundWeakPtr, typename... RunArgs>
static inline void MakeItSo(Functor&& functor,
BoundWeakPtr&& weak_ptr,
RunArgs&&... args) {
if (!weak_ptr)
return;
using Traits = FunctorTraits<typename std::decay<Functor>::type>;
Traits::Invoke(std::forward<Functor>(functor),
std::forward<BoundWeakPtr>(weak_ptr),
std::forward<RunArgs>(args)...);
}
};
// Invoker<>
//
// See description at the top of the file.
template <typename BoundIndices,
typename StorageType, typename Unwrappers,
typename InvokeHelperType, typename UnboundForwardRunType>
template <typename StorageType, typename UnboundRunType>
struct Invoker;
template <size_t... bound_indices,
typename StorageType,
typename... Unwrappers,
typename InvokeHelperType,
typename R,
typename... UnboundForwardArgs>
struct Invoker<IndexSequence<bound_indices...>,
StorageType, TypeList<Unwrappers...>,
InvokeHelperType, R(UnboundForwardArgs...)> {
static R Run(BindStateBase* base,
UnboundForwardArgs... unbound_args) {
StorageType* storage = static_cast<StorageType*>(base);
template <typename StorageType, typename R, typename... UnboundArgs>
struct Invoker<StorageType, R(UnboundArgs...)> {
static R RunOnce(BindStateBase* base, UnboundArgs&&... unbound_args) {
// Local references to make debugger stepping easier. If in a debugger,
// you really want to warp ahead and step through the
// InvokeHelper<>::MakeItSo() call below.
return InvokeHelperType::MakeItSo(
storage->runnable_,
Unwrappers::Unwrap(get<bound_indices>(storage->bound_args_))...,
CallbackForward(unbound_args)...);
StorageType* storage = static_cast<StorageType*>(base);
static constexpr size_t num_bound_args =
std::tuple_size<decltype(storage->bound_args_)>::value;
return RunImpl(std::move(storage->functor_),
std::move(storage->bound_args_),
MakeIndexSequence<num_bound_args>(),
std::forward<UnboundArgs>(unbound_args)...);
}
static R Run(BindStateBase* base, UnboundArgs&&... unbound_args) {
// Local references to make debugger stepping easier. If in a debugger,
// you really want to warp ahead and step through the
// InvokeHelper<>::MakeItSo() call below.
const StorageType* storage = static_cast<StorageType*>(base);
static constexpr size_t num_bound_args =
std::tuple_size<decltype(storage->bound_args_)>::value;
return RunImpl(storage->functor_,
storage->bound_args_,
MakeIndexSequence<num_bound_args>(),
std::forward<UnboundArgs>(unbound_args)...);
}
private:
template <typename Functor, typename BoundArgsTuple, size_t... indices>
static inline R RunImpl(Functor&& functor,
BoundArgsTuple&& bound,
IndexSequence<indices...>,
UnboundArgs&&... unbound_args) {
static constexpr bool is_method =
FunctorTraits<typename std::decay<Functor>::type>::is_method;
using DecayedArgsTuple = typename std::decay<BoundArgsTuple>::type;
static constexpr bool is_weak_call =
IsWeakMethod<is_method,
typename std::tuple_element<
indices,
DecayedArgsTuple>::type...>::value;
return InvokeHelper<is_weak_call, R>::MakeItSo(
std::forward<Functor>(functor),
Unwrap(base::get<indices>(std::forward<BoundArgsTuple>(bound)))...,
std::forward<UnboundArgs>(unbound_args)...);
}
};
// Used to implement MakeUnboundRunType.
template <typename Functor, typename... BoundArgs>
struct MakeUnboundRunTypeImpl {
using RunType =
typename FunctorTraits<typename std::decay<Functor>::type>::RunType;
using ReturnType = ExtractReturnType<RunType>;
using Args = ExtractArgs<RunType>;
using UnboundArgs = DropTypeListItem<sizeof...(BoundArgs), Args>;
using Type = MakeFunctionType<ReturnType, UnboundArgs>;
};
template <typename Functor>
typename std::enable_if<FunctorTraits<Functor>::is_nullable, bool>::type
IsNull(const Functor& functor) {
return !functor;
}
template <typename Functor>
typename std::enable_if<!FunctorTraits<Functor>::is_nullable, bool>::type
IsNull(const Functor&) {
return false;
}
template <typename Functor, typename... BoundArgs>
struct BindState;
template <typename BindStateType, typename SFINAE = void>
struct CancellationChecker {
static constexpr bool is_cancellable = false;
static bool Run(const BindStateBase*) {
return false;
}
};
template <typename Functor, typename... BoundArgs>
struct CancellationChecker<
BindState<Functor, BoundArgs...>,
typename std::enable_if<IsWeakMethod<FunctorTraits<Functor>::is_method,
BoundArgs...>::value>::type> {
static constexpr bool is_cancellable = true;
static bool Run(const BindStateBase* base) {
using BindStateType = BindState<Functor, BoundArgs...>;
const BindStateType* bind_state = static_cast<const BindStateType*>(base);
return !base::get<0>(bind_state->bound_args_);
}
};
template <typename Signature,
typename... BoundArgs,
CopyMode copy_mode,
RepeatMode repeat_mode>
struct CancellationChecker<
BindState<Callback<Signature, copy_mode, repeat_mode>, BoundArgs...>> {
static constexpr bool is_cancellable = true;
static bool Run(const BindStateBase* base) {
using Functor = Callback<Signature, copy_mode, repeat_mode>;
using BindStateType = BindState<Functor, BoundArgs...>;
const BindStateType* bind_state = static_cast<const BindStateType*>(base);
return bind_state->functor_.IsCancelled();
}
};
// Template helpers to detect using Bind() on a base::Callback without any
// additional arguments. In that case, the original base::Callback object should
// just be directly used.
template <typename Functor, typename... BoundArgs>
struct BindingCallbackWithNoArgs {
static constexpr bool value = false;
};
template <typename Signature,
typename... BoundArgs,
CopyMode copy_mode,
RepeatMode repeat_mode>
struct BindingCallbackWithNoArgs<Callback<Signature, copy_mode, repeat_mode>,
BoundArgs...> {
static constexpr bool value = sizeof...(BoundArgs) == 0;
};
// BindState<>
//
// This stores all the state passed into Bind() and is also where most
// of the template resolution magic occurs.
//
// Runnable is the functor we are binding arguments to.
// RunType is type of the Run() function that the Invoker<> should use.
// Normally, this is the same as the RunType of the Runnable, but it can
// be different if an adapter like IgnoreResult() has been used.
//
// BoundArgs contains the storage type for all the bound arguments.
template <typename Runnable, typename RunType, typename... BoundArgs>
struct BindState;
// This stores all the state passed into Bind().
template <typename Functor, typename... BoundArgs>
struct BindState final : BindStateBase {
using IsCancellable = std::integral_constant<
bool, CancellationChecker<BindState>::is_cancellable>;
template <typename Runnable,
typename R,
typename... Args,
typename... BoundArgs>
struct BindState<Runnable, R(Args...), BoundArgs...> final
: public BindStateBase {
private:
using StorageType = BindState<Runnable, R(Args...), BoundArgs...>;
using RunnableType = Runnable;
template <typename ForwardFunctor, typename... ForwardBoundArgs>
explicit BindState(BindStateBase::InvokeFuncStorage invoke_func,
ForwardFunctor&& functor,
ForwardBoundArgs&&... bound_args)
// IsCancellable is std::false_type if the CancellationChecker<>::Run
// returns always false. Otherwise, it's std::true_type.
: BindState(IsCancellable{},
invoke_func,
std::forward<ForwardFunctor>(functor),
std::forward<ForwardBoundArgs>(bound_args)...) {
static_assert(!BindingCallbackWithNoArgs<Functor, BoundArgs...>::value,
"Attempting to bind a base::Callback with no additional "
"arguments: save a heap allocation and use the original "
"base::Callback object");
}
// true_type if Runnable is a method invocation and the first bound argument
// is a WeakPtr.
using IsWeakCall =
IsWeakMethod<HasIsMethodTag<Runnable>::value, BoundArgs...>;
using BoundIndices = MakeIndexSequence<sizeof...(BoundArgs)>;
using Unwrappers = TypeList<UnwrapTraits<BoundArgs>...>;
using UnboundForwardArgs = DropTypeListItem<
sizeof...(BoundArgs),
TypeList<typename CallbackParamTraits<Args>::ForwardType...>>;
using UnboundForwardRunType = MakeFunctionType<R, UnboundForwardArgs>;
using InvokeHelperArgs = ConcatTypeLists<
TypeList<typename UnwrapTraits<BoundArgs>::ForwardType...>,
UnboundForwardArgs>;
using InvokeHelperType =
InvokeHelper<IsWeakCall::value, R, Runnable, InvokeHelperArgs>;
using UnboundArgs = DropTypeListItem<sizeof...(BoundArgs), TypeList<Args...>>;
public:
using InvokerType = Invoker<BoundIndices, StorageType, Unwrappers,
InvokeHelperType, UnboundForwardRunType>;
using UnboundRunType = MakeFunctionType<R, UnboundArgs>;
BindState(const Runnable& runnable, const BoundArgs&... bound_args)
: BindStateBase(&Destroy),
runnable_(runnable),
ref_(bound_args...),
bound_args_(bound_args...) {}
RunnableType runnable_;
MaybeScopedRefPtr<HasIsMethodTag<Runnable>::value, BoundArgs...> ref_;
Tuple<BoundArgs...> bound_args_;
Functor functor_;
std::tuple<BoundArgs...> bound_args_;
private:
template <typename ForwardFunctor, typename... ForwardBoundArgs>
explicit BindState(std::true_type,
BindStateBase::InvokeFuncStorage invoke_func,
ForwardFunctor&& functor,
ForwardBoundArgs&&... bound_args)
: BindStateBase(invoke_func, &Destroy,
&CancellationChecker<BindState>::Run),
functor_(std::forward<ForwardFunctor>(functor)),
bound_args_(std::forward<ForwardBoundArgs>(bound_args)...) {
DCHECK(!IsNull(functor_));
}
template <typename ForwardFunctor, typename... ForwardBoundArgs>
explicit BindState(std::false_type,
BindStateBase::InvokeFuncStorage invoke_func,
ForwardFunctor&& functor,
ForwardBoundArgs&&... bound_args)
: BindStateBase(invoke_func, &Destroy),
functor_(std::forward<ForwardFunctor>(functor)),
bound_args_(std::forward<ForwardBoundArgs>(bound_args)...) {
DCHECK(!IsNull(functor_));
}
~BindState() {}
static void Destroy(BindStateBase* self) {
delete static_cast<BindState*>(self);
static void Destroy(const BindStateBase* self) {
delete static_cast<const BindState*>(self);
}
};
// Used to implement MakeBindStateType.
template <bool is_method, typename Functor, typename... BoundArgs>
struct MakeBindStateTypeImpl;
template <typename Functor, typename... BoundArgs>
struct MakeBindStateTypeImpl<false, Functor, BoundArgs...> {
static_assert(!HasRefCountedTypeAsRawPtr<BoundArgs...>::value,
"A parameter is a refcounted type and needs scoped_refptr.");
using Type = BindState<typename std::decay<Functor>::type,
typename std::decay<BoundArgs>::type...>;
};
template <typename Functor>
struct MakeBindStateTypeImpl<true, Functor> {
using Type = BindState<typename std::decay<Functor>::type>;
};
template <typename Functor, typename Receiver, typename... BoundArgs>
struct MakeBindStateTypeImpl<true, Functor, Receiver, BoundArgs...> {
static_assert(
!std::is_array<typename std::remove_reference<Receiver>::type>::value,
"First bound argument to a method cannot be an array.");
static_assert(!HasRefCountedTypeAsRawPtr<BoundArgs...>::value,
"A parameter is a refcounted type and needs scoped_refptr.");
private:
using DecayedReceiver = typename std::decay<Receiver>::type;
public:
using Type = BindState<
typename std::decay<Functor>::type,
typename std::conditional<
std::is_pointer<DecayedReceiver>::value,
scoped_refptr<typename std::remove_pointer<DecayedReceiver>::type>,
DecayedReceiver>::type,
typename std::decay<BoundArgs>::type...>;
};
template <typename Functor, typename... BoundArgs>
using MakeBindStateType = typename MakeBindStateTypeImpl<
FunctorTraits<typename std::decay<Functor>::type>::is_method,
Functor,
BoundArgs...>::Type;
} // namespace internal
// Returns a RunType of bound functor.
// E.g. MakeUnboundRunType<R(A, B, C), A, B> is evaluated to R(C).
template <typename Functor, typename... BoundArgs>
using MakeUnboundRunType =
typename internal::MakeUnboundRunTypeImpl<Functor, BoundArgs...>::Type;
} // namespace base
#endif // BASE_BIND_INTERNAL_H_

View File

@ -1,69 +0,0 @@
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Specializations of RunnableAdapter<> for Windows specific calling
// conventions. Please see base/bind_internal.h for more info.
#ifndef BASE_BIND_INTERNAL_WIN_H_
#define BASE_BIND_INTERNAL_WIN_H_
#include "build/build_config.h"
// In the x64 architecture in Windows, __fastcall, __stdcall, etc, are all
// the same as __cdecl which would turn the following specializations into
// multiple definitions.
#if !defined(ARCH_CPU_X86_64)
namespace base {
namespace internal {
template <typename Functor>
class RunnableAdapter;
// __stdcall Function.
template <typename R, typename... Args>
class RunnableAdapter<R(__stdcall *)(Args...)> {
public:
// MSVC 2013 doesn't support Type Alias of function types.
// Revisit this after we update it to newer version.
typedef R RunType(Args...);
explicit RunnableAdapter(R(__stdcall *function)(Args...))
: function_(function) {
}
R Run(typename CallbackParamTraits<Args>::ForwardType... args) {
return function_(args...);
}
private:
R (__stdcall *function_)(Args...);
};
// __fastcall Function.
template <typename R, typename... Args>
class RunnableAdapter<R(__fastcall *)(Args...)> {
public:
// MSVC 2013 doesn't support Type Alias of function types.
// Revisit this after we update it to newer version.
typedef R RunType(Args...);
explicit RunnableAdapter(R(__fastcall *function)(Args...))
: function_(function) {
}
R Run(typename CallbackParamTraits<Args>::ForwardType... args) {
return function_(args...);
}
private:
R (__fastcall *function_)(Args...);
};
} // namespace internal
} // namespace base
#endif // !defined(ARCH_CPU_X86_64)
#endif // BASE_BIND_INTERNAL_WIN_H_

View File

@ -6,6 +6,10 @@
#define BASE_BIT_CAST_H_
#include <string.h>
#include <type_traits>
#include "base/compiler_specific.h"
#include "build/build_config.h"
// bit_cast<Dest,Source> is a template function that implements the equivalent
// of "*reinterpret_cast<Dest*>(&source)". We need this in very low-level
@ -54,15 +58,40 @@
// calls to memcpy() with inline object code when the size argument is a
// compile-time constant. On a 32-bit system, memcpy(d,s,4) compiles to one
// load and one store, and memcpy(d,s,8) compiles to two loads and two stores.
//
// WARNING: if Dest or Source is a non-POD type, the result of the memcpy
// is likely to surprise you.
template <class Dest, class Source>
inline Dest bit_cast(const Source& source) {
static_assert(sizeof(Dest) == sizeof(Source),
"bit_cast requires source and destination to be the same size");
#if (__GNUC__ > 5 || (__GNUC__ == 5 && __GNUC_MINOR__ >= 1) || \
(defined(__clang__) && defined(_LIBCPP_VERSION)))
// GCC 5.1 contains the first libstdc++ with is_trivially_copyable.
// Assume libc++ Just Works: is_trivially_copyable added on May 13th 2011.
// However, with libc++ when GCC is the compiler the trait is buggy, see
// crbug.com/607158, so fall back to the less strict variant for non-clang.
static_assert(std::is_trivially_copyable<Dest>::value,
"non-trivially-copyable bit_cast is undefined");
static_assert(std::is_trivially_copyable<Source>::value,
"non-trivially-copyable bit_cast is undefined");
#elif HAS_FEATURE(is_trivially_copyable)
// The compiler supports an equivalent intrinsic.
static_assert(__is_trivially_copyable(Dest),
"non-trivially-copyable bit_cast is undefined");
static_assert(__is_trivially_copyable(Source),
"non-trivially-copyable bit_cast is undefined");
#elif COMPILER_GCC
// Fallback to compiler intrinsic on GCC and clang (which pretends to be
// GCC). This isn't quite the same as is_trivially_copyable but it'll do for
// our purpose.
static_assert(__has_trivial_copy(Dest),
"non-trivially-copyable bit_cast is undefined");
static_assert(__has_trivial_copy(Source),
"non-trivially-copyable bit_cast is undefined");
#else
// Do nothing, let the bots handle it.
#endif
Dest dest;
memcpy(&dest, &source, sizeof(dest));
return dest;

View File

@ -7,397 +7,116 @@
#include "base/callback_forward.h"
#include "base/callback_internal.h"
#include "base/template_util.h"
// NOTE: Header files that do not require the full definition of Callback or
// Closure should #include "base/callback_forward.h" instead of this file.
// -----------------------------------------------------------------------------
// Introduction
// Usage documentation
// -----------------------------------------------------------------------------
//
// The templated Callback class is a generalized function object. Together
// with the Bind() function in bind.h, they provide a type-safe method for
// performing partial application of functions.
//
// Partial application (or "currying") is the process of binding a subset of
// a function's arguments to produce another function that takes fewer
// arguments. This can be used to pass around a unit of delayed execution,
// much like lexical closures are used in other languages. For example, it
// is used in Chromium code to schedule tasks on different MessageLoops.
//
// A callback with no unbound input parameters (base::Callback<void()>)
// is called a base::Closure. Note that this is NOT the same as what other
// languages refer to as a closure -- it does not retain a reference to its
// enclosing environment.
//
// MEMORY MANAGEMENT AND PASSING
//
// The Callback objects themselves should be passed by const-reference, and
// stored by copy. They internally store their state via a refcounted class
// and thus do not need to be deleted.
//
// The reason to pass via a const-reference is to avoid unnecessary
// AddRef/Release pairs to the internal state.
//
//
// -----------------------------------------------------------------------------
// Quick reference for basic stuff
// -----------------------------------------------------------------------------
//
// BINDING A BARE FUNCTION
//
// int Return5() { return 5; }
// base::Callback<int()> func_cb = base::Bind(&Return5);
// LOG(INFO) << func_cb.Run(); // Prints 5.
//
// BINDING A CLASS METHOD
//
// The first argument to bind is the member function to call, the second is
// the object on which to call it.
//
// class Ref : public base::RefCountedThreadSafe<Ref> {
// public:
// int Foo() { return 3; }
// void PrintBye() { LOG(INFO) << "bye."; }
// };
// scoped_refptr<Ref> ref = new Ref();
// base::Callback<void()> ref_cb = base::Bind(&Ref::Foo, ref);
// LOG(INFO) << ref_cb.Run(); // Prints out 3.
//
// By default the object must support RefCounted or you will get a compiler
// error. If you're passing between threads, be sure it's
// RefCountedThreadSafe! See "Advanced binding of member functions" below if
// you don't want to use reference counting.
//
// RUNNING A CALLBACK
//
// Callbacks can be run with their "Run" method, which has the same
// signature as the template argument to the callback.
//
// void DoSomething(const base::Callback<void(int, std::string)>& callback) {
// callback.Run(5, "hello");
// }
//
// Callbacks can be run more than once (they don't get deleted or marked when
// run). However, this precludes using base::Passed (see below).
//
// void DoSomething(const base::Callback<double(double)>& callback) {
// double myresult = callback.Run(3.14159);
// myresult += callback.Run(2.71828);
// }
//
// PASSING UNBOUND INPUT PARAMETERS
//
// Unbound parameters are specified at the time a callback is Run(). They are
// specified in the Callback template type:
//
// void MyFunc(int i, const std::string& str) {}
// base::Callback<void(int, const std::string&)> cb = base::Bind(&MyFunc);
// cb.Run(23, "hello, world");
//
// PASSING BOUND INPUT PARAMETERS
//
// Bound parameters are specified when you create thee callback as arguments
// to Bind(). They will be passed to the function and the Run()ner of the
// callback doesn't see those values or even know that the function it's
// calling.
//
// void MyFunc(int i, const std::string& str) {}
// base::Callback<void()> cb = base::Bind(&MyFunc, 23, "hello world");
// cb.Run();
//
// A callback with no unbound input parameters (base::Callback<void()>)
// is called a base::Closure. So we could have also written:
//
// base::Closure cb = base::Bind(&MyFunc, 23, "hello world");
//
// When calling member functions, bound parameters just go after the object
// pointer.
//
// base::Closure cb = base::Bind(&MyClass::MyFunc, this, 23, "hello world");
//
// PARTIAL BINDING OF PARAMETERS
//
// You can specify some parameters when you create the callback, and specify
// the rest when you execute the callback.
//
// void MyFunc(int i, const std::string& str) {}
// base::Callback<void(const std::string&)> cb = base::Bind(&MyFunc, 23);
// cb.Run("hello world");
//
// When calling a function bound parameters are first, followed by unbound
// parameters.
//
//
// -----------------------------------------------------------------------------
// Quick reference for advanced binding
// -----------------------------------------------------------------------------
//
// BINDING A CLASS METHOD WITH WEAK POINTERS
//
// base::Bind(&MyClass::Foo, GetWeakPtr());
//
// The callback will not be run if the object has already been destroyed.
// DANGER: weak pointers are not threadsafe, so don't use this
// when passing between threads!
//
// BINDING A CLASS METHOD WITH MANUAL LIFETIME MANAGEMENT
//
// base::Bind(&MyClass::Foo, base::Unretained(this));
//
// This disables all lifetime management on the object. You're responsible
// for making sure the object is alive at the time of the call. You break it,
// you own it!
//
// BINDING A CLASS METHOD AND HAVING THE CALLBACK OWN THE CLASS
//
// MyClass* myclass = new MyClass;
// base::Bind(&MyClass::Foo, base::Owned(myclass));
//
// The object will be deleted when the callback is destroyed, even if it's
// not run (like if you post a task during shutdown). Potentially useful for
// "fire and forget" cases.
//
// IGNORING RETURN VALUES
//
// Sometimes you want to call a function that returns a value in a callback
// that doesn't expect a return value.
//
// int DoSomething(int arg) { cout << arg << endl; }
// base::Callback<void(int)> cb =
// base::Bind(base::IgnoreResult(&DoSomething));
//
//
// -----------------------------------------------------------------------------
// Quick reference for binding parameters to Bind()
// -----------------------------------------------------------------------------
//
// Bound parameters are specified as arguments to Bind() and are passed to the
// function. A callback with no parameters or no unbound parameters is called a
// Closure (base::Callback<void()> and base::Closure are the same thing).
//
// PASSING PARAMETERS OWNED BY THE CALLBACK
//
// void Foo(int* arg) { cout << *arg << endl; }
// int* pn = new int(1);
// base::Closure foo_callback = base::Bind(&foo, base::Owned(pn));
//
// The parameter will be deleted when the callback is destroyed, even if it's
// not run (like if you post a task during shutdown).
//
// PASSING PARAMETERS AS A scoped_ptr
//
// void TakesOwnership(scoped_ptr<Foo> arg) {}
// scoped_ptr<Foo> f(new Foo);
// // f becomes null during the following call.
// base::Closure cb = base::Bind(&TakesOwnership, base::Passed(&f));
//
// Ownership of the parameter will be with the callback until the it is run,
// when ownership is passed to the callback function. This means the callback
// can only be run once. If the callback is never run, it will delete the
// object when it's destroyed.
//
// PASSING PARAMETERS AS A scoped_refptr
//
// void TakesOneRef(scoped_refptr<Foo> arg) {}
// scoped_refptr<Foo> f(new Foo)
// base::Closure cb = base::Bind(&TakesOneRef, f);
//
// This should "just work." The closure will take a reference as long as it
// is alive, and another reference will be taken for the called function.
//
// PASSING PARAMETERS BY REFERENCE
//
// Const references are *copied* unless ConstRef is used. Example:
//
// void foo(const int& arg) { printf("%d %p\n", arg, &arg); }
// int n = 1;
// base::Closure has_copy = base::Bind(&foo, n);
// base::Closure has_ref = base::Bind(&foo, base::ConstRef(n));
// n = 2;
// foo(n); // Prints "2 0xaaaaaaaaaaaa"
// has_copy.Run(); // Prints "1 0xbbbbbbbbbbbb"
// has_ref.Run(); // Prints "2 0xaaaaaaaaaaaa"
//
// Normally parameters are copied in the closure. DANGER: ConstRef stores a
// const reference instead, referencing the original parameter. This means
// that you must ensure the object outlives the callback!
//
//
// -----------------------------------------------------------------------------
// Implementation notes
// -----------------------------------------------------------------------------
//
// WHERE IS THIS DESIGN FROM:
//
// The design Callback and Bind is heavily influenced by C++'s
// tr1::function/tr1::bind, and by the "Google Callback" system used inside
// Google.
//
//
// HOW THE IMPLEMENTATION WORKS:
//
// There are three main components to the system:
// 1) The Callback classes.
// 2) The Bind() functions.
// 3) The arguments wrappers (e.g., Unretained() and ConstRef()).
//
// The Callback classes represent a generic function pointer. Internally,
// it stores a refcounted piece of state that represents the target function
// and all its bound parameters. Each Callback specialization has a templated
// constructor that takes an BindState<>*. In the context of the constructor,
// the static type of this BindState<> pointer uniquely identifies the
// function it is representing, all its bound parameters, and a Run() method
// that is capable of invoking the target.
//
// Callback's constructor takes the BindState<>* that has the full static type
// and erases the target function type as well as the types of the bound
// parameters. It does this by storing a pointer to the specific Run()
// function, and upcasting the state of BindState<>* to a
// BindStateBase*. This is safe as long as this BindStateBase pointer
// is only used with the stored Run() pointer.
//
// To BindState<> objects are created inside the Bind() functions.
// These functions, along with a set of internal templates, are responsible for
//
// - Unwrapping the function signature into return type, and parameters
// - Determining the number of parameters that are bound
// - Creating the BindState storing the bound parameters
// - Performing compile-time asserts to avoid error-prone behavior
// - Returning an Callback<> with an arity matching the number of unbound
// parameters and that knows the correct refcounting semantics for the
// target object if we are binding a method.
//
// The Bind functions do the above using type-inference, and template
// specializations.
//
// By default Bind() will store copies of all bound parameters, and attempt
// to refcount a target object if the function being bound is a class method.
// These copies are created even if the function takes parameters as const
// references. (Binding to non-const references is forbidden, see bind.h.)
//
// To change this behavior, we introduce a set of argument wrappers
// (e.g., Unretained(), and ConstRef()). These are simple container templates
// that are passed by value, and wrap a pointer to argument. See the
// file-level comment in base/bind_helpers.h for more info.
//
// These types are passed to the Unwrap() functions, and the MaybeRefcount()
// functions respectively to modify the behavior of Bind(). The Unwrap()
// and MaybeRefcount() functions change behavior by doing partial
// specialization based on whether or not a parameter is a wrapper type.
//
// ConstRef() is similar to tr1::cref. Unretained() is specific to Chromium.
//
//
// WHY NOT TR1 FUNCTION/BIND?
//
// Direct use of tr1::function and tr1::bind was considered, but ultimately
// rejected because of the number of copy constructors invocations involved
// in the binding of arguments during construction, and the forwarding of
// arguments during invocation. These copies will no longer be an issue in
// C++0x because C++0x will support rvalue reference allowing for the compiler
// to avoid these copies. However, waiting for C++0x is not an option.
//
// Measured with valgrind on gcc version 4.4.3 (Ubuntu 4.4.3-4ubuntu5), the
// tr1::bind call itself will invoke a non-trivial copy constructor three times
// for each bound parameter. Also, each when passing a tr1::function, each
// bound argument will be copied again.
//
// In addition to the copies taken at binding and invocation, copying a
// tr1::function causes a copy to be made of all the bound parameters and
// state.
//
// Furthermore, in Chromium, it is desirable for the Callback to take a
// reference on a target object when representing a class method call. This
// is not supported by tr1.
//
// Lastly, tr1::function and tr1::bind has a more general and flexible API.
// This includes things like argument reordering by use of
// tr1::bind::placeholder, support for non-const reference parameters, and some
// limited amount of subtyping of the tr1::function object (e.g.,
// tr1::function<int(int)> is convertible to tr1::function<void(int)>).
//
// These are not features that are required in Chromium. Some of them, such as
// allowing for reference parameters, and subtyping of functions, may actually
// become a source of errors. Removing support for these features actually
// allows for a simpler implementation, and a terser Currying API.
//
//
// WHY NOT GOOGLE CALLBACKS?
//
// The Google callback system also does not support refcounting. Furthermore,
// its implementation has a number of strange edge cases with respect to type
// conversion of its arguments. In particular, the argument's constness must
// at times match exactly the function signature, or the type-inference might
// break. Given the above, writing a custom solution was easier.
//
//
// MISSING FUNCTIONALITY
// - Invoking the return of Bind. Bind(&foo).Run() does not work;
// - Binding arrays to functions that take a non-const pointer.
// Example:
// void Foo(const char* ptr);
// void Bar(char* ptr);
// Bind(&Foo, "test");
// Bind(&Bar, "test"); // This fails because ptr is not const.
// See //docs/callback.md for documentation.
namespace base {
// First, we forward declare the Callback class template. This informs the
// compiler that the template only has 1 type parameter which is the function
// signature that the Callback is representing.
//
// After this, create template specializations for 0-7 parameters. Note that
// even though the template typelist grows, the specialization still
// only has one type: the function signature.
//
// If you are thinking of forward declaring Callback in your own header file,
// please include "base/callback_forward.h" instead.
namespace internal {
template <typename Runnable, typename RunType, typename... BoundArgsType>
struct BindState;
// RunMixin provides different variants of `Run()` function to `Callback<>`
// based on the type of callback.
template <typename CallbackType>
class RunMixin;
// Specialization for OnceCallback.
template <typename R, typename... Args>
class RunMixin<Callback<R(Args...), CopyMode::MoveOnly, RepeatMode::Once>> {
private:
using CallbackType =
Callback<R(Args...), CopyMode::MoveOnly, RepeatMode::Once>;
public:
using PolymorphicInvoke = R(*)(internal::BindStateBase*, Args&&...);
R Run(Args... args) && {
// Move the callback instance into a local variable before the invocation,
// that ensures the internal state is cleared after the invocation.
// It's not safe to touch |this| after the invocation, since running the
// bound function may destroy |this|.
CallbackType cb = static_cast<CallbackType&&>(*this);
PolymorphicInvoke f =
reinterpret_cast<PolymorphicInvoke>(cb.polymorphic_invoke());
return f(cb.bind_state_.get(), std::forward<Args>(args)...);
}
};
// Specialization for RepeatingCallback.
template <typename R, typename... Args, CopyMode copy_mode>
class RunMixin<Callback<R(Args...), copy_mode, RepeatMode::Repeating>> {
private:
using CallbackType = Callback<R(Args...), copy_mode, RepeatMode::Repeating>;
public:
using PolymorphicInvoke = R(*)(internal::BindStateBase*, Args&&...);
R Run(Args... args) const {
const CallbackType& cb = static_cast<const CallbackType&>(*this);
PolymorphicInvoke f =
reinterpret_cast<PolymorphicInvoke>(cb.polymorphic_invoke());
return f(cb.bind_state_.get(), std::forward<Args>(args)...);
}
};
template <typename From, typename To>
struct IsCallbackConvertible : std::false_type {};
template <typename Signature>
struct IsCallbackConvertible<
Callback<Signature, CopyMode::Copyable, RepeatMode::Repeating>,
Callback<Signature, CopyMode::MoveOnly, RepeatMode::Once>> : std::true_type {
};
} // namespace internal
template <typename R, typename... Args>
class Callback<R(Args...)> : public internal::CallbackBase {
template <typename R,
typename... Args,
internal::CopyMode copy_mode,
internal::RepeatMode repeat_mode>
class Callback<R(Args...), copy_mode, repeat_mode>
: public internal::CallbackBase<copy_mode>,
public internal::RunMixin<Callback<R(Args...), copy_mode, repeat_mode>> {
public:
// MSVC 2013 doesn't support Type Alias of function types.
// Revisit this after we update it to newer version.
typedef R RunType(Args...);
static_assert(repeat_mode != internal::RepeatMode::Once ||
copy_mode == internal::CopyMode::MoveOnly,
"OnceCallback must be MoveOnly.");
Callback() : CallbackBase(nullptr) { }
using RunType = R(Args...);
template <typename Runnable, typename BindRunType, typename... BoundArgsType>
explicit Callback(
internal::BindState<Runnable, BindRunType, BoundArgsType...>* bind_state)
: CallbackBase(bind_state) {
// Force the assignment to a local variable of PolymorphicInvoke
// so the compiler will typecheck that the passed in Run() method has
// the correct type.
PolymorphicInvoke invoke_func =
&internal::BindState<Runnable, BindRunType, BoundArgsType...>
::InvokerType::Run;
polymorphic_invoke_ = reinterpret_cast<InvokeFuncStorage>(invoke_func);
Callback() : internal::CallbackBase<copy_mode>(nullptr) {}
explicit Callback(internal::BindStateBase* bind_state)
: internal::CallbackBase<copy_mode>(bind_state) {
}
template <typename OtherCallback,
typename = typename std::enable_if<
internal::IsCallbackConvertible<OtherCallback, Callback>::value
>::type>
Callback(OtherCallback other)
: internal::CallbackBase<copy_mode>(std::move(other)) {}
template <typename OtherCallback,
typename = typename std::enable_if<
internal::IsCallbackConvertible<OtherCallback, Callback>::value
>::type>
Callback& operator=(OtherCallback other) {
static_cast<internal::CallbackBase<copy_mode>&>(*this) = std::move(other);
return *this;
}
bool Equals(const Callback& other) const {
return CallbackBase::Equals(other);
return this->EqualsInternal(other);
}
R Run(typename internal::CallbackParamTraits<Args>::ForwardType... args)
const {
PolymorphicInvoke f =
reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
return f(bind_state_.get(), internal::CallbackForward(args)...);
}
private:
using PolymorphicInvoke =
R(*)(internal::BindStateBase*,
typename internal::CallbackParamTraits<Args>::ForwardType...);
friend class internal::RunMixin<Callback>;
};
} // namespace base

View File

@ -6,14 +6,43 @@
#define BASE_CALLBACK_FORWARD_H_
namespace base {
namespace internal {
template <typename Sig>
// CopyMode is used to control the copyablity of a Callback.
// MoveOnly indicates the Callback is not copyable but movable, and Copyable
// indicates it is copyable and movable.
enum class CopyMode {
MoveOnly,
Copyable,
};
enum class RepeatMode {
Once,
Repeating,
};
} // namespace internal
template <typename Signature,
internal::CopyMode copy_mode = internal::CopyMode::Copyable,
internal::RepeatMode repeat_mode = internal::RepeatMode::Repeating>
class Callback;
// Syntactic sugar to make Callback<void()> easier to declare since it
// will be used in a lot of APIs with delayed execution.
using Closure = Callback<void()>;
template <typename Signature>
using OnceCallback = Callback<Signature,
internal::CopyMode::MoveOnly,
internal::RepeatMode::Once>;
template <typename Signature>
using RepeatingCallback = Callback<Signature,
internal::CopyMode::Copyable,
internal::RepeatMode::Repeating>;
using OnceClosure = OnceCallback<void()>;
using RepeatingClosure = RepeatingCallback<void()>;
} // namespace base
#endif // BASE_CALLBACK_FORWARD_H_

View File

@ -9,38 +9,94 @@
namespace base {
namespace internal {
void BindStateBase::AddRef() {
namespace {
bool ReturnFalse(const BindStateBase*) {
return false;
}
} // namespace
BindStateBase::BindStateBase(InvokeFuncStorage polymorphic_invoke,
void (*destructor)(const BindStateBase*))
: BindStateBase(polymorphic_invoke, destructor, &ReturnFalse) {
}
BindStateBase::BindStateBase(InvokeFuncStorage polymorphic_invoke,
void (*destructor)(const BindStateBase*),
bool (*is_cancelled)(const BindStateBase*))
: polymorphic_invoke_(polymorphic_invoke),
ref_count_(0),
destructor_(destructor),
is_cancelled_(is_cancelled) {}
void BindStateBase::AddRef() const {
AtomicRefCountInc(&ref_count_);
}
void BindStateBase::Release() {
void BindStateBase::Release() const {
if (!AtomicRefCountDec(&ref_count_))
destructor_(this);
}
CallbackBase::CallbackBase(const CallbackBase& c) = default;
CallbackBase& CallbackBase::operator=(const CallbackBase& c) = default;
CallbackBase<CopyMode::MoveOnly>::CallbackBase(CallbackBase&& c) = default;
void CallbackBase::Reset() {
polymorphic_invoke_ = NULL;
CallbackBase<CopyMode::MoveOnly>&
CallbackBase<CopyMode::MoveOnly>::operator=(CallbackBase&& c) = default;
CallbackBase<CopyMode::MoveOnly>::CallbackBase(
const CallbackBase<CopyMode::Copyable>& c)
: bind_state_(c.bind_state_) {}
CallbackBase<CopyMode::MoveOnly>& CallbackBase<CopyMode::MoveOnly>::operator=(
const CallbackBase<CopyMode::Copyable>& c) {
bind_state_ = c.bind_state_;
return *this;
}
void CallbackBase<CopyMode::MoveOnly>::Reset() {
// NULL the bind_state_ last, since it may be holding the last ref to whatever
// object owns us, and we may be deleted after that.
bind_state_ = NULL;
bind_state_ = nullptr;
}
bool CallbackBase::Equals(const CallbackBase& other) const {
return bind_state_.get() == other.bind_state_.get() &&
polymorphic_invoke_ == other.polymorphic_invoke_;
bool CallbackBase<CopyMode::MoveOnly>::IsCancelled() const {
DCHECK(bind_state_);
return bind_state_->IsCancelled();
}
CallbackBase::CallbackBase(BindStateBase* bind_state)
: bind_state_(bind_state),
polymorphic_invoke_(NULL) {
bool CallbackBase<CopyMode::MoveOnly>::EqualsInternal(
const CallbackBase& other) const {
return bind_state_ == other.bind_state_;
}
CallbackBase<CopyMode::MoveOnly>::CallbackBase(
BindStateBase* bind_state)
: bind_state_(bind_state) {
DCHECK(!bind_state_.get() || bind_state_->ref_count_ == 1);
}
CallbackBase::~CallbackBase() {
CallbackBase<CopyMode::MoveOnly>::~CallbackBase() {}
CallbackBase<CopyMode::Copyable>::CallbackBase(
const CallbackBase& c)
: CallbackBase<CopyMode::MoveOnly>(nullptr) {
bind_state_ = c.bind_state_;
}
CallbackBase<CopyMode::Copyable>::CallbackBase(CallbackBase&& c) = default;
CallbackBase<CopyMode::Copyable>&
CallbackBase<CopyMode::Copyable>::operator=(const CallbackBase& c) {
bind_state_ = c.bind_state_;
return *this;
}
CallbackBase<CopyMode::Copyable>&
CallbackBase<CopyMode::Copyable>::operator=(CallbackBase&& c) = default;
template class CallbackBase<CopyMode::MoveOnly>;
template class CallbackBase<CopyMode::Copyable>;
} // namespace internal
} // namespace base

View File

@ -8,19 +8,15 @@
#ifndef BASE_CALLBACK_INTERNAL_H_
#define BASE_CALLBACK_INTERNAL_H_
#include <stddef.h>
#include <memory>
#include <type_traits>
#include "base/atomic_ref_count.h"
#include "base/base_export.h"
#include "base/callback_forward.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/template_util.h"
namespace base {
namespace internal {
template <CopyMode copy_mode>
class CallbackBase;
// BindStateBase is used to provide an opaque handle that the Callback
@ -34,199 +30,108 @@ class CallbackBase;
// Creating a vtable for every BindState template instantiation results in a lot
// of bloat. Its only task is to call the destructor which can be done with a
// function pointer.
class BindStateBase {
class BASE_EXPORT BindStateBase {
public:
using InvokeFuncStorage = void(*)();
protected:
explicit BindStateBase(void (*destructor)(BindStateBase*))
: ref_count_(0), destructor_(destructor) {}
BindStateBase(InvokeFuncStorage polymorphic_invoke,
void (*destructor)(const BindStateBase*));
BindStateBase(InvokeFuncStorage polymorphic_invoke,
void (*destructor)(const BindStateBase*),
bool (*is_cancelled)(const BindStateBase*));
~BindStateBase() = default;
private:
friend class scoped_refptr<BindStateBase>;
template <CopyMode copy_mode>
friend class CallbackBase;
void AddRef();
void Release();
bool IsCancelled() const {
return is_cancelled_(this);
}
AtomicRefCount ref_count_;
void AddRef() const;
void Release() const;
// In C++, it is safe to cast function pointers to function pointers of
// another type. It is not okay to use void*. We create a InvokeFuncStorage
// that that can store our function pointer, and then cast it back to
// the original type on usage.
InvokeFuncStorage polymorphic_invoke_;
mutable AtomicRefCount ref_count_;
// Pointer to a function that will properly destroy |this|.
void (*destructor_)(BindStateBase*);
void (*destructor_)(const BindStateBase*);
bool (*is_cancelled_)(const BindStateBase*);
DISALLOW_COPY_AND_ASSIGN(BindStateBase);
};
// Holds the Callback methods that don't require specialization to reduce
// template bloat.
class BASE_EXPORT CallbackBase {
// CallbackBase<MoveOnly> is a direct base class of MoveOnly callbacks, and
// CallbackBase<Copyable> uses CallbackBase<MoveOnly> for its implementation.
template <>
class BASE_EXPORT CallbackBase<CopyMode::MoveOnly> {
public:
CallbackBase(const CallbackBase& c);
CallbackBase& operator=(const CallbackBase& c);
CallbackBase(CallbackBase&& c);
CallbackBase& operator=(CallbackBase&& c);
explicit CallbackBase(const CallbackBase<CopyMode::Copyable>& c);
CallbackBase& operator=(const CallbackBase<CopyMode::Copyable>& c);
// Returns true if Callback is null (doesn't refer to anything).
bool is_null() const { return bind_state_.get() == NULL; }
explicit operator bool() const { return !is_null(); }
// Returns true if the callback invocation will be nop due to an cancellation.
// It's invalid to call this on uninitialized callback.
bool IsCancelled() const;
// Returns the Callback into an uninitialized state.
void Reset();
protected:
// In C++, it is safe to cast function pointers to function pointers of
// another type. It is not okay to use void*. We create a InvokeFuncStorage
// that that can store our function pointer, and then cast it back to
// the original type on usage.
using InvokeFuncStorage = void(*)();
using InvokeFuncStorage = BindStateBase::InvokeFuncStorage;
// Returns true if this callback equals |other|. |other| may be null.
bool Equals(const CallbackBase& other) const;
bool EqualsInternal(const CallbackBase& other) const;
// Allow initializing of |bind_state_| via the constructor to avoid default
// initialization of the scoped_refptr. We do not also initialize
// |polymorphic_invoke_| here because doing a normal assignment in the
// derived Callback templates makes for much nicer compiler errors.
// initialization of the scoped_refptr.
explicit CallbackBase(BindStateBase* bind_state);
InvokeFuncStorage polymorphic_invoke() const {
return bind_state_->polymorphic_invoke_;
}
// Force the destructor to be instantiated inside this translation unit so
// that our subclasses will not get inlined versions. Avoids more template
// bloat.
~CallbackBase();
scoped_refptr<BindStateBase> bind_state_;
InvokeFuncStorage polymorphic_invoke_;
};
// A helper template to determine if given type is non-const move-only-type,
// i.e. if a value of the given type should be passed via std::move() in a
// destructive way. Types are considered to be move-only if they have a
// sentinel MoveOnlyTypeForCPP03 member: a class typically gets this from using
// the DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND macro.
// It would be easy to generalize this trait to all move-only types... but this
// confuses template deduction in VS2013 with certain types such as
// std::unique_ptr.
// TODO(dcheng): Revisit this when Windows switches to VS2015 by default.
template <typename T> struct IsMoveOnlyType {
template <typename U>
static YesType Test(const typename U::MoveOnlyTypeForCPP03*);
template <typename U>
static NoType Test(...);
static const bool value = sizeof((Test<T>(0))) == sizeof(YesType) &&
!is_const<T>::value;
// CallbackBase<Copyable> is a direct base class of Copyable Callbacks.
template <>
class BASE_EXPORT CallbackBase<CopyMode::Copyable>
: public CallbackBase<CopyMode::MoveOnly> {
public:
CallbackBase(const CallbackBase& c);
CallbackBase(CallbackBase&& c);
CallbackBase& operator=(const CallbackBase& c);
CallbackBase& operator=(CallbackBase&& c);
protected:
explicit CallbackBase(BindStateBase* bind_state)
: CallbackBase<CopyMode::MoveOnly>(bind_state) {}
~CallbackBase() {}
};
// Specialization of IsMoveOnlyType so that std::unique_ptr is still considered
// move-only, even without the sentinel member.
template <typename T>
struct IsMoveOnlyType<std::unique_ptr<T>> : std::true_type {};
template <typename>
struct CallbackParamTraitsForMoveOnlyType;
template <typename>
struct CallbackParamTraitsForNonMoveOnlyType;
// TODO(tzik): Use a default parameter once MSVS supports variadic templates
// with default values.
// http://connect.microsoft.com/VisualStudio/feedbackdetail/view/957801/compilation-error-with-variadic-templates
//
// This is a typetraits object that's used to take an argument type, and
// extract a suitable type for storing and forwarding arguments.
//
// In particular, it strips off references, and converts arrays to
// pointers for storage; and it avoids accidentally trying to create a
// "reference of a reference" if the argument is a reference type.
//
// This array type becomes an issue for storage because we are passing bound
// parameters by const reference. In this case, we end up passing an actual
// array type in the initializer list which C++ does not allow. This will
// break passing of C-string literals.
template <typename T>
struct CallbackParamTraits
: std::conditional<IsMoveOnlyType<T>::value,
CallbackParamTraitsForMoveOnlyType<T>,
CallbackParamTraitsForNonMoveOnlyType<T>>::type {
};
template <typename T>
struct CallbackParamTraitsForNonMoveOnlyType {
using ForwardType = const T&;
using StorageType = T;
};
// The Storage should almost be impossible to trigger unless someone manually
// specifies type of the bind parameters. However, in case they do,
// this will guard against us accidentally storing a reference parameter.
//
// The ForwardType should only be used for unbound arguments.
template <typename T>
struct CallbackParamTraitsForNonMoveOnlyType<T&> {
using ForwardType = T&;
using StorageType = T;
};
// Note that for array types, we implicitly add a const in the conversion. This
// means that it is not possible to bind array arguments to functions that take
// a non-const pointer. Trying to specialize the template based on a "const
// T[n]" does not seem to match correctly, so we are stuck with this
// restriction.
template <typename T, size_t n>
struct CallbackParamTraitsForNonMoveOnlyType<T[n]> {
using ForwardType = const T*;
using StorageType = const T*;
};
// See comment for CallbackParamTraits<T[n]>.
template <typename T>
struct CallbackParamTraitsForNonMoveOnlyType<T[]> {
using ForwardType = const T*;
using StorageType = const T*;
};
// Parameter traits for movable-but-not-copyable scopers.
//
// Callback<>/Bind() understands movable-but-not-copyable semantics where
// the type cannot be copied but can still have its state destructively
// transferred (aka. moved) to another instance of the same type by calling a
// helper function. When used with Bind(), this signifies transferal of the
// object's state to the target function.
//
// For these types, the ForwardType must not be a const reference, or a
// reference. A const reference is inappropriate, and would break const
// correctness, because we are implementing a destructive move. A non-const
// reference cannot be used with temporaries which means the result of a
// function or a cast would not be usable with Callback<> or Bind().
template <typename T>
struct CallbackParamTraitsForMoveOnlyType {
using ForwardType = T;
using StorageType = T;
};
// CallbackForward() is a very limited simulation of C++11's std::forward()
// used by the Callback/Bind system for a set of movable-but-not-copyable
// types. It is needed because forwarding a movable-but-not-copyable
// argument to another function requires us to invoke the proper move
// operator to create a rvalue version of the type. The supported types are
// whitelisted below as overloads of the CallbackForward() function. The
// default template compiles out to be a no-op.
//
// In C++11, std::forward would replace all uses of this function. However, it
// is impossible to implement a general std::forward without C++11 due to a lack
// of rvalue references.
//
// In addition to Callback/Bind, this is used by PostTaskAndReplyWithResult to
// simulate std::forward() and forward the result of one Callback as a
// parameter to another callback. This is to support Callbacks that return
// the movable-but-not-copyable types whitelisted above.
template <typename T>
typename std::enable_if<!IsMoveOnlyType<T>::value, T>::type& CallbackForward(
T& t) {
return t;
}
template <typename T>
typename std::enable_if<IsMoveOnlyType<T>::value, T>::type CallbackForward(
T& t) {
return std::move(t);
}
extern template class CallbackBase<CopyMode::MoveOnly>;
extern template class CallbackBase<CopyMode::Copyable>;
} // namespace internal
} // namespace base

View File

@ -100,6 +100,14 @@
#define NOINLINE
#endif
#if COMPILER_GCC && defined(NDEBUG)
#define ALWAYS_INLINE inline __attribute__((__always_inline__))
#elif COMPILER_MSVC && defined(NDEBUG)
#define ALWAYS_INLINE __forceinline
#else
#define ALWAYS_INLINE inline
#endif
// Specify memory alignment for structs, classes, etc.
// Use like:
// class ALIGNAS(16) MyClass { ... }
@ -169,6 +177,15 @@
#define MSAN_CHECK_MEM_IS_INITIALIZED(p, size)
#endif // MEMORY_SANITIZER
// DISABLE_CFI_PERF -- Disable Control Flow Integrity for perf reasons.
#if !defined(DISABLE_CFI_PERF)
#if defined(__clang__) && defined(OFFICIAL_BUILD)
#define DISABLE_CFI_PERF __attribute__((no_sanitize("cfi")))
#else
#define DISABLE_CFI_PERF
#endif
#endif
// Macro useful for writing cross-platform function pointers.
#if !defined(CDECL)
#if defined(OS_WIN)
@ -187,4 +204,20 @@
#endif // defined(COMPILER_GCC)
#endif // !defined(UNLIKELY)
#if !defined(LIKELY)
#if defined(COMPILER_GCC)
#define LIKELY(x) __builtin_expect((x), 1)
#else
#define LIKELY(x) (x)
#endif // defined(COMPILER_GCC)
#endif // !defined(LIKELY)
// Compiler feature-detection.
// clang.llvm.org/docs/LanguageExtensions.html#has-feature-and-has-extension
#if defined(__has_feature)
#define HAS_FEATURE(FEATURE) __has_feature(FEATURE)
#else
#define HAS_FEATURE(FEATURE) 0
#endif
#endif // BASE_COMPILER_SPECIFIC_H_

View File

@ -0,0 +1,73 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_CONTAINERS_ADAPTERS_H_
#define BASE_CONTAINERS_ADAPTERS_H_
#include <stddef.h>
#include <iterator>
#include "base/macros.h"
namespace base {
namespace internal {
// Internal adapter class for implementing base::Reversed.
template <typename T>
class ReversedAdapter {
public:
using Iterator = decltype(static_cast<T*>(nullptr)->rbegin());
explicit ReversedAdapter(T& t) : t_(t) {}
ReversedAdapter(const ReversedAdapter& ra) : t_(ra.t_) {}
// TODO(mdempsky): Once we can use C++14 library features, use std::rbegin
// and std::rend instead, so we can remove the specialization below.
Iterator begin() const { return t_.rbegin(); }
Iterator end() const { return t_.rend(); }
private:
T& t_;
DISALLOW_ASSIGN(ReversedAdapter);
};
template <typename T, size_t N>
class ReversedAdapter<T[N]> {
public:
using Iterator = std::reverse_iterator<T*>;
explicit ReversedAdapter(T (&t)[N]) : t_(t) {}
ReversedAdapter(const ReversedAdapter& ra) : t_(ra.t_) {}
Iterator begin() const { return Iterator(&t_[N]); }
Iterator end() const { return Iterator(&t_[0]); }
private:
T (&t_)[N];
DISALLOW_ASSIGN(ReversedAdapter);
};
} // namespace internal
// Reversed returns a container adapter usable in a range-based "for" statement
// for iterating a reversible container in reverse order.
//
// Example:
//
// std::vector<int> v = ...;
// for (int i : base::Reversed(v)) {
// // iterates through v from back to front
// }
template <typename T>
internal::ReversedAdapter<T> Reversed(T& t) {
return internal::ReversedAdapter<T>(t);
}
} // namespace base
#endif // BASE_CONTAINERS_ADAPTERS_H_

View File

@ -1,281 +1,75 @@
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
//
// Deal with the differences between Microsoft and GNU implemenations
// of hash_map. Allows all platforms to use |base::hash_map| and
// |base::hash_set|.
// eg:
// base::hash_map<int> my_map;
// base::hash_set<int> my_set;
//
// NOTE: It is an explicit non-goal of this class to provide a generic hash
// function for pointers. If you want to hash a pointers to a particular class,
// please define the template specialization elsewhere (for example, in its
// header file) and keep it specific to just pointers to that class. This is
// because identity hashes are not desirable for all types that might show up
// in containers as pointers.
#ifndef BASE_CONTAINERS_HASH_TABLES_H_
#define BASE_CONTAINERS_HASH_TABLES_H_
#include <stddef.h>
#include <stdint.h>
#include <utility>
#include "base/strings/string16.h"
#include "build/build_config.h"
#if defined(COMPILER_MSVC)
#include <cstddef>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#define BASE_HASH_NAMESPACE std
#include "base/hash.h"
#elif defined(COMPILER_GCC)
// This header file is deprecated. Use the corresponding C++11 type
// instead. https://crbug.com/576864
// Use a custom hasher instead.
#define BASE_HASH_NAMESPACE base_hash
// This is a hack to disable the gcc 4.4 warning about hash_map and hash_set
// being deprecated. We can get rid of this when we upgrade to VS2008 and we
// can use <tr1/unordered_map> and <tr1/unordered_set>.
#ifdef __DEPRECATED
#define CHROME_OLD__DEPRECATED __DEPRECATED
#undef __DEPRECATED
#endif
#include <ext/hash_map>
#include <ext/hash_set>
#define BASE_HASH_IMPL_NAMESPACE __gnu_cxx
#include <string>
#ifdef CHROME_OLD__DEPRECATED
#define __DEPRECATED CHROME_OLD__DEPRECATED
#undef CHROME_OLD__DEPRECATED
#endif
namespace BASE_HASH_NAMESPACE {
// The pre-standard hash behaves like C++11's std::hash, except around pointers.
// const char* is specialized to hash the C string and hash functions for
// general T* are missing. Define a BASE_HASH_NAMESPACE::hash which aligns with
// the C++11 behavior.
// A separate hasher which, by default, forwards to std::hash. This is so legacy
// uses of BASE_HASH_NAMESPACE with base::hash_map do not interfere with
// std::hash mid-transition.
template<typename T>
struct hash {
std::size_t operator()(const T& value) const {
return BASE_HASH_IMPL_NAMESPACE::hash<T>()(value);
}
std::size_t operator()(const T& value) const { return std::hash<T>()(value); }
};
template<typename T>
struct hash<T*> {
std::size_t operator()(T* value) const {
return BASE_HASH_IMPL_NAMESPACE::hash<uintptr_t>()(
reinterpret_cast<uintptr_t>(value));
// Use base::IntPairHash from base/hash.h as a custom hasher instead.
template <typename Type1, typename Type2>
struct hash<std::pair<Type1, Type2>> {
std::size_t operator()(std::pair<Type1, Type2> value) const {
return base::HashInts(value.first, value.second);
}
};
// The GNU C++ library provides identity hash functions for many integral types,
// but not for |long long|. This hash function will truncate if |size_t| is
// narrower than |long long|. This is probably good enough for what we will
// use it for.
#define DEFINE_TRIVIAL_HASH(integral_type) \
template<> \
struct hash<integral_type> { \
std::size_t operator()(integral_type value) const { \
return static_cast<std::size_t>(value); \
} \
}
DEFINE_TRIVIAL_HASH(long long);
DEFINE_TRIVIAL_HASH(unsigned long long);
#undef DEFINE_TRIVIAL_HASH
// Implement string hash functions so that strings of various flavors can
// be used as keys in STL maps and sets. The hash algorithm comes from the
// GNU C++ library, in <tr1/functional>. It is duplicated here because GCC
// versions prior to 4.3.2 are unable to compile <tr1/functional> when RTTI
// is disabled, as it is in our build.
#define DEFINE_STRING_HASH(string_type) \
template<> \
struct hash<string_type> { \
std::size_t operator()(const string_type& s) const { \
std::size_t result = 0; \
for (string_type::const_iterator i = s.begin(); i != s.end(); ++i) \
result = (result * 131) + *i; \
return result; \
} \
}
DEFINE_STRING_HASH(std::string);
DEFINE_STRING_HASH(base::string16);
#undef DEFINE_STRING_HASH
} // namespace BASE_HASH_NAMESPACE
#else // COMPILER
#error define BASE_HASH_NAMESPACE for your compiler
#endif // COMPILER
namespace base {
// On MSVC, use the C++11 containers.
#if defined(COMPILER_MSVC)
template<class Key, class T,
class Hash = std::hash<Key>,
class Pred = std::equal_to<Key>,
class Alloc = std::allocator<std::pair<const Key, T>>>
// Use std::unordered_map instead.
template <class Key,
class T,
class Hash = BASE_HASH_NAMESPACE::hash<Key>,
class Pred = std::equal_to<Key>,
class Alloc = std::allocator<std::pair<const Key, T>>>
using hash_map = std::unordered_map<Key, T, Hash, Pred, Alloc>;
template<class Key, class T,
class Hash = std::hash<Key>,
class Pred = std::equal_to<Key>,
class Alloc = std::allocator<std::pair<const Key, T>>>
// Use std::unordered_multimap instead.
template <class Key,
class T,
class Hash = BASE_HASH_NAMESPACE::hash<Key>,
class Pred = std::equal_to<Key>,
class Alloc = std::allocator<std::pair<const Key, T>>>
using hash_multimap = std::unordered_multimap<Key, T, Hash, Pred, Alloc>;
template<class Key,
class Hash = std::hash<Key>,
class Pred = std::equal_to<Key>,
class Alloc = std::allocator<Key>>
// Use std::unordered_multiset instead.
template <class Key,
class Hash = BASE_HASH_NAMESPACE::hash<Key>,
class Pred = std::equal_to<Key>,
class Alloc = std::allocator<Key>>
using hash_multiset = std::unordered_multiset<Key, Hash, Pred, Alloc>;
template<class Key,
class Hash = std::hash<Key>,
class Pred = std::equal_to<Key>,
class Alloc = std::allocator<Key>>
// Use std::unordered_set instead.
template <class Key,
class Hash = BASE_HASH_NAMESPACE::hash<Key>,
class Pred = std::equal_to<Key>,
class Alloc = std::allocator<Key>>
using hash_set = std::unordered_set<Key, Hash, Pred, Alloc>;
#else // !COMPILER_MSVC
// Otherwise, use the pre-standard ones, but override the default hash to match
// C++11.
template<class Key, class T,
class Hash = BASE_HASH_NAMESPACE::hash<Key>,
class Pred = std::equal_to<Key>,
class Alloc = std::allocator<std::pair<const Key, T>>>
using hash_map = BASE_HASH_IMPL_NAMESPACE::hash_map<Key, T, Hash, Pred, Alloc>;
template<class Key, class T,
class Hash = BASE_HASH_NAMESPACE::hash<Key>,
class Pred = std::equal_to<Key>,
class Alloc = std::allocator<std::pair<const Key, T>>>
using hash_multimap =
BASE_HASH_IMPL_NAMESPACE::hash_multimap<Key, T, Hash, Pred, Alloc>;
template<class Key,
class Hash = BASE_HASH_NAMESPACE::hash<Key>,
class Pred = std::equal_to<Key>,
class Alloc = std::allocator<Key>>
using hash_multiset =
BASE_HASH_IMPL_NAMESPACE::hash_multiset<Key, Hash, Pred, Alloc>;
template<class Key,
class Hash = BASE_HASH_NAMESPACE::hash<Key>,
class Pred = std::equal_to<Key>,
class Alloc = std::allocator<Key>>
using hash_set = BASE_HASH_IMPL_NAMESPACE::hash_set<Key, Hash, Pred, Alloc>;
#undef BASE_HASH_IMPL_NAMESPACE
#endif // COMPILER_MSVC
// Implement hashing for pairs of at-most 32 bit integer values.
// When size_t is 32 bits, we turn the 64-bit hash code into 32 bits by using
// multiply-add hashing. This algorithm, as described in
// Theorem 4.3.3 of the thesis "Über die Komplexität der Multiplikation in
// eingeschränkten Branchingprogrammmodellen" by Woelfel, is:
//
// h32(x32, y32) = (h64(x32, y32) * rand_odd64 + rand16 * 2^16) % 2^64 / 2^32
//
// Contact danakj@chromium.org for any questions.
inline std::size_t HashInts32(uint32_t value1, uint32_t value2) {
uint64_t value1_64 = value1;
uint64_t hash64 = (value1_64 << 32) | value2;
if (sizeof(std::size_t) >= sizeof(uint64_t))
return static_cast<std::size_t>(hash64);
uint64_t odd_random = 481046412LL << 32 | 1025306955LL;
uint32_t shift_random = 10121U << 16;
hash64 = hash64 * odd_random + shift_random;
std::size_t high_bits = static_cast<std::size_t>(
hash64 >> (8 * (sizeof(uint64_t) - sizeof(std::size_t))));
return high_bits;
}
// Implement hashing for pairs of up-to 64-bit integer values.
// We use the compound integer hash method to produce a 64-bit hash code, by
// breaking the two 64-bit inputs into 4 32-bit values:
// http://opendatastructures.org/versions/edition-0.1d/ods-java/node33.html#SECTION00832000000000000000
// Then we reduce our result to 32 bits if required, similar to above.
inline std::size_t HashInts64(uint64_t value1, uint64_t value2) {
uint32_t short_random1 = 842304669U;
uint32_t short_random2 = 619063811U;
uint32_t short_random3 = 937041849U;
uint32_t short_random4 = 3309708029U;
uint32_t value1a = static_cast<uint32_t>(value1 & 0xffffffff);
uint32_t value1b = static_cast<uint32_t>((value1 >> 32) & 0xffffffff);
uint32_t value2a = static_cast<uint32_t>(value2 & 0xffffffff);
uint32_t value2b = static_cast<uint32_t>((value2 >> 32) & 0xffffffff);
uint64_t product1 = static_cast<uint64_t>(value1a) * short_random1;
uint64_t product2 = static_cast<uint64_t>(value1b) * short_random2;
uint64_t product3 = static_cast<uint64_t>(value2a) * short_random3;
uint64_t product4 = static_cast<uint64_t>(value2b) * short_random4;
uint64_t hash64 = product1 + product2 + product3 + product4;
if (sizeof(std::size_t) >= sizeof(uint64_t))
return static_cast<std::size_t>(hash64);
uint64_t odd_random = 1578233944LL << 32 | 194370989LL;
uint32_t shift_random = 20591U << 16;
hash64 = hash64 * odd_random + shift_random;
std::size_t high_bits = static_cast<std::size_t>(
hash64 >> (8 * (sizeof(uint64_t) - sizeof(std::size_t))));
return high_bits;
}
template<typename T1, typename T2>
inline std::size_t HashPair(T1 value1, T2 value2) {
// This condition is expected to be compile-time evaluated and optimised away
// in release builds.
if (sizeof(T1) > sizeof(uint32_t) || (sizeof(T2) > sizeof(uint32_t)))
return HashInts64(value1, value2);
return HashInts32(value1, value2);
}
} // namespace base
namespace BASE_HASH_NAMESPACE {
// Implement methods for hashing a pair of integers, so they can be used as
// keys in STL containers.
template<typename Type1, typename Type2>
struct hash<std::pair<Type1, Type2> > {
std::size_t operator()(std::pair<Type1, Type2> value) const {
return base::HashPair(value.first, value.second);
}
};
} // namespace BASE_HASH_NAMESPACE
#undef DEFINE_PAIR_HASH_FUNCTION_START
#undef DEFINE_PAIR_HASH_FUNCTION_END
#endif // BASE_CONTAINERS_HASH_TABLES_H_

View File

@ -7,13 +7,11 @@
#include <limits.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include "base/macros.h"
#include "base/strings/string_piece.h"
#include "build/build_config.h"
#if defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX))
@ -45,11 +43,11 @@ CPU::CPU()
has_ssse3_(false),
has_sse41_(false),
has_sse42_(false),
has_popcnt_(false),
has_avx_(false),
has_avx2_(false),
has_aesni_(false),
has_non_stop_time_stamp_counter_(false),
has_broken_neon_(false),
cpu_vendor_("unknown") {
Initialize();
}
@ -99,7 +97,7 @@ uint64_t _xgetbv(uint32_t xcr) {
#if defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX))
class LazyCpuInfoValue {
public:
LazyCpuInfoValue() : has_broken_neon_(false) {
LazyCpuInfoValue() {
// This function finds the value from /proc/cpuinfo under the key "model
// name" or "Processor". "model name" is used in Linux 3.8 and later (3.7
// and later for arm64) and is shown once per CPU. "Processor" is used in
@ -108,21 +106,6 @@ class LazyCpuInfoValue {
const char kModelNamePrefix[] = "model name\t: ";
const char kProcessorPrefix[] = "Processor\t: ";
// This function also calculates whether we believe that this CPU has a
// broken NEON unit based on these fields from cpuinfo:
unsigned implementer = 0, architecture = 0, variant = 0, part = 0,
revision = 0;
const struct {
const char key[17];
unsigned int* result;
} kUnsignedValues[] = {
{"CPU implementer", &implementer},
{"CPU architecture", &architecture},
{"CPU variant", &variant},
{"CPU part", &part},
{"CPU revision", &revision},
};
std::string contents;
ReadFileToString(FilePath("/proc/cpuinfo"), &contents);
DCHECK(!contents.empty());
@ -138,52 +121,13 @@ class LazyCpuInfoValue {
line.compare(0, strlen(kProcessorPrefix), kProcessorPrefix) == 0)) {
brand_.assign(line.substr(strlen(kModelNamePrefix)));
}
for (size_t i = 0; i < arraysize(kUnsignedValues); i++) {
const char *key = kUnsignedValues[i].key;
const size_t len = strlen(key);
if (line.compare(0, len, key) == 0 &&
line.size() >= len + 1 &&
(line[len] == '\t' || line[len] == ' ' || line[len] == ':')) {
size_t colon_pos = line.find(':', len);
if (colon_pos == std::string::npos) {
continue;
}
const StringPiece line_sp(line);
StringPiece value_sp = line_sp.substr(colon_pos + 1);
while (!value_sp.empty() &&
(value_sp[0] == ' ' || value_sp[0] == '\t')) {
value_sp = value_sp.substr(1);
}
// The string may have leading "0x" or not, so we use strtoul to
// handle that.
char* endptr;
std::string value(value_sp.as_string());
unsigned long int result = strtoul(value.c_str(), &endptr, 0);
if (*endptr == 0 && result <= UINT_MAX) {
*kUnsignedValues[i].result = result;
}
}
}
}
has_broken_neon_ =
implementer == 0x51 &&
architecture == 7 &&
variant == 1 &&
part == 0x4d &&
revision == 0;
}
const std::string& brand() const { return brand_; }
bool has_broken_neon() const { return has_broken_neon_; }
private:
std::string brand_;
bool has_broken_neon_;
DISALLOW_COPY_AND_ASSIGN(LazyCpuInfoValue);
};
@ -234,6 +178,8 @@ void CPU::Initialize() {
has_ssse3_ = (cpu_info[2] & 0x00000200) != 0;
has_sse41_ = (cpu_info[2] & 0x00080000) != 0;
has_sse42_ = (cpu_info[2] & 0x00100000) != 0;
has_popcnt_ = (cpu_info[2] & 0x00800000) != 0;
// AVX instructions will generate an illegal instruction exception unless
// a) they are supported by the CPU,
// b) XSAVE is supported by the CPU and
@ -277,7 +223,6 @@ void CPU::Initialize() {
}
#elif defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX))
cpu_brand_.assign(g_lazy_cpuinfo.Get().brand());
has_broken_neon_ = g_lazy_cpuinfo.Get().has_broken_neon();
#endif
}

View File

@ -46,16 +46,13 @@ class BASE_EXPORT CPU {
bool has_ssse3() const { return has_ssse3_; }
bool has_sse41() const { return has_sse41_; }
bool has_sse42() const { return has_sse42_; }
bool has_popcnt() const { return has_popcnt_; }
bool has_avx() const { return has_avx_; }
bool has_avx2() const { return has_avx2_; }
bool has_aesni() const { return has_aesni_; }
bool has_non_stop_time_stamp_counter() const {
return has_non_stop_time_stamp_counter_;
}
// has_broken_neon is only valid on ARM chips. If true, it indicates that we
// believe that the NEON unit on the current CPU is flawed and cannot execute
// some code. See https://code.google.com/p/chromium/issues/detail?id=341598
bool has_broken_neon() const { return has_broken_neon_; }
IntelMicroArchitecture GetIntelMicroArchitecture() const;
const std::string& cpu_brand() const { return cpu_brand_; }
@ -78,11 +75,11 @@ class BASE_EXPORT CPU {
bool has_ssse3_;
bool has_sse41_;
bool has_sse42_;
bool has_popcnt_;
bool has_avx_;
bool has_avx2_;
bool has_aesni_;
bool has_non_stop_time_stamp_counter_;
bool has_broken_neon_;
std::string cpu_vendor_;
std::string cpu_brand_;
};

View File

@ -13,6 +13,7 @@
#include "build/build_config.h"
#if defined(OS_WIN)
#include "base/win/current_module.h"
#include "base/win/pe_image.h"
#endif // defined(OS_WIN)
@ -56,6 +57,10 @@ void RestartProfilingAfterFork() {
ProfilerRegisterThread();
}
bool IsProfilingSupported() {
return true;
}
#else
void StartProfiling(const std::string& name) {
@ -74,6 +79,10 @@ bool BeingProfiled() {
void RestartProfilingAfterFork() {
}
bool IsProfilingSupported() {
return false;
}
#endif
#if !defined(OS_WIN)
@ -100,9 +109,6 @@ MoveDynamicSymbol GetProfilerMoveDynamicSymbolFunc() {
#else // defined(OS_WIN)
// http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx
extern "C" IMAGE_DOS_HEADER __ImageBase;
bool IsBinaryInstrumented() {
enum InstrumentationCheckState {
UNINITIALIZED,
@ -113,8 +119,7 @@ bool IsBinaryInstrumented() {
static InstrumentationCheckState state = UNINITIALIZED;
if (state == UNINITIALIZED) {
HMODULE this_module = reinterpret_cast<HMODULE>(&__ImageBase);
base::win::PEImage image(this_module);
base::win::PEImage image(CURRENT_MODULE());
// Check to be sure our image is structured as we'd expect.
DCHECK(image.VerifyMagic());
@ -149,8 +154,8 @@ bool FindResolutionFunctionInImports(
FunctionSearchContext* context =
reinterpret_cast<FunctionSearchContext*>(cookie);
DCHECK_NE(static_cast<FunctionSearchContext*>(NULL), context);
DCHECK_EQ(static_cast<FARPROC>(NULL), context->function);
DCHECK(context);
DCHECK(!context->function);
// Our import address table contains pointers to the functions we import
// at this point. Let's retrieve the first such function and use it to
@ -184,8 +189,7 @@ FunctionType FindFunctionInImports(const char* function_name) {
if (!IsBinaryInstrumented())
return NULL;
HMODULE this_module = reinterpret_cast<HMODULE>(&__ImageBase);
base::win::PEImage image(this_module);
base::win::PEImage image(CURRENT_MODULE());
FunctionSearchContext ctx = { function_name, NULL };
image.EnumImportChunks(FindResolutionFunctionInImports, &ctx);

View File

@ -38,6 +38,9 @@ BASE_EXPORT void RestartProfilingAfterFork();
// Returns true iff this executable is instrumented with the Syzygy profiler.
BASE_EXPORT bool IsBinaryInstrumented();
// Returns true iff this executable supports profiling.
BASE_EXPORT bool IsProfilingSupported();
// There's a class of profilers that use "return address swizzling" to get a
// hook on function exits. This class of profilers uses some form of entry hook,
// like e.g. binary instrumentation, or a compiler flag, that calls a hook each

View File

@ -0,0 +1,90 @@
// 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_ENVIRONMENT_H_
#define BASE_ENVIRONMENT_H_
#include <map>
#include <memory>
#include <string>
#include "base/base_export.h"
#include "base/strings/string16.h"
#include "base/strings/string_piece.h"
#include "build/build_config.h"
namespace base {
namespace env_vars {
#if defined(OS_POSIX)
BASE_EXPORT extern const char kHome[];
#endif
} // namespace env_vars
class BASE_EXPORT Environment {
public:
virtual ~Environment();
// Returns the appropriate platform-specific instance.
static std::unique_ptr<Environment> Create();
// Gets an environment variable's value and stores it in |result|.
// Returns false if the key is unset.
virtual bool GetVar(StringPiece variable_name, std::string* result) = 0;
// Syntactic sugar for GetVar(variable_name, nullptr);
virtual bool HasVar(StringPiece variable_name);
// Returns true on success, otherwise returns false.
virtual bool SetVar(StringPiece variable_name,
const std::string& new_value) = 0;
// Returns true on success, otherwise returns false.
virtual bool UnSetVar(StringPiece variable_name) = 0;
};
#if defined(OS_WIN)
typedef string16 NativeEnvironmentString;
typedef std::map<NativeEnvironmentString, NativeEnvironmentString>
EnvironmentMap;
// Returns a modified environment vector constructed from the given environment
// and the list of changes given in |changes|. Each key in the environment is
// matched against the first element of the pairs. In the event of a match, the
// value is replaced by the second of the pair, unless the second is empty, in
// which case the key-value is removed.
//
// This Windows version takes and returns a Windows-style environment block
// which is a concatenated list of null-terminated 16-bit strings. The end is
// marked by a double-null terminator. The size of the returned string will
// include the terminators.
BASE_EXPORT string16 AlterEnvironment(const wchar_t* env,
const EnvironmentMap& changes);
#elif defined(OS_POSIX)
typedef std::string NativeEnvironmentString;
typedef std::map<NativeEnvironmentString, NativeEnvironmentString>
EnvironmentMap;
// See general comments for the Windows version above.
//
// This Posix version takes and returns a Posix-style environment block, which
// is a null-terminated list of pointers to null-terminated strings. The
// returned array will have appended to it the storage for the array itself so
// there is only one pointer to manage, but this means that you can't copy the
// array without keeping the original around.
BASE_EXPORT std::unique_ptr<char* []> AlterEnvironment(
const char* const* env,
const EnvironmentMap& changes);
#endif
} // namespace base
#endif // BASE_ENVIRONMENT_H_

View File

@ -138,6 +138,7 @@ namespace base {
class Pickle;
class PickleIterator;
class PickleSizer;
// An abstraction to isolate users from the differences between native
// pathnames on different platforms.
@ -372,11 +373,12 @@ class BASE_EXPORT FilePath {
// internally calls SysWideToNativeMB() on POSIX systems other than Mac
// and Chrome OS, to mitigate the encoding issue. See the comment at
// AsUTF8Unsafe() for details.
static FilePath FromUTF8Unsafe(const std::string& utf8);
static FilePath FromUTF8Unsafe(StringPiece utf8);
// Similar to FromUTF8Unsafe, but accepts UTF-16 instead.
static FilePath FromUTF16Unsafe(const string16& utf16);
static FilePath FromUTF16Unsafe(StringPiece16 utf16);
void GetSizeForPickle(PickleSizer* sizer) const;
void WriteToPickle(Pickle* pickle) const;
bool ReadFromPickle(PickleIterator* iter);

View File

@ -10,23 +10,33 @@
#include <string>
#include "base/base_export.h"
#include "base/strings/string_piece.h"
#include "build/build_config.h"
namespace base {
// Generate a 128-bit random GUID of the form: "%08X-%04X-%04X-%04X-%012llX".
// Generate a 128-bit (pseudo) random GUID in the form of version 4 as described
// in RFC 4122, section 4.4.
// The format of GUID version 4 must be xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx,
// where y is one of [8, 9, A, B].
// The hexadecimal values "a" through "f" are output as lower case characters.
// If GUID generation fails an empty string is returned.
// The POSIX implementation uses pseudo random number generation to create
// the GUID. The Windows implementation uses system services.
BASE_EXPORT std::string GenerateGUID();
// Returns true if the input string conforms to the GUID format.
BASE_EXPORT bool IsValidGUID(const std::string& guid);
// Returns true if the input string conforms to the version 4 GUID format.
// Note that this does NOT check if the hexadecimal values "a" through "f"
// are in lower case characters, as Version 4 RFC says onput they're
// case insensitive. (Use IsValidGUIDOutputString for checking if the
// given string is valid output string)
BASE_EXPORT bool IsValidGUID(const base::StringPiece& guid);
// Returns true if the input string is valid version 4 GUID output string.
// This also checks if the hexadecimal values "a" through "f" are in lower
// case characters.
BASE_EXPORT bool IsValidGUIDOutputString(const base::StringPiece& guid);
#if defined(OS_POSIX)
// For unit testing purposes only. Do not use outside of tests.
BASE_EXPORT std::string RandomDataToGUIDString(const uint64_t bytes[2]);
#endif
} // namespace base

View File

@ -11,8 +11,12 @@ extern "C" uint32_t SuperFastHash(const char* data, int len);
namespace base {
uint32_t SuperFastHash(const char* data, int len) {
return ::SuperFastHash(data, len);
uint32_t SuperFastHash(const char* data, size_t length) {
if (length > static_cast<size_t>(std::numeric_limits<int>::max())) {
NOTREACHED();
return 0;
}
return ::SuperFastHash(data, static_cast<int>(length));
}
} // namespace base

View File

@ -10,6 +10,7 @@
#include <limits>
#include <string>
#include <utility>
#include "base/base_export.h"
#include "base/logging.h"
@ -17,16 +18,12 @@
namespace base {
// WARNING: This hash function should not be used for any cryptographic purpose.
BASE_EXPORT uint32_t SuperFastHash(const char* data, int len);
BASE_EXPORT uint32_t SuperFastHash(const char* data, size_t length);
// Computes a hash of a memory buffer |data| of a given |length|.
// WARNING: This hash function should not be used for any cryptographic purpose.
inline uint32_t Hash(const char* data, size_t length) {
if (length > static_cast<size_t>(std::numeric_limits<int>::max())) {
NOTREACHED();
return 0;
}
return SuperFastHash(data, static_cast<int>(length));
return SuperFastHash(data, length);
}
// Computes a hash of a string |str|.
@ -35,6 +32,87 @@ inline uint32_t Hash(const std::string& str) {
return Hash(str.data(), str.size());
}
// Implement hashing for pairs of at-most 32 bit integer values.
// When size_t is 32 bits, we turn the 64-bit hash code into 32 bits by using
// multiply-add hashing. This algorithm, as described in
// Theorem 4.3.3 of the thesis "Über die Komplexität der Multiplikation in
// eingeschränkten Branchingprogrammmodellen" by Woelfel, is:
//
// h32(x32, y32) = (h64(x32, y32) * rand_odd64 + rand16 * 2^16) % 2^64 / 2^32
//
// Contact danakj@chromium.org for any questions.
inline size_t HashInts32(uint32_t value1, uint32_t value2) {
uint64_t value1_64 = value1;
uint64_t hash64 = (value1_64 << 32) | value2;
if (sizeof(size_t) >= sizeof(uint64_t))
return static_cast<size_t>(hash64);
uint64_t odd_random = 481046412LL << 32 | 1025306955LL;
uint32_t shift_random = 10121U << 16;
hash64 = hash64 * odd_random + shift_random;
size_t high_bits =
static_cast<size_t>(hash64 >> (8 * (sizeof(uint64_t) - sizeof(size_t))));
return high_bits;
}
// Implement hashing for pairs of up-to 64-bit integer values.
// We use the compound integer hash method to produce a 64-bit hash code, by
// breaking the two 64-bit inputs into 4 32-bit values:
// http://opendatastructures.org/versions/edition-0.1d/ods-java/node33.html#SECTION00832000000000000000
// Then we reduce our result to 32 bits if required, similar to above.
inline size_t HashInts64(uint64_t value1, uint64_t value2) {
uint32_t short_random1 = 842304669U;
uint32_t short_random2 = 619063811U;
uint32_t short_random3 = 937041849U;
uint32_t short_random4 = 3309708029U;
uint32_t value1a = static_cast<uint32_t>(value1 & 0xffffffff);
uint32_t value1b = static_cast<uint32_t>((value1 >> 32) & 0xffffffff);
uint32_t value2a = static_cast<uint32_t>(value2 & 0xffffffff);
uint32_t value2b = static_cast<uint32_t>((value2 >> 32) & 0xffffffff);
uint64_t product1 = static_cast<uint64_t>(value1a) * short_random1;
uint64_t product2 = static_cast<uint64_t>(value1b) * short_random2;
uint64_t product3 = static_cast<uint64_t>(value2a) * short_random3;
uint64_t product4 = static_cast<uint64_t>(value2b) * short_random4;
uint64_t hash64 = product1 + product2 + product3 + product4;
if (sizeof(size_t) >= sizeof(uint64_t))
return static_cast<size_t>(hash64);
uint64_t odd_random = 1578233944LL << 32 | 194370989LL;
uint32_t shift_random = 20591U << 16;
hash64 = hash64 * odd_random + shift_random;
size_t high_bits =
static_cast<size_t>(hash64 >> (8 * (sizeof(uint64_t) - sizeof(size_t))));
return high_bits;
}
template <typename T1, typename T2>
inline size_t HashInts(T1 value1, T2 value2) {
// This condition is expected to be compile-time evaluated and optimised away
// in release builds.
if (sizeof(T1) > sizeof(uint32_t) || (sizeof(T2) > sizeof(uint32_t)))
return HashInts64(value1, value2);
return HashInts32(value1, value2);
}
// A templated hasher for pairs of integer types.
template <typename T>
struct IntPairHash;
template <typename Type1, typename Type2>
struct IntPairHash<std::pair<Type1, Type2>> {
size_t operator()(std::pair<Type1, Type2> value) const {
return HashInts(value.first, value.second);
}
};
} // namespace base
#endif // BASE_HASH_H_

View File

@ -55,7 +55,7 @@ namespace base {
template <typename Type>
struct DefaultLazyInstanceTraits {
static const bool kRegisterOnExit = true;
#ifndef NDEBUG
#if DCHECK_IS_ON()
static const bool kAllowedToAccessOnNonjoinableThread = false;
#endif
@ -89,7 +89,7 @@ namespace internal {
template <typename Type>
struct LeakyLazyInstanceTraits {
static const bool kRegisterOnExit = false;
#ifndef NDEBUG
#if DCHECK_IS_ON()
static const bool kAllowedToAccessOnNonjoinableThread = true;
#endif
@ -102,7 +102,7 @@ struct LeakyLazyInstanceTraits {
};
// Our AtomicWord doubles as a spinlock, where a value of
// kBeingCreatedMarker means the spinlock is being held for creation.
// kLazyInstanceStateCreating means the spinlock is being held for creation.
static const subtle::AtomicWord kLazyInstanceStateCreating = 1;
// Check if instance needs to be created. If so return true otherwise
@ -138,7 +138,7 @@ class LazyInstance {
}
Type* Pointer() {
#ifndef NDEBUG
#if DCHECK_IS_ON()
// Avoid making TLS lookup on release builds.
if (!Traits::kAllowedToAccessOnNonjoinableThread)
ThreadRestrictions::AssertSingletonAllowed();

View File

@ -11,7 +11,7 @@
#include <string>
#include "base/base_export.h"
#include "base/containers/hash_tables.h"
#include "base/hash.h"
namespace tracked_objects {
@ -59,7 +59,7 @@ class BASE_EXPORT Location {
// it comes from __FILE__, so no need to check the contents of the string.
// See the definition of FROM_HERE in location.h, and how it is used
// elsewhere.
return base::HashPair(reinterpret_cast<uintptr_t>(location.file_name()),
return base::HashInts(reinterpret_cast<uintptr_t>(location.file_name()),
location.line_number());
}
};
@ -97,7 +97,7 @@ struct BASE_EXPORT LocationSnapshot {
BASE_EXPORT const void* GetProgramCounter();
// Define a macro to record the current source location.
#define FROM_HERE FROM_HERE_WITH_EXPLICIT_FUNCTION(__FUNCTION__)
#define FROM_HERE FROM_HERE_WITH_EXPLICIT_FUNCTION(__func__)
#define FROM_HERE_WITH_EXPLICIT_FUNCTION(function_name) \
::tracked_objects::Location(function_name, \

View File

@ -11,10 +11,13 @@
#include <cstring>
#include <sstream>
#include <string>
#include <type_traits>
#include <utility>
#include "base/base_export.h"
#include "base/debug/debugger.h"
#include "base/macros.h"
#include "base/template_util.h"
#include "build/build_config.h"
//
@ -306,15 +309,16 @@ const LogSeverity LOG_DFATAL = LOG_FATAL;
// by LOG() and LOG_IF, etc. Since these are used all over our code, it's
// better to have compact code for these operations.
#define COMPACT_GOOGLE_LOG_EX_INFO(ClassName, ...) \
logging::ClassName(__FILE__, __LINE__, logging::LOG_INFO , ##__VA_ARGS__)
#define COMPACT_GOOGLE_LOG_EX_WARNING(ClassName, ...) \
logging::ClassName(__FILE__, __LINE__, logging::LOG_WARNING , ##__VA_ARGS__)
::logging::ClassName(__FILE__, __LINE__, ::logging::LOG_INFO, ##__VA_ARGS__)
#define COMPACT_GOOGLE_LOG_EX_WARNING(ClassName, ...) \
::logging::ClassName(__FILE__, __LINE__, ::logging::LOG_WARNING, \
##__VA_ARGS__)
#define COMPACT_GOOGLE_LOG_EX_ERROR(ClassName, ...) \
logging::ClassName(__FILE__, __LINE__, logging::LOG_ERROR , ##__VA_ARGS__)
::logging::ClassName(__FILE__, __LINE__, ::logging::LOG_ERROR, ##__VA_ARGS__)
#define COMPACT_GOOGLE_LOG_EX_FATAL(ClassName, ...) \
logging::ClassName(__FILE__, __LINE__, logging::LOG_FATAL , ##__VA_ARGS__)
::logging::ClassName(__FILE__, __LINE__, ::logging::LOG_FATAL, ##__VA_ARGS__)
#define COMPACT_GOOGLE_LOG_EX_DFATAL(ClassName, ...) \
logging::ClassName(__FILE__, __LINE__, logging::LOG_DFATAL , ##__VA_ARGS__)
::logging::ClassName(__FILE__, __LINE__, ::logging::LOG_DFATAL, ##__VA_ARGS__)
#define COMPACT_GOOGLE_LOG_INFO \
COMPACT_GOOGLE_LOG_EX_INFO(LogMessage)
@ -373,12 +377,9 @@ const LogSeverity LOG_0 = LOG_ERROR;
#define LOG_IF(severity, condition) \
LAZY_STREAM(LOG_STREAM(severity), LOG_IS_ON(severity) && (condition))
#define SYSLOG(severity) LOG(severity)
#define SYSLOG_IF(severity, condition) LOG_IF(severity, condition)
// The VLOG macros log with negative verbosities.
#define VLOG_STREAM(verbose_level) \
logging::LogMessage(__FILE__, __LINE__, -verbose_level).stream()
::logging::LogMessage(__FILE__, __LINE__, -verbose_level).stream()
#define VLOG(verbose_level) \
LAZY_STREAM(VLOG_STREAM(verbose_level), VLOG_IS_ON(verbose_level))
@ -389,11 +390,11 @@ const LogSeverity LOG_0 = LOG_ERROR;
#if defined (OS_WIN)
#define VPLOG_STREAM(verbose_level) \
logging::Win32ErrorLogMessage(__FILE__, __LINE__, -verbose_level, \
::logging::Win32ErrorLogMessage(__FILE__, __LINE__, -verbose_level, \
::logging::GetLastSystemErrorCode()).stream()
#elif defined(OS_POSIX)
#define VPLOG_STREAM(verbose_level) \
logging::ErrnoLogMessage(__FILE__, __LINE__, -verbose_level, \
::logging::ErrnoLogMessage(__FILE__, __LINE__, -verbose_level, \
::logging::GetLastSystemErrorCode()).stream()
#endif
@ -408,8 +409,6 @@ const LogSeverity LOG_0 = LOG_ERROR;
#define LOG_ASSERT(condition) \
LOG_IF(FATAL, !(condition)) << "Assert failed: " #condition ". "
#define SYSLOG_ASSERT(condition) \
SYSLOG_IF(FATAL, !(condition)) << "Assert failed: " #condition ". "
#if defined(OS_WIN)
#define PLOG_STREAM(severity) \
@ -435,7 +434,7 @@ const LogSeverity LOG_0 = LOG_ERROR;
// boolean.
class CheckOpResult {
public:
// |message| must be null if and only if the check failed.
// |message| must be non-null if and only if the check failed.
CheckOpResult(std::string* message) : message_(message) {}
// Returns true if the check succeeded.
operator bool() const { return !message_; }
@ -453,22 +452,28 @@ class CheckOpResult {
// We make sure CHECK et al. always evaluates their arguments, as
// doing CHECK(FunctionWithSideEffect()) is a common idiom.
#if defined(OFFICIAL_BUILD) && defined(NDEBUG) && !defined(OS_ANDROID)
#if defined(OFFICIAL_BUILD) && defined(NDEBUG)
// Make all CHECK functions discard their log strings to reduce code
// bloat for official release builds (except Android).
// bloat, and improve performance, for official release builds.
// TODO(akalin): This would be more valuable if there were some way to
// remove BreakDebugger() from the backtrace, perhaps by turning it
// into a macro (like __debugbreak() on Windows).
#if defined(COMPILER_GCC) || __clang__
#define LOGGING_CRASH() __builtin_trap()
#else
#define LOGGING_CRASH() ((void)(*(volatile char*)0 = 0))
#endif
// This is not calling BreakDebugger since this is called frequently, and
// calling an out-of-line function instead of a noreturn inline macro prevents
// compiler optimizations.
#define CHECK(condition) \
!(condition) ? ::base::debug::BreakDebugger() : EAT_STREAM_PARAMETERS
!(condition) ? LOGGING_CRASH() : EAT_STREAM_PARAMETERS
#define PCHECK(condition) CHECK(condition)
#define CHECK_OP(name, op, val1, val2) CHECK((val1) op (val2))
#else
#else // !(OFFICIAL_BUILD && NDEBUG)
#if defined(_PREFAST_) && defined(OS_WIN)
// Use __analysis_assume to tell the VC++ static analysis engine that
@ -491,8 +496,8 @@ class CheckOpResult {
#else // _PREFAST_
// Do as much work as possible out of line to reduce inline code size.
#define CHECK(condition) \
LAZY_STREAM(logging::LogMessage(__FILE__, __LINE__, #condition).stream(), \
#define CHECK(condition) \
LAZY_STREAM(::logging::LogMessage(__FILE__, __LINE__, #condition).stream(), \
!(condition))
#define PCHECK(condition) \
@ -509,14 +514,38 @@ class CheckOpResult {
// CHECK_EQ(2, a);
#define CHECK_OP(name, op, val1, val2) \
switch (0) case 0: default: \
if (logging::CheckOpResult true_if_passed = \
logging::Check##name##Impl((val1), (val2), \
#val1 " " #op " " #val2)) \
if (::logging::CheckOpResult true_if_passed = \
::logging::Check##name##Impl((val1), (val2), \
#val1 " " #op " " #val2)) \
; \
else \
logging::LogMessage(__FILE__, __LINE__, true_if_passed.message()).stream()
::logging::LogMessage(__FILE__, __LINE__, true_if_passed.message()).stream()
#endif
#endif // !(OFFICIAL_BUILD && NDEBUG)
// This formats a value for a failing CHECK_XX statement. Ordinarily,
// it uses the definition for operator<<, with a few special cases below.
template <typename T>
inline typename std::enable_if<
base::internal::SupportsOstreamOperator<const T&>::value,
void>::type
MakeCheckOpValueString(std::ostream* os, const T& v) {
(*os) << v;
}
// We need overloads for enums that don't support operator<<.
// (i.e. scoped enums where no operator<< overload was declared).
template <typename T>
inline typename std::enable_if<
!base::internal::SupportsOstreamOperator<const T&>::value &&
std::is_enum<T>::value,
void>::type
MakeCheckOpValueString(std::ostream* os, const T& v) {
(*os) << static_cast<typename base::underlying_type<T>::type>(v);
}
// We need an explicit overload for std::nullptr_t.
BASE_EXPORT void MakeCheckOpValueString(std::ostream* os, std::nullptr_t p);
// Build the error message string. This is separate from the "Impl"
// function template because it is not performance critical and so can
@ -525,7 +554,11 @@ class CheckOpResult {
template<class t1, class t2>
std::string* MakeCheckOpString(const t1& v1, const t2& v2, const char* names) {
std::ostringstream ss;
ss << names << " (" << v1 << " vs. " << v2 << ")";
ss << names << " (";
MakeCheckOpValueString(&ss, v1);
ss << " vs. ";
MakeCheckOpValueString(&ss, v2);
ss << ")";
std::string* msg = new std::string(ss.str());
return msg;
}
@ -556,11 +589,11 @@ std::string* MakeCheckOpString<std::string, std::string>(
inline std::string* Check##name##Impl(const t1& v1, const t2& v2, \
const char* names) { \
if (v1 op v2) return NULL; \
else return MakeCheckOpString(v1, v2, names); \
else return ::logging::MakeCheckOpString(v1, v2, names); \
} \
inline std::string* Check##name##Impl(int v1, int v2, const char* names) { \
if (v1 op v2) return NULL; \
else return MakeCheckOpString(v1, v2, names); \
else return ::logging::MakeCheckOpString(v1, v2, names); \
}
DEFINE_CHECK_OP_IMPL(EQ, ==)
DEFINE_CHECK_OP_IMPL(NE, !=)
@ -577,12 +610,6 @@ DEFINE_CHECK_OP_IMPL(GT, > )
#define CHECK_GE(val1, val2) CHECK_OP(GE, >=, val1, val2)
#define CHECK_GT(val1, val2) CHECK_OP(GT, > , val1, val2)
#if defined(NDEBUG)
#define ENABLE_DLOG 0
#else
#define ENABLE_DLOG 1
#endif
#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
#define DCHECK_IS_ON() 0
#else
@ -591,7 +618,7 @@ DEFINE_CHECK_OP_IMPL(GT, > )
// Definitions for DLOG et al.
#if ENABLE_DLOG
#if DCHECK_IS_ON()
#define DLOG_IS_ON(severity) LOG_IS_ON(severity)
#define DLOG_IF(severity, condition) LOG_IF(severity, condition)
@ -600,12 +627,11 @@ DEFINE_CHECK_OP_IMPL(GT, > )
#define DVLOG_IF(verboselevel, condition) VLOG_IF(verboselevel, condition)
#define DVPLOG_IF(verboselevel, condition) VPLOG_IF(verboselevel, condition)
#else // ENABLE_DLOG
#else // DCHECK_IS_ON()
// If ENABLE_DLOG is off, we want to avoid emitting any references to
// |condition| (which may reference a variable defined only if NDEBUG
// is not defined). Contrast this with DCHECK et al., which has
// different behavior.
// If !DCHECK_IS_ON(), we want to avoid emitting any references to |condition|
// (which may reference a variable defined only if DCHECK_IS_ON()).
// Contrast this with DCHECK et al., which has different behavior.
#define DLOG_IS_ON(severity) false
#define DLOG_IF(severity, condition) EAT_STREAM_PARAMETERS
@ -614,19 +640,14 @@ DEFINE_CHECK_OP_IMPL(GT, > )
#define DVLOG_IF(verboselevel, condition) EAT_STREAM_PARAMETERS
#define DVPLOG_IF(verboselevel, condition) EAT_STREAM_PARAMETERS
#endif // ENABLE_DLOG
#endif // DCHECK_IS_ON()
// DEBUG_MODE is for uses like
// DEBUG_MODE is for runtime uses like
// if (DEBUG_MODE) foo.CheckThatFoo();
// instead of
// #ifndef NDEBUG
// foo.CheckThatFoo();
// #endif
// We tie its state to DCHECK_IS_ON().
//
// We tie its state to ENABLE_DLOG.
enum { DEBUG_MODE = ENABLE_DLOG };
#undef ENABLE_DLOG
// For compile-time checks, #if DCHECK_IS_ON() can be used.
enum { DEBUG_MODE = DCHECK_IS_ON() };
#define DLOG(severity) \
LAZY_STREAM(LOG_STREAM(severity), DLOG_IS_ON(severity))
@ -693,16 +714,16 @@ const LogSeverity LOG_DCHECK = LOG_INFO;
// macro is used in an 'if' clause such as:
// if (a == 1)
// DCHECK_EQ(2, a);
#define DCHECK_OP(name, op, val1, val2) \
switch (0) case 0: default: \
if (logging::CheckOpResult true_if_passed = \
DCHECK_IS_ON() ? \
logging::Check##name##Impl((val1), (val2), \
#val1 " " #op " " #val2) : nullptr) \
; \
else \
logging::LogMessage(__FILE__, __LINE__, ::logging::LOG_DCHECK, \
true_if_passed.message()).stream()
#define DCHECK_OP(name, op, val1, val2) \
switch (0) case 0: default: \
if (::logging::CheckOpResult true_if_passed = \
DCHECK_IS_ON() ? \
::logging::Check##name##Impl((val1), (val2), \
#val1 " " #op " " #val2) : nullptr) \
; \
else \
::logging::LogMessage(__FILE__, __LINE__, ::logging::LOG_DCHECK, \
true_if_passed.message()).stream()
// Equality/Inequality checks - compare two values, and log a
// LOG_DCHECK message including the two values when the result is not
@ -710,7 +731,7 @@ const LogSeverity LOG_DCHECK = LOG_INFO;
// defined.
//
// You may append to the error message like so:
// DCHECK_NE(1, 2) << ": The world must be ending!";
// DCHECK_NE(1, 2) << "The world must be ending!";
//
// We are very careful to ensure that each argument is evaluated exactly
// once, and that anything which is legal to pass as a function argument is
@ -719,9 +740,10 @@ const LogSeverity LOG_DCHECK = LOG_INFO;
// for example:
// DCHECK_EQ(string("abc")[1], 'b');
//
// WARNING: These may not compile correctly if one of the arguments is a pointer
// and the other is NULL. To work around this, simply static_cast NULL to the
// type of the desired pointer.
// WARNING: These don't compile correctly if one of the arguments is a pointer
// and the other is NULL. In new code, prefer nullptr instead. To
// work around this for C++98, simply static_cast NULL to the type of the
// desired pointer.
#define DCHECK_EQ(val1, val2) DCHECK_OP(EQ, ==, val1, val2)
#define DCHECK_NE(val1, val2) DCHECK_OP(NE, !=, val1, val2)
@ -773,6 +795,9 @@ class BASE_EXPORT LogMessage {
std::ostream& stream() { return stream_; }
LogSeverity severity() { return severity_; }
std::string str() { return stream_.str(); }
private:
void Init(const char* file, int line);
@ -807,12 +832,6 @@ class BASE_EXPORT LogMessage {
DISALLOW_COPY_AND_ASSIGN(LogMessage);
};
// A non-macro interface to the log facility; (useful
// when the logging level is not a compile-time constant).
inline void LogAtLevel(int log_level, const std::string& msg) {
LogMessage(__FILE__, __LINE__, log_level).stream() << msg;
}
// This class is used to explicitly ignore values in the conditional
// logging macros. This avoids compiler warnings like "value computed
// is not used" and "statement has no effect".
@ -886,12 +905,14 @@ BASE_EXPORT void CloseLogFile();
// Async signal safe logging mechanism.
BASE_EXPORT void RawLog(int level, const char* message);
#define RAW_LOG(level, message) logging::RawLog(logging::LOG_ ## level, message)
#define RAW_LOG(level, message) \
::logging::RawLog(::logging::LOG_##level, message)
#define RAW_CHECK(condition) \
do { \
if (!(condition)) \
logging::RawLog(logging::LOG_FATAL, "Check failed: " #condition "\n"); \
#define RAW_CHECK(condition) \
do { \
if (!(condition)) \
::logging::RawLog(::logging::LOG_FATAL, \
"Check failed: " #condition "\n"); \
} while (0)
#if defined(OS_WIN)

View File

@ -20,11 +20,11 @@
#define DISALLOW_ASSIGN(TypeName) \
void operator=(const TypeName&) = delete
// A macro to disallow the copy constructor and operator= functions
// This should be used in the private: declarations for a class
// A macro to disallow the copy constructor and operator= functions.
// This should be used in the private: declarations for a class.
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&); \
void operator=(const TypeName&)
TypeName(const TypeName&) = delete; \
void operator=(const TypeName&) = delete
// A macro to disallow all the implicit constructors, namely the
// default constructor, copy constructor and operator= functions.
@ -52,7 +52,7 @@ template <typename T, size_t N> char (&ArraySizeHelper(T (&array)[N]))[N];
// really sure you don't want to do anything with the return value of a function
// that has been marked WARN_UNUSED_RESULT, wrap it with this. Example:
//
// scoped_ptr<MyType> my_var = ...;
// std::unique_ptr<MyType> my_var = ...;
// if (TakeOwnership(my_var.get()) == SUCCESS)
// ignore_result(my_var.release());
//

View File

@ -26,9 +26,9 @@
// // ... later, to release the memory:
// AlignedFree(my_array);
//
// Or using scoped_ptr:
// Or using unique_ptr:
//
// scoped_ptr<float, AlignedFreeDeleter> my_array(
// std::unique_ptr<float, AlignedFreeDeleter> my_array(
// static_cast<float*>(AlignedAlloc(size, alignment)));
#ifndef BASE_MEMORY_ALIGNED_MEMORY_H_
@ -104,8 +104,8 @@ inline void AlignedFree(void* ptr) {
#endif
}
// Deleter for use with scoped_ptr. E.g., use as
// scoped_ptr<Foo, base::AlignedFreeDeleter> foo;
// Deleter for use with unique_ptr. E.g., use as
// std::unique_ptr<Foo, base::AlignedFreeDeleter> foo;
struct AlignedFreeDeleter {
inline void operator()(void* ptr) const {
AlignedFree(ptr);

View File

@ -0,0 +1,25 @@
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_MEMORY_FREE_DELETER_H_
#define BASE_MEMORY_FREE_DELETER_H_
#include <stdlib.h>
namespace base {
// Function object which invokes 'free' on its parameter, which must be
// a pointer. Can be used to store malloc-allocated pointers in std::unique_ptr:
//
// std::unique_ptr<int, base::FreeDeleter> foo_ptr(
// static_cast<int*>(malloc(sizeof(int))));
struct FreeDeleter {
inline void operator()(void* ptr) const {
free(ptr);
}
};
} // namespace base
#endif // BASE_MEMORY_FREE_DELETER_H_

View File

@ -0,0 +1,74 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_MEMORY_PTR_UTIL_H_
#define BASE_MEMORY_PTR_UTIL_H_
#include <memory>
#include <utility>
namespace base {
// Helper to transfer ownership of a raw pointer to a std::unique_ptr<T>.
// Note that std::unique_ptr<T> has very different semantics from
// std::unique_ptr<T[]>: do not use this helper for array allocations.
template <typename T>
std::unique_ptr<T> WrapUnique(T* ptr) {
return std::unique_ptr<T>(ptr);
}
namespace internal {
template <typename T>
struct MakeUniqueResult {
using Scalar = std::unique_ptr<T>;
};
template <typename T>
struct MakeUniqueResult<T[]> {
using Array = std::unique_ptr<T[]>;
};
template <typename T, size_t N>
struct MakeUniqueResult<T[N]> {
using Invalid = void;
};
} // namespace internal
// Helper to construct an object wrapped in a std::unique_ptr. This is an
// implementation of C++14's std::make_unique that can be used in Chrome.
//
// MakeUnique<T>(args) should be preferred over WrapUnique(new T(args)): bare
// calls to `new` should be treated with scrutiny.
//
// Usage:
// // ptr is a std::unique_ptr<std::string>
// auto ptr = MakeUnique<std::string>("hello world!");
//
// // arr is a std::unique_ptr<int[]>
// auto arr = MakeUnique<int[]>(5);
// Overload for non-array types. Arguments are forwarded to T's constructor.
template <typename T, typename... Args>
typename internal::MakeUniqueResult<T>::Scalar MakeUnique(Args&&... args) {
return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
// Overload for array types of unknown bound, e.g. T[]. The array is allocated
// with `new T[n]()` and value-initialized: note that this is distinct from
// `new T[n]`, which default-initializes.
template <typename T>
typename internal::MakeUniqueResult<T>::Array MakeUnique(size_t size) {
return std::unique_ptr<T>(new typename std::remove_extent<T>::type[size]());
}
// Overload to reject array types of known bound, e.g. T[n].
template <typename T, typename... Args>
typename internal::MakeUniqueResult<T>::Invalid MakeUnique(Args&&... args) =
delete;
} // namespace base
#endif // BASE_MEMORY_PTR_UTIL_H_

View File

@ -5,10 +5,10 @@
#ifndef BASE_MEMORY_RAW_SCOPED_REFPTR_MISMATCH_CHECKER_H_
#define BASE_MEMORY_RAW_SCOPED_REFPTR_MISMATCH_CHECKER_H_
#include <tuple>
#include <type_traits>
#include "base/memory/ref_counted.h"
#include "base/template_util.h"
#include "base/tuple.h"
#include "build/build_config.h"
// It is dangerous to post a task with a T* argument where T is a subtype of
// RefCounted(Base|ThreadSafeBase), since by the time the parameter is used, the
@ -25,20 +25,14 @@ namespace internal {
template <typename T>
struct NeedsScopedRefptrButGetsRawPtr {
#if defined(OS_WIN)
enum {
value = base::false_type::value
};
#else
enum {
// Human readable translation: you needed to be a scoped_refptr if you are a
// raw pointer type and are convertible to a RefCounted(Base|ThreadSafeBase)
// type.
value = (is_pointer<T>::value &&
(is_convertible<T, subtle::RefCountedBase*>::value ||
is_convertible<T, subtle::RefCountedThreadSafeBase*>::value))
value = (std::is_pointer<T>::value &&
(std::is_convertible<T, subtle::RefCountedBase*>::value ||
std::is_convertible<T, subtle::RefCountedThreadSafeBase*>::value))
};
#endif
};
template <typename Params>
@ -47,14 +41,14 @@ struct ParamsUseScopedRefptrCorrectly {
};
template <>
struct ParamsUseScopedRefptrCorrectly<Tuple<>> {
struct ParamsUseScopedRefptrCorrectly<std::tuple<>> {
enum { value = 1 };
};
template <typename Head, typename... Tail>
struct ParamsUseScopedRefptrCorrectly<Tuple<Head, Tail...>> {
struct ParamsUseScopedRefptrCorrectly<std::tuple<Head, Tail...>> {
enum { value = !NeedsScopedRefptrButGetsRawPtr<Head>::value &&
ParamsUseScopedRefptrCorrectly<Tuple<Tail...>>::value };
ParamsUseScopedRefptrCorrectly<std::tuple<Tail...>>::value };
};
} // namespace internal

View File

@ -15,32 +15,32 @@ bool RefCountedThreadSafeBase::HasOneRef() const {
}
RefCountedThreadSafeBase::RefCountedThreadSafeBase() : ref_count_(0) {
#ifndef NDEBUG
#if DCHECK_IS_ON()
in_dtor_ = false;
#endif
}
RefCountedThreadSafeBase::~RefCountedThreadSafeBase() {
#ifndef NDEBUG
#if DCHECK_IS_ON()
DCHECK(in_dtor_) << "RefCountedThreadSafe object deleted without "
"calling Release()";
#endif
}
void RefCountedThreadSafeBase::AddRef() const {
#ifndef NDEBUG
#if DCHECK_IS_ON()
DCHECK(!in_dtor_);
#endif
AtomicRefCountInc(&ref_count_);
}
bool RefCountedThreadSafeBase::Release() const {
#ifndef NDEBUG
#if DCHECK_IS_ON()
DCHECK(!in_dtor_);
DCHECK(!AtomicRefCountIsZero(&ref_count_));
#endif
if (!AtomicRefCountDec(&ref_count_)) {
#ifndef NDEBUG
#if DCHECK_IS_ON()
in_dtor_ = true;
#endif
return true;

View File

@ -5,16 +5,17 @@
#ifndef BASE_MEMORY_REF_COUNTED_H_
#define BASE_MEMORY_REF_COUNTED_H_
#include <stddef.h>
#include <cassert>
#include <iosfwd>
#include <type_traits>
#include "base/atomic_ref_count.h"
#include "base/base_export.h"
#include "base/compiler_specific.h"
#include "base/macros.h"
#ifndef NDEBUG
#include "base/logging.h"
#endif
#include "base/macros.h"
#include "base/threading/thread_collision_warner.h"
#include "build/build_config.h"
@ -29,16 +30,16 @@ class BASE_EXPORT RefCountedBase {
protected:
RefCountedBase()
: ref_count_(0)
#ifndef NDEBUG
, in_dtor_(false)
#endif
{
#if DCHECK_IS_ON()
, in_dtor_(false)
#endif
{
}
~RefCountedBase() {
#ifndef NDEBUG
#if DCHECK_IS_ON()
DCHECK(in_dtor_) << "RefCounted object deleted without calling Release()";
#endif
#endif
}
@ -47,9 +48,9 @@ class BASE_EXPORT RefCountedBase {
// Current thread books the critical section "AddRelease"
// without release it.
// DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_);
#ifndef NDEBUG
#if DCHECK_IS_ON()
DCHECK(!in_dtor_);
#endif
#endif
++ref_count_;
}
@ -59,21 +60,21 @@ class BASE_EXPORT RefCountedBase {
// Current thread books the critical section "AddRelease"
// without release it.
// DFAKE_SCOPED_LOCK_THREAD_LOCKED(add_release_);
#ifndef NDEBUG
#if DCHECK_IS_ON()
DCHECK(!in_dtor_);
#endif
#endif
if (--ref_count_ == 0) {
#ifndef NDEBUG
#if DCHECK_IS_ON()
in_dtor_ = true;
#endif
#endif
return true;
}
return false;
}
private:
mutable int ref_count_;
#ifndef NDEBUG
mutable size_t ref_count_;
#if DCHECK_IS_ON()
mutable bool in_dtor_;
#endif
@ -97,7 +98,7 @@ class BASE_EXPORT RefCountedThreadSafeBase {
private:
mutable AtomicRefCount ref_count_;
#ifndef NDEBUG
#if DCHECK_IS_ON()
mutable bool in_dtor_;
#endif
@ -108,7 +109,7 @@ class BASE_EXPORT RefCountedThreadSafeBase {
//
// A base class for reference counted classes. Otherwise, known as a cheap
// knock-off of WebKit's RefCounted<T> class. To use this guy just extend your
// knock-off of WebKit's RefCounted<T> class. To use this, just extend your
// class from it like so:
//
// class MyFoo : public base::RefCounted<MyFoo> {
@ -123,7 +124,7 @@ class BASE_EXPORT RefCountedThreadSafeBase {
template <class T>
class RefCounted : public subtle::RefCountedBase {
public:
RefCounted() {}
RefCounted() = default;
void AddRef() const {
subtle::RefCountedBase::AddRef();
@ -136,7 +137,7 @@ class RefCounted : public subtle::RefCountedBase {
}
protected:
~RefCounted() {}
~RefCounted() = default;
private:
DISALLOW_COPY_AND_ASSIGN(RefCounted<T>);
@ -173,7 +174,7 @@ struct DefaultRefCountedThreadSafeTraits {
template <class T, typename Traits = DefaultRefCountedThreadSafeTraits<T> >
class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase {
public:
RefCountedThreadSafe() {}
RefCountedThreadSafe() = default;
void AddRef() const {
subtle::RefCountedThreadSafeBase::AddRef();
@ -186,7 +187,7 @@ class RefCountedThreadSafe : public subtle::RefCountedThreadSafeBase {
}
protected:
~RefCountedThreadSafe() {}
~RefCountedThreadSafe() = default;
private:
friend struct DefaultRefCountedThreadSafeTraits<T>;
@ -210,7 +211,7 @@ class RefCountedData
private:
friend class base::RefCountedThreadSafe<base::RefCountedData<T> >;
~RefCountedData() {}
~RefCountedData() = default;
};
} // namespace base
@ -234,7 +235,7 @@ class RefCountedData
// void some_other_function() {
// scoped_refptr<MyFoo> foo = new MyFoo();
// ...
// foo = NULL; // explicitly releases |foo|
// foo = nullptr; // explicitly releases |foo|
// ...
// if (foo)
// foo->Method(param);
@ -249,7 +250,7 @@ class RefCountedData
// scoped_refptr<MyFoo> b;
//
// b.swap(a);
// // now, |b| references the MyFoo object, and |a| references NULL.
// // now, |b| references the MyFoo object, and |a| references nullptr.
// }
//
// To make both |a| and |b| in the above example reference the same MyFoo
@ -268,8 +269,7 @@ class scoped_refptr {
public:
typedef T element_type;
scoped_refptr() : ptr_(NULL) {
}
scoped_refptr() {}
scoped_refptr(T* p) : ptr_(p) {
if (ptr_)
@ -283,7 +283,9 @@ class scoped_refptr {
}
// Copy conversion constructor.
template <typename U>
template <typename U,
typename = typename std::enable_if<
std::is_convertible<U*, T*>::value>::type>
scoped_refptr(const scoped_refptr<U>& r) : ptr_(r.get()) {
if (ptr_)
AddRef(ptr_);
@ -294,7 +296,9 @@ class scoped_refptr {
scoped_refptr(scoped_refptr&& r) : ptr_(r.get()) { r.ptr_ = nullptr; }
// Move conversion constructor.
template <typename U>
template <typename U,
typename = typename std::enable_if<
std::is_convertible<U*, T*>::value>::type>
scoped_refptr(scoped_refptr<U>&& r) : ptr_(r.get()) {
r.ptr_ = nullptr;
}
@ -307,12 +311,12 @@ class scoped_refptr {
T* get() const { return ptr_; }
T& operator*() const {
assert(ptr_ != NULL);
assert(ptr_ != nullptr);
return *ptr_;
}
T* operator->() const {
assert(ptr_ != NULL);
assert(ptr_ != nullptr);
return ptr_;
}
@ -357,20 +361,7 @@ class scoped_refptr {
swap(&r.ptr_);
}
private:
template <typename U> friend class scoped_refptr;
// Allow scoped_refptr<T> to be used in boolean expressions, but not
// implicitly convertible to a real bool (which is dangerous).
//
// Note that this trick is only safe when the == and != operators
// are declared explicitly, as otherwise "refptr1 == refptr2"
// will compile but do the wrong thing (i.e., convert to Testable
// and then do the comparison).
typedef T* scoped_refptr::*Testable;
public:
operator Testable() const { return ptr_ ? &scoped_refptr::ptr_ : nullptr; }
explicit operator bool() const { return ptr_ != nullptr; }
template <typename U>
bool operator==(const scoped_refptr<U>& rhs) const {
@ -388,9 +379,13 @@ class scoped_refptr {
}
protected:
T* ptr_;
T* ptr_ = nullptr;
private:
// Friend required for move constructors that set r.ptr_ to null.
template <typename U>
friend class scoped_refptr;
// Non-inline helpers to allow:
// class Opaque;
// extern template class scoped_refptr<Opaque>;
@ -399,11 +394,13 @@ class scoped_refptr {
static void Release(T* ptr);
};
// static
template <typename T>
void scoped_refptr<T>::AddRef(T* ptr) {
ptr->AddRef();
}
// static
template <typename T>
void scoped_refptr<T>::Release(T* ptr) {
ptr->Release();
@ -416,8 +413,6 @@ scoped_refptr<T> make_scoped_refptr(T* t) {
return scoped_refptr<T>(t);
}
// Temporary operator overloads to facilitate the transition. See
// https://crbug.com/110610.
template <typename T, typename U>
bool operator==(const scoped_refptr<T>& lhs, const U* rhs) {
return lhs.get() == rhs;
@ -428,6 +423,16 @@ bool operator==(const T* lhs, const scoped_refptr<U>& rhs) {
return lhs == rhs.get();
}
template <typename T>
bool operator==(const scoped_refptr<T>& lhs, std::nullptr_t null) {
return !static_cast<bool>(lhs);
}
template <typename T>
bool operator==(std::nullptr_t null, const scoped_refptr<T>& rhs) {
return !static_cast<bool>(rhs);
}
template <typename T, typename U>
bool operator!=(const scoped_refptr<T>& lhs, const U* rhs) {
return !operator==(lhs, rhs);
@ -438,6 +443,16 @@ bool operator!=(const T* lhs, const scoped_refptr<U>& rhs) {
return !operator==(lhs, rhs);
}
template <typename T>
bool operator!=(const scoped_refptr<T>& lhs, std::nullptr_t null) {
return !operator==(lhs, null);
}
template <typename T>
bool operator!=(std::nullptr_t null, const scoped_refptr<T>& rhs) {
return !operator==(null, rhs);
}
template <typename T>
std::ostream& operator<<(std::ostream& out, const scoped_refptr<T>& p) {
return out << p.get();

View File

@ -1,607 +0,0 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Scopers help you manage ownership of a pointer, helping you easily manage a
// pointer within a scope, and automatically destroying the pointer at the end
// of a scope. There are two main classes you will use, which correspond to the
// operators new/delete and new[]/delete[].
//
// Example usage (scoped_ptr<T>):
// {
// scoped_ptr<Foo> foo(new Foo("wee"));
// } // foo goes out of scope, releasing the pointer with it.
//
// {
// scoped_ptr<Foo> foo; // No pointer managed.
// foo.reset(new Foo("wee")); // Now a pointer is managed.
// foo.reset(new Foo("wee2")); // Foo("wee") was destroyed.
// foo.reset(new Foo("wee3")); // Foo("wee2") was destroyed.
// foo->Method(); // Foo::Method() called.
// foo.get()->Method(); // Foo::Method() called.
// SomeFunc(foo.release()); // SomeFunc takes ownership, foo no longer
// // manages a pointer.
// foo.reset(new Foo("wee4")); // foo manages a pointer again.
// foo.reset(); // Foo("wee4") destroyed, foo no longer
// // manages a pointer.
// } // foo wasn't managing a pointer, so nothing was destroyed.
//
// Example usage (scoped_ptr<T[]>):
// {
// scoped_ptr<Foo[]> foo(new Foo[100]);
// foo.get()->Method(); // Foo::Method on the 0th element.
// foo[10].Method(); // Foo::Method on the 10th element.
// }
//
// These scopers also implement part of the functionality of C++11 unique_ptr
// in that they are "movable but not copyable." You can use the scopers in
// the parameter and return types of functions to signify ownership transfer
// in to and out of a function. When calling a function that has a scoper
// as the argument type, it must be called with an rvalue of a scoper, which
// can be created by using std::move(), or the result of another function that
// generates a temporary; passing by copy will NOT work. Here is an example
// using scoped_ptr:
//
// void TakesOwnership(scoped_ptr<Foo> arg) {
// // Do something with arg.
// }
// scoped_ptr<Foo> CreateFoo() {
// // No need for calling std::move() for returning a move-only value, or
// // when you already have an rvalue as we do here.
// return scoped_ptr<Foo>(new Foo("new"));
// }
// scoped_ptr<Foo> PassThru(scoped_ptr<Foo> arg) {
// return arg;
// }
//
// {
// scoped_ptr<Foo> ptr(new Foo("yay")); // ptr manages Foo("yay").
// TakesOwnership(std::move(ptr)); // ptr no longer owns Foo("yay").
// scoped_ptr<Foo> ptr2 = CreateFoo(); // ptr2 owns the return Foo.
// scoped_ptr<Foo> ptr3 = // ptr3 now owns what was in ptr2.
// PassThru(std::move(ptr2)); // ptr2 is correspondingly nullptr.
// }
//
// Notice that if you do not call std::move() when returning from PassThru(), or
// when invoking TakesOwnership(), the code will not compile because scopers
// are not copyable; they only implement move semantics which require calling
// the std::move() function to signify a destructive transfer of state.
// CreateFoo() is different though because we are constructing a temporary on
// the return line and thus can avoid needing to call std::move().
//
// The conversion move-constructor properly handles upcast in initialization,
// i.e. you can use a scoped_ptr<Child> to initialize a scoped_ptr<Parent>:
//
// scoped_ptr<Foo> foo(new Foo());
// scoped_ptr<FooParent> parent(std::move(foo));
#ifndef BASE_MEMORY_SCOPED_PTR_H_
#define BASE_MEMORY_SCOPED_PTR_H_
// This is an implementation designed to match the anticipated future TR2
// implementation of the scoped_ptr class.
#include <assert.h>
#include <stddef.h>
#include <stdlib.h>
#include <iosfwd>
#include <memory>
#include <type_traits>
#include <utility>
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/move.h"
#include "base/template_util.h"
namespace base {
namespace subtle {
class RefCountedBase;
class RefCountedThreadSafeBase;
} // namespace subtle
// Function object which invokes 'free' on its parameter, which must be
// a pointer. Can be used to store malloc-allocated pointers in scoped_ptr:
//
// scoped_ptr<int, base::FreeDeleter> foo_ptr(
// static_cast<int*>(malloc(sizeof(int))));
struct FreeDeleter {
inline void operator()(void* ptr) const {
free(ptr);
}
};
namespace internal {
template <typename T> struct IsNotRefCounted {
enum {
value = !base::is_convertible<T*, base::subtle::RefCountedBase*>::value &&
!base::is_convertible<T*, base::subtle::RefCountedThreadSafeBase*>::
value
};
};
// Minimal implementation of the core logic of scoped_ptr, suitable for
// reuse in both scoped_ptr and its specializations.
template <class T, class D>
class scoped_ptr_impl {
public:
explicit scoped_ptr_impl(T* p) : data_(p) {}
// Initializer for deleters that have data parameters.
scoped_ptr_impl(T* p, const D& d) : data_(p, d) {}
// Templated constructor that destructively takes the value from another
// scoped_ptr_impl.
template <typename U, typename V>
scoped_ptr_impl(scoped_ptr_impl<U, V>* other)
: data_(other->release(), other->get_deleter()) {
// We do not support move-only deleters. We could modify our move
// emulation to have base::subtle::move() and base::subtle::forward()
// functions that are imperfect emulations of their C++11 equivalents,
// but until there's a requirement, just assume deleters are copyable.
}
template <typename U, typename V>
void TakeState(scoped_ptr_impl<U, V>* other) {
// See comment in templated constructor above regarding lack of support
// for move-only deleters.
reset(other->release());
get_deleter() = other->get_deleter();
}
~scoped_ptr_impl() {
// Match libc++, which calls reset() in its destructor.
// Use nullptr as the new value for three reasons:
// 1. libc++ does it.
// 2. Avoids infinitely recursing into destructors if two classes are owned
// in a reference cycle (see ScopedPtrTest.ReferenceCycle).
// 3. If |this| is accessed in the future, in a use-after-free bug, attempts
// to dereference |this|'s pointer should cause either a failure or a
// segfault closer to the problem. If |this| wasn't reset to nullptr,
// the access would cause the deleted memory to be read or written
// leading to other more subtle issues.
reset(nullptr);
}
void reset(T* p) {
// Match C++11's definition of unique_ptr::reset(), which requires changing
// the pointer before invoking the deleter on the old pointer. This prevents
// |this| from being accessed after the deleter is run, which may destroy
// |this|.
T* old = data_.ptr;
data_.ptr = p;
if (old != nullptr)
static_cast<D&>(data_)(old);
}
T* get() const { return data_.ptr; }
D& get_deleter() { return data_; }
const D& get_deleter() const { return data_; }
void swap(scoped_ptr_impl& p2) {
// Standard swap idiom: 'using std::swap' ensures that std::swap is
// present in the overload set, but we call swap unqualified so that
// any more-specific overloads can be used, if available.
using std::swap;
swap(static_cast<D&>(data_), static_cast<D&>(p2.data_));
swap(data_.ptr, p2.data_.ptr);
}
T* release() {
T* old_ptr = data_.ptr;
data_.ptr = nullptr;
return old_ptr;
}
private:
// Needed to allow type-converting constructor.
template <typename U, typename V> friend class scoped_ptr_impl;
// Use the empty base class optimization to allow us to have a D
// member, while avoiding any space overhead for it when D is an
// empty class. See e.g. http://www.cantrip.org/emptyopt.html for a good
// discussion of this technique.
struct Data : public D {
explicit Data(T* ptr_in) : ptr(ptr_in) {}
Data(T* ptr_in, const D& other) : D(other), ptr(ptr_in) {}
T* ptr;
};
Data data_;
DISALLOW_COPY_AND_ASSIGN(scoped_ptr_impl);
};
} // namespace internal
} // namespace base
// A scoped_ptr<T> is like a T*, except that the destructor of scoped_ptr<T>
// automatically deletes the pointer it holds (if any).
// That is, scoped_ptr<T> owns the T object that it points to.
// Like a T*, a scoped_ptr<T> may hold either nullptr or a pointer to a T
// object. Also like T*, scoped_ptr<T> is thread-compatible, and once you
// dereference it, you get the thread safety guarantees of T.
//
// The size of scoped_ptr is small. On most compilers, when using the
// std::default_delete, sizeof(scoped_ptr<T>) == sizeof(T*). Custom deleters
// will increase the size proportional to whatever state they need to have. See
// comments inside scoped_ptr_impl<> for details.
//
// Current implementation targets having a strict subset of C++11's
// unique_ptr<> features. Known deficiencies include not supporting move-only
// deleteres, function pointers as deleters, and deleters with reference
// types.
template <class T, class D = std::default_delete<T>>
class scoped_ptr {
DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND(scoped_ptr)
static_assert(!std::is_array<T>::value,
"scoped_ptr doesn't support array with size");
static_assert(base::internal::IsNotRefCounted<T>::value,
"T is a refcounted type and needs a scoped_refptr");
public:
// The element and deleter types.
using element_type = T;
using deleter_type = D;
// Constructor. Defaults to initializing with nullptr.
scoped_ptr() : impl_(nullptr) {}
// Constructor. Takes ownership of p.
explicit scoped_ptr(element_type* p) : impl_(p) {}
// Constructor. Allows initialization of a stateful deleter.
scoped_ptr(element_type* p, const D& d) : impl_(p, d) {}
// Constructor. Allows construction from a nullptr.
scoped_ptr(std::nullptr_t) : impl_(nullptr) {}
// Move constructor.
//
// IMPLEMENTATION NOTE: Clang requires a move constructor to be defined (and
// not just the conversion constructor) in order to warn on pessimizing moves.
// The requirements for the move constructor are specified in C++11
// 20.7.1.2.1.15-17, which has some subtleties around reference deleters. As
// we don't support reference (or move-only) deleters, the post conditions are
// trivially true: we always copy construct the deleter from other's deleter.
scoped_ptr(scoped_ptr&& other) : impl_(&other.impl_) {}
// Conversion constructor. Allows construction from a scoped_ptr rvalue for a
// convertible type and deleter.
//
// IMPLEMENTATION NOTE: C++ 20.7.1.2.1.19 requires this constructor to only
// participate in overload resolution if all the following are true:
// - U is implicitly convertible to T: this is important for 2 reasons:
// 1. So type traits don't incorrectly return true, e.g.
// std::is_convertible<scoped_ptr<Base>, scoped_ptr<Derived>>::value
// should be false.
// 2. To make sure code like this compiles:
// void F(scoped_ptr<int>);
// void F(scoped_ptr<Base>);
// // Ambiguous since both conversion constructors match.
// F(scoped_ptr<Derived>());
// - U is not an array type: to prevent conversions from scoped_ptr<T[]> to
// scoped_ptr<T>.
// - D is a reference type and E is the same type, or D is not a reference
// type and E is implicitly convertible to D: again, we don't support
// reference deleters, so we only worry about the latter requirement.
template <typename U,
typename E,
typename std::enable_if<!std::is_array<U>::value &&
std::is_convertible<U*, T*>::value &&
std::is_convertible<E, D>::value>::type* =
nullptr>
scoped_ptr(scoped_ptr<U, E>&& other)
: impl_(&other.impl_) {}
// operator=.
//
// IMPLEMENTATION NOTE: Unlike the move constructor, Clang does not appear to
// require a move assignment operator to trigger the pessimizing move warning:
// in this case, the warning triggers when moving a temporary. For consistency
// with the move constructor, we define it anyway. C++11 20.7.1.2.3.1-3
// defines several requirements around this: like the move constructor, the
// requirements are simplified by the fact that we don't support move-only or
// reference deleters.
scoped_ptr& operator=(scoped_ptr&& rhs) {
impl_.TakeState(&rhs.impl_);
return *this;
}
// operator=. Allows assignment from a scoped_ptr rvalue for a convertible
// type and deleter.
//
// IMPLEMENTATION NOTE: C++11 unique_ptr<> keeps this operator= distinct from
// the normal move assignment operator. C++11 20.7.1.2.3.4-7 contains the
// requirement for this operator, but like the conversion constructor, the
// requirements are greatly simplified by not supporting move-only or
// reference deleters.
template <typename U,
typename E,
typename std::enable_if<!std::is_array<U>::value &&
std::is_convertible<U*, T*>::value &&
// Note that this really should be
// std::is_assignable, but <type_traits>
// appears to be missing this on some
// platforms. This is close enough (though
// it's not the same).
std::is_convertible<D, E>::value>::type* =
nullptr>
scoped_ptr& operator=(scoped_ptr<U, E>&& rhs) {
impl_.TakeState(&rhs.impl_);
return *this;
}
// operator=. Allows assignment from a nullptr. Deletes the currently owned
// object, if any.
scoped_ptr& operator=(std::nullptr_t) {
reset();
return *this;
}
// Reset. Deletes the currently owned object, if any.
// Then takes ownership of a new object, if given.
void reset(element_type* p = nullptr) { impl_.reset(p); }
// Accessors to get the owned object.
// operator* and operator-> will assert() if there is no current object.
element_type& operator*() const {
assert(impl_.get() != nullptr);
return *impl_.get();
}
element_type* operator->() const {
assert(impl_.get() != nullptr);
return impl_.get();
}
element_type* get() const { return impl_.get(); }
// Access to the deleter.
deleter_type& get_deleter() { return impl_.get_deleter(); }
const deleter_type& get_deleter() const { return impl_.get_deleter(); }
// Allow scoped_ptr<element_type> to be used in boolean expressions, but not
// implicitly convertible to a real bool (which is dangerous).
//
// Note that this trick is only safe when the == and != operators
// are declared explicitly, as otherwise "scoped_ptr1 ==
// scoped_ptr2" will compile but do the wrong thing (i.e., convert
// to Testable and then do the comparison).
private:
typedef base::internal::scoped_ptr_impl<element_type, deleter_type>
scoped_ptr::*Testable;
public:
operator Testable() const {
return impl_.get() ? &scoped_ptr::impl_ : nullptr;
}
// Swap two scoped pointers.
void swap(scoped_ptr& p2) {
impl_.swap(p2.impl_);
}
// Release a pointer.
// The return value is the current pointer held by this object. If this object
// holds a nullptr, the return value is nullptr. After this operation, this
// object will hold a nullptr, and will not own the object any more.
element_type* release() WARN_UNUSED_RESULT {
return impl_.release();
}
private:
// Needed to reach into |impl_| in the constructor.
template <typename U, typename V> friend class scoped_ptr;
base::internal::scoped_ptr_impl<element_type, deleter_type> impl_;
// Forbidden for API compatibility with std::unique_ptr.
explicit scoped_ptr(int disallow_construction_from_null);
};
template <class T, class D>
class scoped_ptr<T[], D> {
DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND(scoped_ptr)
public:
// The element and deleter types.
using element_type = T;
using deleter_type = D;
// Constructor. Defaults to initializing with nullptr.
scoped_ptr() : impl_(nullptr) {}
// Constructor. Stores the given array. Note that the argument's type
// must exactly match T*. In particular:
// - it cannot be a pointer to a type derived from T, because it is
// inherently unsafe in the general case to access an array through a
// pointer whose dynamic type does not match its static type (eg., if
// T and the derived types had different sizes access would be
// incorrectly calculated). Deletion is also always undefined
// (C++98 [expr.delete]p3). If you're doing this, fix your code.
// - it cannot be const-qualified differently from T per unique_ptr spec
// (http://cplusplus.github.com/LWG/lwg-active.html#2118). Users wanting
// to work around this may use const_cast<const T*>().
explicit scoped_ptr(element_type* array) : impl_(array) {}
// Constructor. Allows construction from a nullptr.
scoped_ptr(std::nullptr_t) : impl_(nullptr) {}
// Constructor. Allows construction from a scoped_ptr rvalue.
scoped_ptr(scoped_ptr&& other) : impl_(&other.impl_) {}
// operator=. Allows assignment from a scoped_ptr rvalue.
scoped_ptr& operator=(scoped_ptr&& rhs) {
impl_.TakeState(&rhs.impl_);
return *this;
}
// operator=. Allows assignment from a nullptr. Deletes the currently owned
// array, if any.
scoped_ptr& operator=(std::nullptr_t) {
reset();
return *this;
}
// Reset. Deletes the currently owned array, if any.
// Then takes ownership of a new object, if given.
void reset(element_type* array = nullptr) { impl_.reset(array); }
// Accessors to get the owned array.
element_type& operator[](size_t i) const {
assert(impl_.get() != nullptr);
return impl_.get()[i];
}
element_type* get() const { return impl_.get(); }
// Access to the deleter.
deleter_type& get_deleter() { return impl_.get_deleter(); }
const deleter_type& get_deleter() const { return impl_.get_deleter(); }
// Allow scoped_ptr<element_type> to be used in boolean expressions, but not
// implicitly convertible to a real bool (which is dangerous).
private:
typedef base::internal::scoped_ptr_impl<element_type, deleter_type>
scoped_ptr::*Testable;
public:
operator Testable() const {
return impl_.get() ? &scoped_ptr::impl_ : nullptr;
}
// Swap two scoped pointers.
void swap(scoped_ptr& p2) {
impl_.swap(p2.impl_);
}
// Release a pointer.
// The return value is the current pointer held by this object. If this object
// holds a nullptr, the return value is nullptr. After this operation, this
// object will hold a nullptr, and will not own the object any more.
element_type* release() WARN_UNUSED_RESULT {
return impl_.release();
}
private:
// Force element_type to be a complete type.
enum { type_must_be_complete = sizeof(element_type) };
// Actually hold the data.
base::internal::scoped_ptr_impl<element_type, deleter_type> impl_;
// Disable initialization from any type other than element_type*, by
// providing a constructor that matches such an initialization, but is
// private and has no definition. This is disabled because it is not safe to
// call delete[] on an array whose static type does not match its dynamic
// type.
template <typename U> explicit scoped_ptr(U* array);
explicit scoped_ptr(int disallow_construction_from_null);
// Disable reset() from any type other than element_type*, for the same
// reasons as the constructor above.
template <typename U> void reset(U* array);
void reset(int disallow_reset_from_null);
};
// Free functions
template <class T, class D>
void swap(scoped_ptr<T, D>& p1, scoped_ptr<T, D>& p2) {
p1.swap(p2);
}
template <class T1, class D1, class T2, class D2>
bool operator==(const scoped_ptr<T1, D1>& p1, const scoped_ptr<T2, D2>& p2) {
return p1.get() == p2.get();
}
template <class T, class D>
bool operator==(const scoped_ptr<T, D>& p, std::nullptr_t) {
return p.get() == nullptr;
}
template <class T, class D>
bool operator==(std::nullptr_t, const scoped_ptr<T, D>& p) {
return p.get() == nullptr;
}
template <class T1, class D1, class T2, class D2>
bool operator!=(const scoped_ptr<T1, D1>& p1, const scoped_ptr<T2, D2>& p2) {
return !(p1 == p2);
}
template <class T, class D>
bool operator!=(const scoped_ptr<T, D>& p, std::nullptr_t) {
return !(p == nullptr);
}
template <class T, class D>
bool operator!=(std::nullptr_t, const scoped_ptr<T, D>& p) {
return !(p == nullptr);
}
template <class T1, class D1, class T2, class D2>
bool operator<(const scoped_ptr<T1, D1>& p1, const scoped_ptr<T2, D2>& p2) {
return p1.get() < p2.get();
}
template <class T, class D>
bool operator<(const scoped_ptr<T, D>& p, std::nullptr_t) {
return p.get() < nullptr;
}
template <class T, class D>
bool operator<(std::nullptr_t, const scoped_ptr<T, D>& p) {
return nullptr < p.get();
}
template <class T1, class D1, class T2, class D2>
bool operator>(const scoped_ptr<T1, D1>& p1, const scoped_ptr<T2, D2>& p2) {
return p2 < p1;
}
template <class T, class D>
bool operator>(const scoped_ptr<T, D>& p, std::nullptr_t) {
return nullptr < p;
}
template <class T, class D>
bool operator>(std::nullptr_t, const scoped_ptr<T, D>& p) {
return p < nullptr;
}
template <class T1, class D1, class T2, class D2>
bool operator<=(const scoped_ptr<T1, D1>& p1, const scoped_ptr<T2, D2>& p2) {
return !(p1 > p2);
}
template <class T, class D>
bool operator<=(const scoped_ptr<T, D>& p, std::nullptr_t) {
return !(p > nullptr);
}
template <class T, class D>
bool operator<=(std::nullptr_t, const scoped_ptr<T, D>& p) {
return !(nullptr > p);
}
template <class T1, class D1, class T2, class D2>
bool operator>=(const scoped_ptr<T1, D1>& p1, const scoped_ptr<T2, D2>& p2) {
return !(p1 < p2);
}
template <class T, class D>
bool operator>=(const scoped_ptr<T, D>& p, std::nullptr_t) {
return !(p < nullptr);
}
template <class T, class D>
bool operator>=(std::nullptr_t, const scoped_ptr<T, D>& p) {
return !(nullptr < p);
}
// A function to convert T* into scoped_ptr<T>
// Doing e.g. make_scoped_ptr(new FooBarBaz<type>(arg)) is a shorter notation
// for scoped_ptr<FooBarBaz<type> >(new FooBarBaz<type>(arg))
template <typename T>
scoped_ptr<T> make_scoped_ptr(T* ptr) {
return scoped_ptr<T>(ptr);
}
template <typename T>
std::ostream& operator<<(std::ostream& out, const scoped_ptr<T>& p) {
return out << p.get();
}
#endif // BASE_MEMORY_SCOPED_PTR_H_

View File

@ -0,0 +1,292 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_MEMORY_SHARED_MEMORY_H_
#define BASE_MEMORY_SHARED_MEMORY_H_
#include <stddef.h>
#include <string>
#include "base/base_export.h"
#include "base/macros.h"
#include "base/memory/shared_memory_handle.h"
#include "base/process/process_handle.h"
#include "build/build_config.h"
#if defined(OS_POSIX)
#include <stdio.h>
#include <sys/types.h>
#include <semaphore.h>
#include "base/file_descriptor_posix.h"
#include "base/files/file_util.h"
#include "base/files/scoped_file.h"
#endif
#if defined(OS_WIN)
#include "base/win/scoped_handle.h"
#endif
namespace base {
class FilePath;
// Options for creating a shared memory object.
struct BASE_EXPORT SharedMemoryCreateOptions {
#if !(defined(OS_MACOSX) && !defined(OS_IOS))
// DEPRECATED (crbug.com/345734):
// If NULL, the object is anonymous. This pointer is owned by the caller
// and must live through the call to Create().
const std::string* name_deprecated = nullptr;
// DEPRECATED (crbug.com/345734):
// If true, and the shared memory already exists, Create() will open the
// existing shared memory and ignore the size parameter. If false,
// shared memory must not exist. This flag is meaningless unless
// name_deprecated is non-NULL.
bool open_existing_deprecated = false;
#endif // !(defined(OS_MACOSX) && !defined(OS_IOS))
// Size of the shared memory object to be created.
// When opening an existing object, this has no effect.
size_t size = 0;
// If true, mappings might need to be made executable later.
bool executable = false;
// If true, the file can be shared read-only to a process.
bool share_read_only = false;
};
// Platform abstraction for shared memory. Provides a C++ wrapper
// around the OS primitive for a memory mapped file.
class BASE_EXPORT SharedMemory {
public:
SharedMemory();
#if defined(OS_WIN)
// Similar to the default constructor, except that this allows for
// calling LockDeprecated() to acquire the named mutex before either Create or
// Open are called on Windows.
explicit SharedMemory(const std::wstring& name);
#endif
// Create a new SharedMemory object from an existing, open
// shared memory file.
//
// WARNING: This does not reduce the OS-level permissions on the handle; it
// only affects how the SharedMemory will be mmapped. Use
// ShareReadOnlyToProcess to drop permissions. TODO(jln,jyasskin): DCHECK
// that |read_only| matches the permissions of the handle.
SharedMemory(const SharedMemoryHandle& handle, bool read_only);
// Closes any open files.
~SharedMemory();
// 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);
// Returns invalid handle (see comment above for exact definition).
static SharedMemoryHandle NULLHandle();
// Closes a shared memory handle.
static void CloseHandle(const SharedMemoryHandle& handle);
// Returns the maximum number of handles that can be open at once per process.
static size_t GetHandleLimit();
// Duplicates The underlying OS primitive. Returns NULLHandle() on failure.
// The caller is responsible for destroying the duplicated OS primitive.
static SharedMemoryHandle DuplicateHandle(const SharedMemoryHandle& handle);
#if defined(OS_POSIX) && !(defined(OS_MACOSX) && !defined(OS_IOS))
// This method requires that the SharedMemoryHandle is backed by a POSIX fd.
static int GetFdFromSharedMemoryHandle(const SharedMemoryHandle& handle);
#endif
#if defined(OS_POSIX) && !defined(OS_ANDROID)
// Gets the size of the shared memory region referred to by |handle|.
// Returns false on a failure to determine the size. On success, populates the
// output variable |size|.
static bool GetSizeFromSharedMemoryHandle(const SharedMemoryHandle& handle,
size_t* size);
#endif // defined(OS_POSIX) && !defined(OS_ANDROID)
// Creates a shared memory object as described by the options struct.
// Returns true on success and false on failure.
bool Create(const SharedMemoryCreateOptions& options);
// Creates and maps an anonymous shared memory segment of size size.
// Returns true on success and false on failure.
bool CreateAndMapAnonymous(size_t size);
// Creates an anonymous shared memory segment of size size.
// Returns true on success and false on failure.
bool CreateAnonymous(size_t size) {
SharedMemoryCreateOptions options;
options.size = size;
return Create(options);
}
#if !defined(OS_MACOSX) || defined(OS_IOS)
// DEPRECATED (crbug.com/345734):
// Creates or opens a shared memory segment based on a name.
// If open_existing is true, and the shared memory already exists,
// opens the existing shared memory and ignores the size parameter.
// If open_existing is false, shared memory must not exist.
// size is the size of the block to be created.
// Returns true on success, false on failure.
bool CreateNamedDeprecated(
const std::string& name, bool open_existing, size_t size) {
SharedMemoryCreateOptions options;
options.name_deprecated = &name;
options.open_existing_deprecated = open_existing;
options.size = size;
return Create(options);
}
// Deletes resources associated with a shared memory segment based on name.
// Not all platforms require this call.
bool Delete(const std::string& name);
// Opens a shared memory segment based on a name.
// If read_only is true, opens for read-only access.
// Returns true on success, false on failure.
bool Open(const std::string& name, bool read_only);
#endif // !defined(OS_MACOSX) || defined(OS_IOS)
// 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. The mapped address is guaranteed to
// have an alignment of at least MAP_MINIMUM_ALIGNMENT. This method will fail
// if this object is currently mapped.
bool Map(size_t bytes) {
return MapAt(0, bytes);
}
// Same as above, but with |offset| to specify from begining of the shared
// memory block to map.
// |offset| must be alignent to value of |SysInfo::VMAllocationGranularity()|.
bool MapAt(off_t offset, size_t bytes);
enum { MAP_MINIMUM_ALIGNMENT = 32 };
// Unmaps the shared memory from the caller's address space.
// Returns true if successful; returns false on error or if the
// memory is not mapped.
bool Unmap();
// The size requested when the map is first created.
size_t requested_size() const { return requested_size_; }
// The actual size of the mapped memory (may be larger than requested).
size_t mapped_size() const { return mapped_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_; }
// Returns the underlying OS handle for this segment.
// Use of this handle for anything other than an opaque
// identifier is not portable.
SharedMemoryHandle handle() const;
// Returns the underlying OS handle for this segment. The caller also gets
// ownership of the handle. This is logically equivalent to:
// SharedMemoryHandle dup = DuplicateHandle(handle());
// Close();
// return dup;
SharedMemoryHandle TakeHandle();
// Closes the open shared memory segment. The memory will remain mapped if
// it was previously mapped.
// It is safe to call Close repeatedly.
void Close();
// Shares the shared memory to another process. Attempts to create a
// platform-specific new_handle which can be used in a remote process to read
// the shared memory file. new_handle is an output parameter to receive the
// handle for use in the remote process.
//
// |*this| must have been initialized using one of the Create*() or Open()
// methods with share_read_only=true. If it was constructed from a
// SharedMemoryHandle, this call will CHECK-fail.
//
// Returns true on success, false otherwise.
bool ShareReadOnlyToProcess(ProcessHandle process,
SharedMemoryHandle* new_handle) {
return ShareToProcessCommon(process, new_handle, false, SHARE_READONLY);
}
// Logically equivalent to:
// bool ok = ShareReadOnlyToProcess(process, new_handle);
// Close();
// return ok;
// Note that the memory is unmapped by calling this method, regardless of the
// return value.
bool GiveReadOnlyToProcess(ProcessHandle process,
SharedMemoryHandle* new_handle) {
return ShareToProcessCommon(process, new_handle, true, SHARE_READONLY);
}
// Shares the shared memory to another process. Attempts
// to create a platform-specific new_handle which can be
// used in a remote process to access the shared memory
// file. new_handle is an output parameter to receive
// the handle for use in the remote process.
// Returns true on success, false otherwise.
bool ShareToProcess(ProcessHandle process,
SharedMemoryHandle* new_handle) {
return ShareToProcessCommon(process, new_handle, false, SHARE_CURRENT_MODE);
}
// Logically equivalent to:
// bool ok = ShareToProcess(process, new_handle);
// Close();
// return ok;
// Note that the memory is unmapped by calling this method, regardless of the
// return value.
bool GiveToProcess(ProcessHandle process,
SharedMemoryHandle* new_handle) {
return ShareToProcessCommon(process, new_handle, true, SHARE_CURRENT_MODE);
}
private:
#if defined(OS_POSIX) && !defined(OS_NACL) && !defined(OS_ANDROID) && \
!(defined(OS_MACOSX) && !defined(OS_IOS))
bool PrepareMapFile(ScopedFILE fp, ScopedFD readonly);
bool FilePathForMemoryName(const std::string& mem_name, FilePath* path);
#endif
enum ShareMode {
SHARE_READONLY,
SHARE_CURRENT_MODE,
};
bool ShareToProcessCommon(ProcessHandle process,
SharedMemoryHandle* new_handle,
bool close_self,
ShareMode);
#if defined(OS_WIN)
// If true indicates this came from an external source so needs extra checks
// before being mapped.
bool external_section_;
std::wstring name_;
win::ScopedHandle mapped_file_;
#elif defined(OS_MACOSX) && !defined(OS_IOS)
// The OS primitive that backs the shared memory region.
SharedMemoryHandle shm_;
#elif defined(OS_POSIX)
int mapped_file_;
int readonly_mapped_file_;
#endif
size_t mapped_size_;
void* memory_;
bool read_only_;
size_t requested_size_;
DISALLOW_COPY_AND_ASSIGN(SharedMemory);
};
} // namespace base
#endif // BASE_MEMORY_SHARED_MEMORY_H_

View File

@ -0,0 +1,162 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_MEMORY_SHARED_MEMORY_HANDLE_H_
#define BASE_MEMORY_SHARED_MEMORY_HANDLE_H_
#include <stddef.h>
#include "build/build_config.h"
#if defined(OS_WIN)
#include <windows.h>
#include "base/process/process_handle.h"
#elif defined(OS_MACOSX) && !defined(OS_IOS)
#include <mach/mach.h>
#include "base/base_export.h"
#include "base/macros.h"
#include "base/process/process_handle.h"
#elif defined(OS_POSIX)
#include <sys/types.h>
#include "base/file_descriptor_posix.h"
#endif
namespace base {
// SharedMemoryHandle is a platform specific type which represents
// the underlying OS handle to a shared memory segment.
#if defined(OS_POSIX) && !(defined(OS_MACOSX) && !defined(OS_IOS))
typedef FileDescriptor SharedMemoryHandle;
#elif defined(OS_WIN)
class BASE_EXPORT SharedMemoryHandle {
public:
// The default constructor returns an invalid SharedMemoryHandle.
SharedMemoryHandle();
SharedMemoryHandle(HANDLE h, base::ProcessId pid);
// Standard copy constructor. The new instance shares the underlying OS
// primitives.
SharedMemoryHandle(const SharedMemoryHandle& handle);
// Standard assignment operator. The updated instance shares the underlying
// OS primitives.
SharedMemoryHandle& operator=(const SharedMemoryHandle& handle);
// Comparison operators.
bool operator==(const SharedMemoryHandle& handle) const;
bool operator!=(const SharedMemoryHandle& handle) const;
// Closes the underlying OS resources.
void Close() const;
// Whether the underlying OS primitive is valid.
bool IsValid() const;
// Whether |pid_| is the same as the current process's id.
bool BelongsToCurrentProcess() const;
// Whether handle_ needs to be duplicated into the destination process when
// an instance of this class is passed over a Chrome IPC channel.
bool NeedsBrokering() const;
void SetOwnershipPassesToIPC(bool ownership_passes);
bool OwnershipPassesToIPC() const;
HANDLE GetHandle() const;
base::ProcessId GetPID() const;
private:
HANDLE handle_;
// The process in which |handle_| is valid and can be used. If |handle_| is
// invalid, this will be kNullProcessId.
base::ProcessId pid_;
// Whether passing this object as a parameter to an IPC message passes
// ownership of |handle_| to the IPC stack. This is meant to mimic the
// behavior of the |auto_close| parameter of FileDescriptor. This member only
// affects attachment-brokered SharedMemoryHandles.
// Defaults to |false|.
bool ownership_passes_to_ipc_;
};
#else
class BASE_EXPORT SharedMemoryHandle {
public:
// The default constructor returns an invalid SharedMemoryHandle.
SharedMemoryHandle();
// Makes a Mach-based SharedMemoryHandle of the given size. On error,
// subsequent calls to IsValid() return false.
explicit SharedMemoryHandle(mach_vm_size_t size);
// Makes a Mach-based SharedMemoryHandle from |memory_object|, a named entry
// in the task with process id |pid|. The memory region has size |size|.
SharedMemoryHandle(mach_port_t memory_object,
mach_vm_size_t size,
base::ProcessId pid);
// Standard copy constructor. The new instance shares the underlying OS
// primitives.
SharedMemoryHandle(const SharedMemoryHandle& handle);
// Standard assignment operator. The updated instance shares the underlying
// OS primitives.
SharedMemoryHandle& operator=(const SharedMemoryHandle& handle);
// Duplicates the underlying OS resources.
SharedMemoryHandle Duplicate() const;
// Comparison operators.
bool operator==(const SharedMemoryHandle& handle) const;
bool operator!=(const SharedMemoryHandle& handle) const;
// Whether the underlying OS primitive is valid. Once the SharedMemoryHandle
// is backed by a valid OS primitive, it becomes immutable.
bool IsValid() const;
// Exposed so that the SharedMemoryHandle can be transported between
// processes.
mach_port_t GetMemoryObject() const;
// Returns false on a failure to determine the size. On success, populates the
// output variable |size|. Returns 0 if the handle is invalid.
bool GetSize(size_t* size) const;
// The SharedMemoryHandle must be valid.
// Returns whether the SharedMemoryHandle was successfully mapped into memory.
// On success, |memory| is an output variable that contains the start of the
// mapped memory.
bool MapAt(off_t offset, size_t bytes, void** memory, bool read_only);
// Closes the underlying OS primitive.
void Close() const;
void SetOwnershipPassesToIPC(bool ownership_passes);
bool OwnershipPassesToIPC() const;
private:
// Shared code between copy constructor and operator=.
void CopyRelevantData(const SharedMemoryHandle& handle);
mach_port_t memory_object_ = MACH_PORT_NULL;
// The size of the shared memory region when |type_| is MACH. Only
// relevant if |memory_object_| is not |MACH_PORT_NULL|.
mach_vm_size_t size_ = 0;
// The pid of the process in which |memory_object_| is usable. Only
// relevant if |memory_object_| is not |MACH_PORT_NULL|.
base::ProcessId pid_ = 0;
// Whether passing this object as a parameter to an IPC message passes
// ownership of |memory_object_| to the IPC stack. This is meant to mimic
// the behavior of the |auto_close| parameter of FileDescriptor.
// Defaults to |false|.
bool ownership_passes_to_ipc_ = false;
};
#endif
} // namespace base
#endif // BASE_MEMORY_SHARED_MEMORY_HANDLE_H_

View File

@ -0,0 +1,79 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/memory/shared_memory_handle.h"
#include "base/logging.h"
namespace base {
SharedMemoryHandle::SharedMemoryHandle()
: handle_(nullptr), pid_(kNullProcessId), ownership_passes_to_ipc_(false) {}
SharedMemoryHandle::SharedMemoryHandle(HANDLE h, base::ProcessId pid)
: handle_(h), pid_(pid), ownership_passes_to_ipc_(false) {}
SharedMemoryHandle::SharedMemoryHandle(const SharedMemoryHandle& handle)
: handle_(handle.handle_),
pid_(handle.pid_),
ownership_passes_to_ipc_(handle.ownership_passes_to_ipc_) {}
SharedMemoryHandle& SharedMemoryHandle::operator=(
const SharedMemoryHandle& handle) {
if (this == &handle)
return *this;
handle_ = handle.handle_;
pid_ = handle.pid_;
ownership_passes_to_ipc_ = handle.ownership_passes_to_ipc_;
return *this;
}
bool SharedMemoryHandle::operator==(const SharedMemoryHandle& handle) const {
// Invalid handles are always equal.
if (!IsValid() && !handle.IsValid())
return true;
return handle_ == handle.handle_ && pid_ == handle.pid_;
}
bool SharedMemoryHandle::operator!=(const SharedMemoryHandle& handle) const {
return !(*this == handle);
}
void SharedMemoryHandle::Close() const {
DCHECK(handle_ != nullptr);
DCHECK(BelongsToCurrentProcess());
::CloseHandle(handle_);
}
bool SharedMemoryHandle::IsValid() const {
return handle_ != nullptr;
}
bool SharedMemoryHandle::BelongsToCurrentProcess() const {
return pid_ == base::GetCurrentProcId();
}
bool SharedMemoryHandle::NeedsBrokering() const {
return BelongsToCurrentProcess();
}
HANDLE SharedMemoryHandle::GetHandle() const {
return handle_;
}
base::ProcessId SharedMemoryHandle::GetPID() const {
return pid_;
}
void SharedMemoryHandle::SetOwnershipPassesToIPC(bool ownership_passes) {
ownership_passes_to_ipc_ = ownership_passes;
}
bool SharedMemoryHandle::OwnershipPassesToIPC() const {
return ownership_passes_to_ipc_;
}
} // namespace base

View File

@ -0,0 +1,395 @@
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/memory/shared_memory.h"
#include <aclapi.h>
#include <stddef.h>
#include <stdint.h>
#include "base/logging.h"
#include "base/metrics/histogram_macros.h"
#include "base/rand_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
namespace {
// Errors that can occur during Shared Memory construction.
// These match tools/metrics/histograms/histograms.xml.
// This enum is append-only.
enum CreateError {
SUCCESS = 0,
SIZE_ZERO = 1,
SIZE_TOO_LARGE = 2,
INITIALIZE_ACL_FAILURE = 3,
INITIALIZE_SECURITY_DESC_FAILURE = 4,
SET_SECURITY_DESC_FAILURE = 5,
CREATE_FILE_MAPPING_FAILURE = 6,
REDUCE_PERMISSIONS_FAILURE = 7,
ALREADY_EXISTS = 8,
CREATE_ERROR_LAST = ALREADY_EXISTS
};
// Emits UMA metrics about encountered errors. Pass zero (0) for |winerror|
// if there is no associated Windows error.
void LogError(CreateError error, DWORD winerror) {
UMA_HISTOGRAM_ENUMERATION("SharedMemory.CreateError", error,
CREATE_ERROR_LAST + 1);
static_assert(ERROR_SUCCESS == 0, "Windows error code changed!");
if (winerror != ERROR_SUCCESS)
UMA_HISTOGRAM_SPARSE_SLOWLY("SharedMemory.CreateWinError", winerror);
}
typedef enum _SECTION_INFORMATION_CLASS {
SectionBasicInformation,
} SECTION_INFORMATION_CLASS;
typedef struct _SECTION_BASIC_INFORMATION {
PVOID BaseAddress;
ULONG Attributes;
LARGE_INTEGER Size;
} SECTION_BASIC_INFORMATION, *PSECTION_BASIC_INFORMATION;
typedef ULONG(__stdcall* NtQuerySectionType)(
HANDLE SectionHandle,
SECTION_INFORMATION_CLASS SectionInformationClass,
PVOID SectionInformation,
ULONG SectionInformationLength,
PULONG ResultLength);
// Returns the length of the memory section starting at the supplied address.
size_t GetMemorySectionSize(void* address) {
MEMORY_BASIC_INFORMATION memory_info;
if (!::VirtualQuery(address, &memory_info, sizeof(memory_info)))
return 0;
return memory_info.RegionSize - (static_cast<char*>(address) -
static_cast<char*>(memory_info.AllocationBase));
}
// Checks if the section object is safe to map. At the moment this just means
// it's not an image section.
bool IsSectionSafeToMap(HANDLE handle) {
static NtQuerySectionType nt_query_section_func;
if (!nt_query_section_func) {
nt_query_section_func = reinterpret_cast<NtQuerySectionType>(
::GetProcAddress(::GetModuleHandle(L"ntdll.dll"), "NtQuerySection"));
DCHECK(nt_query_section_func);
}
// The handle must have SECTION_QUERY access for this to succeed.
SECTION_BASIC_INFORMATION basic_information = {};
ULONG status =
nt_query_section_func(handle, SectionBasicInformation, &basic_information,
sizeof(basic_information), nullptr);
if (status)
return false;
return (basic_information.Attributes & SEC_IMAGE) != SEC_IMAGE;
}
// Returns a HANDLE on success and |nullptr| on failure.
// This function is similar to CreateFileMapping, but removes the permissions
// WRITE_DAC, WRITE_OWNER, READ_CONTROL, and DELETE.
//
// A newly created file mapping has two sets of permissions. It has access
// control permissions (WRITE_DAC, WRITE_OWNER, READ_CONTROL, and DELETE) and
// file permissions (FILE_MAP_READ, FILE_MAP_WRITE, etc.). ::DuplicateHandle()
// with the parameter DUPLICATE_SAME_ACCESS copies both sets of permissions.
//
// The Chrome sandbox prevents HANDLEs with the WRITE_DAC permission from being
// duplicated into unprivileged processes. But the only way to copy file
// permissions is with the parameter DUPLICATE_SAME_ACCESS. This means that
// there is no way for a privileged process to duplicate a file mapping into an
// unprivileged process while maintaining the previous file permissions.
//
// By removing all access control permissions of a file mapping immediately
// after creation, ::DuplicateHandle() effectively only copies the file
// permissions.
HANDLE CreateFileMappingWithReducedPermissions(SECURITY_ATTRIBUTES* sa,
size_t rounded_size,
LPCWSTR name) {
HANDLE h = CreateFileMapping(INVALID_HANDLE_VALUE, sa, PAGE_READWRITE, 0,
static_cast<DWORD>(rounded_size), name);
if (!h) {
LogError(CREATE_FILE_MAPPING_FAILURE, GetLastError());
return nullptr;
}
HANDLE h2;
BOOL success = ::DuplicateHandle(
GetCurrentProcess(), h, GetCurrentProcess(), &h2,
FILE_MAP_READ | FILE_MAP_WRITE | SECTION_QUERY, FALSE, 0);
BOOL rv = ::CloseHandle(h);
DCHECK(rv);
if (!success) {
LogError(REDUCE_PERMISSIONS_FAILURE, GetLastError());
return nullptr;
}
return h2;
}
} // namespace.
namespace base {
SharedMemory::SharedMemory()
: external_section_(false),
mapped_size_(0),
memory_(NULL),
read_only_(false),
requested_size_(0) {}
SharedMemory::SharedMemory(const std::wstring& name)
: external_section_(false),
name_(name),
mapped_size_(0),
memory_(NULL),
read_only_(false),
requested_size_(0) {}
SharedMemory::SharedMemory(const SharedMemoryHandle& handle, bool read_only)
: external_section_(true),
mapped_size_(0),
memory_(NULL),
read_only_(read_only),
requested_size_(0) {
DCHECK(!handle.IsValid() || handle.BelongsToCurrentProcess());
mapped_file_.Set(handle.GetHandle());
}
SharedMemory::~SharedMemory() {
Unmap();
Close();
}
// static
bool SharedMemory::IsHandleValid(const SharedMemoryHandle& handle) {
return handle.IsValid();
}
// static
SharedMemoryHandle SharedMemory::NULLHandle() {
return SharedMemoryHandle();
}
// static
void SharedMemory::CloseHandle(const SharedMemoryHandle& handle) {
handle.Close();
}
// static
size_t SharedMemory::GetHandleLimit() {
// Rounded down from value reported here:
// http://blogs.technet.com/b/markrussinovich/archive/2009/09/29/3283844.aspx
return static_cast<size_t>(1 << 23);
}
// static
SharedMemoryHandle SharedMemory::DuplicateHandle(
const SharedMemoryHandle& handle) {
DCHECK(handle.BelongsToCurrentProcess());
HANDLE duped_handle;
ProcessHandle process = GetCurrentProcess();
BOOL success =
::DuplicateHandle(process, handle.GetHandle(), process, &duped_handle, 0,
FALSE, DUPLICATE_SAME_ACCESS);
if (success) {
base::SharedMemoryHandle handle(duped_handle, GetCurrentProcId());
handle.SetOwnershipPassesToIPC(true);
return handle;
}
return SharedMemoryHandle();
}
bool SharedMemory::CreateAndMapAnonymous(size_t size) {
return CreateAnonymous(size) && Map(size);
}
bool SharedMemory::Create(const SharedMemoryCreateOptions& options) {
// TODO(bsy,sehr): crbug.com/210609 NaCl forces us to round up 64k here,
// wasting 32k per mapping on average.
static const size_t kSectionMask = 65536 - 1;
DCHECK(!options.executable);
DCHECK(!mapped_file_.Get());
if (options.size == 0) {
LogError(SIZE_ZERO, 0);
return false;
}
// Check maximum accounting for overflow.
if (options.size >
static_cast<size_t>(std::numeric_limits<int>::max()) - kSectionMask) {
LogError(SIZE_TOO_LARGE, 0);
return false;
}
size_t rounded_size = (options.size + kSectionMask) & ~kSectionMask;
name_ = options.name_deprecated ?
ASCIIToUTF16(*options.name_deprecated) : L"";
SECURITY_ATTRIBUTES sa = { sizeof(sa), NULL, FALSE };
SECURITY_DESCRIPTOR sd;
ACL dacl;
if (name_.empty()) {
// Add an empty DACL to enforce anonymous read-only sections.
sa.lpSecurityDescriptor = &sd;
if (!InitializeAcl(&dacl, sizeof(dacl), ACL_REVISION)) {
LogError(INITIALIZE_ACL_FAILURE, GetLastError());
return false;
}
if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) {
LogError(INITIALIZE_SECURITY_DESC_FAILURE, GetLastError());
return false;
}
if (!SetSecurityDescriptorDacl(&sd, TRUE, &dacl, FALSE)) {
LogError(SET_SECURITY_DESC_FAILURE, GetLastError());
return false;
}
// Windows ignores DACLs on certain unnamed objects (like shared sections).
// So, we generate a random name when we need to enforce read-only.
uint64_t rand_values[4];
RandBytes(&rand_values, sizeof(rand_values));
name_ = StringPrintf(L"CrSharedMem_%016llx%016llx%016llx%016llx",
rand_values[0], rand_values[1],
rand_values[2], rand_values[3]);
}
mapped_file_.Set(CreateFileMappingWithReducedPermissions(
&sa, rounded_size, name_.empty() ? nullptr : name_.c_str()));
if (!mapped_file_.IsValid()) {
// The error is logged within CreateFileMappingWithReducedPermissions().
return false;
}
requested_size_ = options.size;
// Check if the shared memory pre-exists.
if (GetLastError() == ERROR_ALREADY_EXISTS) {
// If the file already existed, set requested_size_ to 0 to show that
// we don't know the size.
requested_size_ = 0;
external_section_ = true;
if (!options.open_existing_deprecated) {
Close();
// From "if" above: GetLastError() == ERROR_ALREADY_EXISTS.
LogError(ALREADY_EXISTS, ERROR_ALREADY_EXISTS);
return false;
}
}
LogError(SUCCESS, ERROR_SUCCESS);
return true;
}
bool SharedMemory::Delete(const std::string& name) {
// intentionally empty -- there is nothing for us to do on Windows.
return true;
}
bool SharedMemory::Open(const std::string& name, bool read_only) {
DCHECK(!mapped_file_.Get());
DWORD access = FILE_MAP_READ | SECTION_QUERY;
if (!read_only)
access |= FILE_MAP_WRITE;
name_ = ASCIIToUTF16(name);
read_only_ = read_only;
mapped_file_.Set(
OpenFileMapping(access, false, name_.empty() ? nullptr : name_.c_str()));
if (!mapped_file_.IsValid())
return false;
// If a name specified assume it's an external section.
if (!name_.empty())
external_section_ = true;
// Note: size_ is not set in this case.
return true;
}
bool SharedMemory::MapAt(off_t offset, size_t bytes) {
if (!mapped_file_.Get())
return false;
if (bytes > static_cast<size_t>(std::numeric_limits<int>::max()))
return false;
if (memory_)
return false;
if (external_section_ && !IsSectionSafeToMap(mapped_file_.Get()))
return false;
memory_ = MapViewOfFile(
mapped_file_.Get(),
read_only_ ? FILE_MAP_READ : FILE_MAP_READ | FILE_MAP_WRITE,
static_cast<uint64_t>(offset) >> 32, static_cast<DWORD>(offset), bytes);
if (memory_ != NULL) {
DCHECK_EQ(0U, reinterpret_cast<uintptr_t>(memory_) &
(SharedMemory::MAP_MINIMUM_ALIGNMENT - 1));
mapped_size_ = GetMemorySectionSize(memory_);
return true;
}
return false;
}
bool SharedMemory::Unmap() {
if (memory_ == NULL)
return false;
UnmapViewOfFile(memory_);
memory_ = NULL;
return true;
}
bool SharedMemory::ShareToProcessCommon(ProcessHandle process,
SharedMemoryHandle* new_handle,
bool close_self,
ShareMode share_mode) {
*new_handle = SharedMemoryHandle();
DWORD access = FILE_MAP_READ | SECTION_QUERY;
DWORD options = 0;
HANDLE mapped_file = mapped_file_.Get();
HANDLE result;
if (share_mode == SHARE_CURRENT_MODE && !read_only_)
access |= FILE_MAP_WRITE;
if (close_self) {
// DUPLICATE_CLOSE_SOURCE causes DuplicateHandle to close mapped_file.
options = DUPLICATE_CLOSE_SOURCE;
HANDLE detached_handle = mapped_file_.Take();
DCHECK_EQ(detached_handle, mapped_file);
Unmap();
}
if (process == GetCurrentProcess() && close_self) {
*new_handle = SharedMemoryHandle(mapped_file, base::GetCurrentProcId());
return true;
}
if (!::DuplicateHandle(GetCurrentProcess(), mapped_file, process, &result,
access, FALSE, options)) {
return false;
}
*new_handle = SharedMemoryHandle(result, base::GetProcId(process));
new_handle->SetOwnershipPassesToIPC(true);
return true;
}
void SharedMemory::Close() {
mapped_file_.Close();
}
SharedMemoryHandle SharedMemory::handle() const {
return SharedMemoryHandle(mapped_file_.Get(), base::GetCurrentProcId());
}
SharedMemoryHandle SharedMemory::TakeHandle() {
SharedMemoryHandle handle(mapped_file_.Take(), base::GetCurrentProcId());
handle.SetOwnershipPassesToIPC(true);
memory_ = nullptr;
mapped_size_ = 0;
return handle;
}
} // namespace base

View File

@ -22,6 +22,7 @@
#include "base/at_exit.h"
#include "base/atomicops.h"
#include "base/base_export.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/aligned_memory.h"
#include "base/threading/thread_restrictions.h"
@ -63,7 +64,7 @@ struct DefaultSingletonTraits {
// exit. See below for the required call that makes this happen.
static const bool kRegisterAtExit = true;
#ifndef NDEBUG
#if DCHECK_IS_ON()
// Set to false to disallow access on a non-joinable thread. This is
// different from kRegisterAtExit because StaticMemorySingletonTraits allows
// access on non-joinable threads, and gracefully handles this.
@ -78,7 +79,7 @@ struct DefaultSingletonTraits {
template<typename Type>
struct LeakySingletonTraits : public DefaultSingletonTraits<Type> {
static const bool kRegisterAtExit = false;
#ifndef NDEBUG
#if DCHECK_IS_ON()
static const bool kAllowedToAccessOnNonjoinableThread = true;
#endif
};
@ -227,7 +228,7 @@ class Singleton {
// Return a pointer to the one true instance of the class.
static Type* get() {
#ifndef NDEBUG
#if DCHECK_IS_ON()
// Avoid making TLS lookup on release builds.
if (!Traits::kAllowedToAccessOnNonjoinableThread)
ThreadRestrictions::AssertSingletonAllowed();

View File

@ -3,7 +3,7 @@
// found in the LICENSE file.
// Weak pointers are pointers to an object that do not affect its lifetime,
// and which may be invalidated (i.e. reset to NULL) by the object, or its
// and which may be invalidated (i.e. reset to nullptr) by the object, or its
// owner, at any time, most commonly when the object is about to be deleted.
// Weak pointers are useful when an object needs to be accessed safely by one
@ -70,12 +70,14 @@
#ifndef BASE_MEMORY_WEAK_PTR_H_
#define BASE_MEMORY_WEAK_PTR_H_
#include <cstddef>
#include <type_traits>
#include "base/base_export.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/sequence_checker.h"
#include "base/template_util.h"
namespace base {
@ -110,6 +112,11 @@ class BASE_EXPORT WeakReference {
explicit WeakReference(const Flag* flag);
~WeakReference();
WeakReference(WeakReference&& other);
WeakReference(const WeakReference& other);
WeakReference& operator=(WeakReference&& other) = default;
WeakReference& operator=(const WeakReference& other) = default;
bool is_valid() const;
private:
@ -142,6 +149,11 @@ class BASE_EXPORT WeakPtrBase {
WeakPtrBase();
~WeakPtrBase();
WeakPtrBase(const WeakPtrBase& other) = default;
WeakPtrBase(WeakPtrBase&& other) = default;
WeakPtrBase& operator=(const WeakPtrBase& other) = default;
WeakPtrBase& operator=(WeakPtrBase&& other) = default;
protected:
explicit WeakPtrBase(const WeakReference& ref);
@ -159,10 +171,9 @@ class SupportsWeakPtrBase {
// function that makes calling this easier.
template<typename Derived>
static WeakPtr<Derived> StaticAsWeakPtr(Derived* t) {
typedef
is_convertible<Derived, internal::SupportsWeakPtrBase&> convertible;
static_assert(convertible::value,
"AsWeakPtr argument must inherit from SupportsWeakPtr");
static_assert(
std::is_base_of<internal::SupportsWeakPtrBase, Derived>::value,
"AsWeakPtr argument must inherit from SupportsWeakPtr");
return AsWeakPtrImpl<Derived>(t, *t);
}
@ -198,50 +209,39 @@ template <typename T> class WeakPtrFactory;
template <typename T>
class WeakPtr : public internal::WeakPtrBase {
public:
WeakPtr() : ptr_(NULL) {
}
WeakPtr() : ptr_(nullptr) {}
WeakPtr(std::nullptr_t) : ptr_(nullptr) {}
// Allow conversion from U to T provided U "is a" T. Note that this
// is separate from the (implicit) copy constructor.
// is separate from the (implicit) copy and move constructors.
template <typename U>
WeakPtr(const WeakPtr<U>& other) : WeakPtrBase(other), ptr_(other.ptr_) {
}
template <typename U>
WeakPtr(WeakPtr<U>&& other)
: WeakPtrBase(std::move(other)), ptr_(other.ptr_) {}
T* get() const { return ref_.is_valid() ? ptr_ : NULL; }
T* get() const { return ref_.is_valid() ? ptr_ : nullptr; }
T& operator*() const {
DCHECK(get() != NULL);
DCHECK(get() != nullptr);
return *get();
}
T* operator->() const {
DCHECK(get() != NULL);
DCHECK(get() != nullptr);
return get();
}
// Allow WeakPtr<element_type> to be used in boolean expressions, but not
// implicitly convertible to a real bool (which is dangerous).
//
// Note that this trick is only safe when the == and != operators
// are declared explicitly, as otherwise "weak_ptr1 == weak_ptr2"
// will compile but do the wrong thing (i.e., convert to Testable
// and then do the comparison).
private:
typedef T* WeakPtr::*Testable;
public:
operator Testable() const { return get() ? &WeakPtr::ptr_ : NULL; }
void reset() {
ref_ = internal::WeakReference();
ptr_ = NULL;
ptr_ = nullptr;
}
private:
// Explicitly declare comparison operators as required by the bool
// trick, but keep them private.
template <class U> bool operator==(WeakPtr<U> const&) const;
template <class U> bool operator!=(WeakPtr<U> const&) const;
// Allow conditionals to test validity, e.g. if (weak_ptr) {...};
explicit operator bool() const { return get() != nullptr; }
private:
friend class internal::SupportsWeakPtrBase;
template <typename U> friend class WeakPtr;
friend class SupportsWeakPtr<T>;
@ -253,10 +253,28 @@ class WeakPtr : public internal::WeakPtrBase {
}
// This pointer is only valid when ref_.is_valid() is true. Otherwise, its
// value is undefined (as opposed to NULL).
// value is undefined (as opposed to nullptr).
T* ptr_;
};
// Allow callers to compare WeakPtrs against nullptr to test validity.
template <class T>
bool operator!=(const WeakPtr<T>& weak_ptr, std::nullptr_t) {
return !(weak_ptr == nullptr);
}
template <class T>
bool operator!=(std::nullptr_t, const WeakPtr<T>& weak_ptr) {
return weak_ptr != nullptr;
}
template <class T>
bool operator==(const WeakPtr<T>& weak_ptr, std::nullptr_t) {
return weak_ptr.get() == nullptr;
}
template <class T>
bool operator==(std::nullptr_t, const WeakPtr<T>& weak_ptr) {
return weak_ptr == nullptr;
}
// A class may be composed of a WeakPtrFactory and thereby
// control how it exposes weak pointers to itself. This is helpful if you only
// need weak pointers within the implementation of a class. This class is also
@ -268,9 +286,7 @@ class WeakPtrFactory {
explicit WeakPtrFactory(T* ptr) : ptr_(ptr) {
}
~WeakPtrFactory() {
ptr_ = NULL;
}
~WeakPtrFactory() { ptr_ = nullptr; }
WeakPtr<T> GetWeakPtr() {
DCHECK(ptr_);

View File

@ -1,57 +0,0 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_MOVE_H_
#define BASE_MOVE_H_
#include <utility>
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "build/build_config.h"
// TODO(crbug.com/566182): DEPRECATED!
// Use DISALLOW_COPY_AND_ASSIGN instead, or if your type will be used in
// Callbacks, use DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND instead.
#define MOVE_ONLY_TYPE_FOR_CPP_03(type) \
DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND(type)
// A macro to disallow the copy constructor and copy assignment functions.
// This should be used in the private: declarations for a class.
//
// Use this macro instead of DISALLOW_COPY_AND_ASSIGN if you want to pass
// ownership of the type through a base::Callback without heap-allocating it
// into a scoped_ptr. The class must define a move constructor and move
// assignment operator to make this work.
//
// This version of the macro adds a Pass() function and a cryptic
// MoveOnlyTypeForCPP03 typedef for the base::Callback implementation to use.
// See IsMoveOnlyType template and its usage in base/callback_internal.h
// for more details.
// TODO(crbug.com/566182): Remove this macro and use DISALLOW_COPY_AND_ASSIGN
// everywhere instead.
#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_MACOSX)
#define DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND(type) \
private: \
type(const type&) = delete; \
void operator=(const type&) = delete; \
\
public: \
typedef void MoveOnlyTypeForCPP03; \
\
private:
#else
#define DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND(type) \
private: \
type(const type&) = delete; \
void operator=(const type&) = delete; \
\
public: \
type&& Pass() WARN_UNUSED_RESULT { return std::move(*this); } \
typedef void MoveOnlyTypeForCPP03; \
\
private:
#endif
#endif // BASE_MOVE_H_

View File

@ -18,7 +18,7 @@ namespace base {
// Convenience function that returns true if the supplied value is in range
// for the destination type.
template <typename Dst, typename Src>
inline bool IsValueInRangeForNumericType(Src value) {
constexpr bool IsValueInRangeForNumericType(Src value) {
return internal::DstRangeRelationToSrcRange<Dst>(value) ==
internal::RANGE_VALID;
}
@ -26,7 +26,7 @@ inline bool IsValueInRangeForNumericType(Src value) {
// Convenience function for determining if a numeric value is negative without
// throwing compiler warnings on: unsigned(value) < 0.
template <typename T>
typename std::enable_if<std::numeric_limits<T>::is_signed, bool>::type
constexpr typename std::enable_if<std::numeric_limits<T>::is_signed, bool>::type
IsValueNegative(T value) {
static_assert(std::numeric_limits<T>::is_specialized,
"Argument must be numeric.");
@ -34,39 +34,62 @@ IsValueNegative(T value) {
}
template <typename T>
typename std::enable_if<!std::numeric_limits<T>::is_signed, bool>::type
IsValueNegative(T) {
constexpr typename std::enable_if<!std::numeric_limits<T>::is_signed,
bool>::type IsValueNegative(T) {
static_assert(std::numeric_limits<T>::is_specialized,
"Argument must be numeric.");
return false;
}
// checked_cast<> is analogous to static_cast<> for numeric types,
// except that it CHECKs that the specified numeric conversion will not
// overflow or underflow. NaN source will always trigger a CHECK.
template <typename Dst, typename Src>
inline Dst checked_cast(Src value) {
CHECK(IsValueInRangeForNumericType<Dst>(value));
return static_cast<Dst>(value);
}
// HandleNaN will cause this class to CHECK(false).
struct SaturatedCastNaNBehaviorCheck {
// Just fires a CHECK(false). Used for numeric boundary errors.
struct CheckOnFailure {
template <typename T>
static T HandleNaN() {
static T HandleFailure() {
CHECK(false);
return T();
}
};
// checked_cast<> is analogous to static_cast<> for numeric types,
// except that it CHECKs that the specified numeric conversion will not
// overflow or underflow. NaN source will always trigger a CHECK.
template <typename Dst,
class CheckHandler = CheckOnFailure,
typename Src>
constexpr Dst checked_cast(Src value) {
// This throws a compile-time error on evaluating the constexpr if it can be
// determined at compile-time as failing, otherwise it will CHECK at runtime.
return IsValueInRangeForNumericType<Dst>(value)
? static_cast<Dst>(value)
: CheckHandler::template HandleFailure<Dst>();
}
// HandleNaN will return 0 in this case.
struct SaturatedCastNaNBehaviorReturnZero {
template <typename T>
static T HandleNaN() {
static constexpr T HandleFailure() {
return T();
}
};
namespace internal {
// This wrapper is used for C++11 constexpr support by avoiding the declaration
// of local variables in the saturated_cast template function.
template <typename Dst, class NaNHandler, typename Src>
constexpr Dst saturated_cast_impl(const Src value,
const RangeConstraint constraint) {
return constraint == RANGE_VALID
? static_cast<Dst>(value)
: (constraint == RANGE_UNDERFLOW
? std::numeric_limits<Dst>::min()
: (constraint == RANGE_OVERFLOW
? std::numeric_limits<Dst>::max()
: (constraint == RANGE_INVALID
? NaNHandler::template HandleFailure<Dst>()
: (NOTREACHED(), static_cast<Dst>(value)))));
}
} // namespace internal
// saturated_cast<> is analogous to static_cast<> for numeric types, except
// that the specified numeric conversion will saturate rather than overflow or
// underflow. NaN assignment to an integral will defer the behavior to a
@ -74,35 +97,18 @@ struct SaturatedCastNaNBehaviorReturnZero {
template <typename Dst,
class NaNHandler = SaturatedCastNaNBehaviorReturnZero,
typename Src>
inline Dst saturated_cast(Src value) {
// Optimization for floating point values, which already saturate.
if (std::numeric_limits<Dst>::is_iec559)
return static_cast<Dst>(value);
switch (internal::DstRangeRelationToSrcRange<Dst>(value)) {
case internal::RANGE_VALID:
return static_cast<Dst>(value);
case internal::RANGE_UNDERFLOW:
return std::numeric_limits<Dst>::min();
case internal::RANGE_OVERFLOW:
return std::numeric_limits<Dst>::max();
// Should fail only on attempting to assign NaN to a saturated integer.
case internal::RANGE_INVALID:
return NaNHandler::template HandleNaN<Dst>();
}
NOTREACHED();
return static_cast<Dst>(value);
constexpr Dst saturated_cast(Src value) {
return std::numeric_limits<Dst>::is_iec559
? static_cast<Dst>(value) // Floating point optimization.
: internal::saturated_cast_impl<Dst, NaNHandler>(
value, internal::DstRangeRelationToSrcRange<Dst>(value));
}
// strict_cast<> is analogous to static_cast<> for numeric types, except that
// it will cause a compile failure if the destination type is not large enough
// to contain any value in the source type. It performs no runtime checking.
template <typename Dst, typename Src>
inline Dst strict_cast(Src value) {
constexpr Dst strict_cast(Src value) {
static_assert(std::numeric_limits<Src>::is_specialized,
"Argument must be numeric.");
static_assert(std::numeric_limits<Dst>::is_specialized,
@ -128,33 +134,33 @@ inline Dst strict_cast(Src value) {
// compiles cleanly with truncation warnings enabled.
// This template should introduce no runtime overhead, but it also provides no
// runtime checking of any of the associated mathematical operations. Use
// CheckedNumeric for runtime range checks of tha actual value being assigned.
// CheckedNumeric for runtime range checks of the actual value being assigned.
template <typename T>
class StrictNumeric {
public:
typedef T type;
StrictNumeric() : value_(0) {}
constexpr StrictNumeric() : value_(0) {}
// Copy constructor.
template <typename Src>
StrictNumeric(const StrictNumeric<Src>& rhs)
constexpr StrictNumeric(const StrictNumeric<Src>& rhs)
: value_(strict_cast<T>(rhs.value_)) {}
// This is not an explicit constructor because we implicitly upgrade regular
// numerics to StrictNumerics to make them easier to use.
template <typename Src>
StrictNumeric(Src value)
constexpr StrictNumeric(Src value)
: value_(strict_cast<T>(value)) {}
// The numeric cast operator basically handles all the magic.
template <typename Dst>
operator Dst() const {
constexpr operator Dst() const {
return strict_cast<Dst>(value_);
}
private:
T value_;
const T value_;
};
// Explicitly make a shorter size_t typedef for convenience.

View File

@ -8,9 +8,9 @@
#include <limits.h>
#include <stdint.h>
#include <climits>
#include <limits>
#include "base/template_util.h"
#include <type_traits>
namespace base {
namespace internal {
@ -20,9 +20,11 @@ namespace internal {
// for accurate range comparisons between floating point and integer types.
template <typename NumericType>
struct MaxExponent {
static_assert(std::is_arithmetic<NumericType>::value,
"Argument must be numeric.");
static const int value = std::numeric_limits<NumericType>::is_iec559
? std::numeric_limits<NumericType>::max_exponent
: (sizeof(NumericType) * 8 + 1 -
: (sizeof(NumericType) * CHAR_BIT + 1 -
std::numeric_limits<NumericType>::is_signed);
};
@ -96,17 +98,18 @@ enum RangeConstraint {
};
// Helper function for coercing an int back to a RangeContraint.
inline RangeConstraint GetRangeConstraint(int integer_range_constraint) {
DCHECK(integer_range_constraint >= RANGE_VALID &&
integer_range_constraint <= RANGE_INVALID);
constexpr RangeConstraint GetRangeConstraint(int integer_range_constraint) {
// TODO(jschuh): Once we get full C++14 support we want this
// assert(integer_range_constraint >= RANGE_VALID &&
// integer_range_constraint <= RANGE_INVALID)
return static_cast<RangeConstraint>(integer_range_constraint);
}
// This function creates a RangeConstraint from an upper and lower bound
// check by taking advantage of the fact that only NaN can be out of range in
// both directions at once.
inline RangeConstraint GetRangeConstraint(bool is_in_upper_bound,
bool is_in_lower_bound) {
constexpr inline RangeConstraint GetRangeConstraint(bool is_in_upper_bound,
bool is_in_lower_bound) {
return GetRangeConstraint((is_in_upper_bound ? 0 : RANGE_OVERFLOW) |
(is_in_lower_bound ? 0 : RANGE_UNDERFLOW));
}
@ -136,25 +139,24 @@ template <typename Dst, typename Src>
struct NarrowingRange {
typedef typename std::numeric_limits<Src> SrcLimits;
typedef typename std::numeric_limits<Dst> DstLimits;
// The following logic avoids warnings where the max function is
// instantiated with invalid values for a bit shift (even though
// such a function can never be called).
static const int shift = (MaxExponent<Src>::value > MaxExponent<Dst>::value &&
SrcLimits::digits < DstLimits::digits &&
SrcLimits::is_iec559 &&
DstLimits::is_integer)
? (DstLimits::digits - SrcLimits::digits)
: 0;
static Dst max() {
// The following logic avoids warnings where the max function is
// instantiated with invalid values for a bit shift (even though
// such a function can never be called).
static const int shift =
(MaxExponent<Src>::value > MaxExponent<Dst>::value &&
SrcLimits::digits < DstLimits::digits && SrcLimits::is_iec559 &&
DstLimits::is_integer)
? (DstLimits::digits - SrcLimits::digits)
: 0;
static constexpr Dst max() {
// We use UINTMAX_C below to avoid compiler warnings about shifting floating
// points. Since it's a compile time calculation, it shouldn't have any
// performance impact.
return DstLimits::max() - static_cast<Dst>((UINTMAX_C(1) << shift) - 1);
}
static Dst min() {
static constexpr Dst min() {
return std::numeric_limits<Dst>::is_iec559 ? -DstLimits::max()
: DstLimits::min();
}
@ -187,7 +189,7 @@ struct DstRangeRelationToSrcRangeImpl<Dst,
DstSign,
SrcSign,
NUMERIC_RANGE_CONTAINED> {
static RangeConstraint Check(Src value) { return RANGE_VALID; }
static constexpr RangeConstraint Check(Src value) { return RANGE_VALID; }
};
// Signed to signed narrowing: Both the upper and lower boundaries may be
@ -198,7 +200,7 @@ struct DstRangeRelationToSrcRangeImpl<Dst,
INTEGER_REPRESENTATION_SIGNED,
INTEGER_REPRESENTATION_SIGNED,
NUMERIC_RANGE_NOT_CONTAINED> {
static RangeConstraint Check(Src value) {
static constexpr RangeConstraint Check(Src value) {
return GetRangeConstraint((value <= NarrowingRange<Dst, Src>::max()),
(value >= NarrowingRange<Dst, Src>::min()));
}
@ -211,7 +213,7 @@ struct DstRangeRelationToSrcRangeImpl<Dst,
INTEGER_REPRESENTATION_UNSIGNED,
INTEGER_REPRESENTATION_UNSIGNED,
NUMERIC_RANGE_NOT_CONTAINED> {
static RangeConstraint Check(Src value) {
static constexpr RangeConstraint Check(Src value) {
return GetRangeConstraint(value <= NarrowingRange<Dst, Src>::max(), true);
}
};
@ -223,7 +225,7 @@ struct DstRangeRelationToSrcRangeImpl<Dst,
INTEGER_REPRESENTATION_SIGNED,
INTEGER_REPRESENTATION_UNSIGNED,
NUMERIC_RANGE_NOT_CONTAINED> {
static RangeConstraint Check(Src value) {
static constexpr RangeConstraint Check(Src value) {
return sizeof(Dst) > sizeof(Src)
? RANGE_VALID
: GetRangeConstraint(
@ -240,7 +242,7 @@ struct DstRangeRelationToSrcRangeImpl<Dst,
INTEGER_REPRESENTATION_UNSIGNED,
INTEGER_REPRESENTATION_SIGNED,
NUMERIC_RANGE_NOT_CONTAINED> {
static RangeConstraint Check(Src value) {
static constexpr RangeConstraint Check(Src value) {
return (MaxExponent<Dst>::value >= MaxExponent<Src>::value)
? GetRangeConstraint(true, value >= static_cast<Src>(0))
: GetRangeConstraint(
@ -250,7 +252,7 @@ struct DstRangeRelationToSrcRangeImpl<Dst,
};
template <typename Dst, typename Src>
inline RangeConstraint DstRangeRelationToSrcRange(Src value) {
constexpr RangeConstraint DstRangeRelationToSrcRange(Src value) {
static_assert(std::numeric_limits<Src>::is_specialized,
"Argument must be numeric.");
static_assert(std::numeric_limits<Dst>::is_specialized,

View File

@ -7,6 +7,10 @@
#include <stddef.h>
#include <limits>
#include <type_traits>
#include "base/logging.h"
#include "base/numerics/safe_math_impl.h"
namespace base {
@ -44,6 +48,9 @@ namespace internal {
// Do stuff...
template <typename T>
class CheckedNumeric {
static_assert(std::is_arithmetic<T>::value,
"CheckedNumeric<T>: T must be a numeric type.");
public:
typedef T type;
@ -52,16 +59,15 @@ class CheckedNumeric {
// Copy constructor.
template <typename Src>
CheckedNumeric(const CheckedNumeric<Src>& rhs)
: state_(rhs.ValueUnsafe(), rhs.validity()) {}
: state_(rhs.ValueUnsafe(), rhs.IsValid()) {}
template <typename Src>
CheckedNumeric(Src value, RangeConstraint validity)
: state_(value, validity) {}
CheckedNumeric(Src value, bool is_valid) : state_(value, is_valid) {}
// This is not an explicit constructor because we implicitly upgrade regular
// numerics to CheckedNumerics to make them easier to use.
template <typename Src>
CheckedNumeric(Src value)
CheckedNumeric(Src value) // NOLINT(runtime/explicit)
: state_(value) {
static_assert(std::numeric_limits<Src>::is_specialized,
"Argument must be numeric.");
@ -70,12 +76,12 @@ class CheckedNumeric {
// This is not an explicit constructor because we want a seamless conversion
// from StrictNumeric types.
template <typename Src>
CheckedNumeric(StrictNumeric<Src> value)
CheckedNumeric(StrictNumeric<Src> value) // NOLINT(runtime/explicit)
: state_(static_cast<Src>(value)) {
}
// IsValid() is the public API to test if a CheckedNumeric is currently valid.
bool IsValid() const { return validity() == RANGE_VALID; }
bool IsValid() const { return state_.is_valid(); }
// ValueOrDie() The primary accessor for the underlying value. If the current
// state is not valid it will CHECK and crash.
@ -99,51 +105,42 @@ class CheckedNumeric {
return CheckedNumeric<T>::cast(*this).ValueUnsafe();
}
// validity() - DO NOT USE THIS IN EXTERNAL CODE - It is public right now for
// tests and to avoid a big matrix of friend operator overloads. But the
// values it returns are likely to change in the future.
// Returns: current validity state (i.e. valid, overflow, underflow, nan).
// TODO(jschuh): crbug.com/332611 Figure out and implement semantics for
// saturation/wrapping so we can expose this state consistently and implement
// saturated arithmetic.
RangeConstraint validity() const { return state_.validity(); }
// ValueUnsafe() - DO NOT USE THIS IN EXTERNAL CODE - It is public right now
// for tests and to avoid a big matrix of friend operator overloads. But the
// values it returns are likely to change in the future.
// values it returns are unintuitive and likely to change in the future.
// Returns: the raw numeric value, regardless of the current state.
// TODO(jschuh): crbug.com/332611 Figure out and implement semantics for
// saturation/wrapping so we can expose this state consistently and implement
// saturated arithmetic.
T ValueUnsafe() const { return state_.value(); }
// Prototypes for the supported arithmetic operator overloads.
template <typename Src> CheckedNumeric& operator+=(Src rhs);
template <typename Src> CheckedNumeric& operator-=(Src rhs);
template <typename Src> CheckedNumeric& operator*=(Src rhs);
template <typename Src> CheckedNumeric& operator/=(Src rhs);
template <typename Src> CheckedNumeric& operator%=(Src rhs);
template <typename Src>
CheckedNumeric& operator+=(Src rhs);
template <typename Src>
CheckedNumeric& operator-=(Src rhs);
template <typename Src>
CheckedNumeric& operator*=(Src rhs);
template <typename Src>
CheckedNumeric& operator/=(Src rhs);
template <typename Src>
CheckedNumeric& operator%=(Src rhs);
template <typename Src>
CheckedNumeric& operator<<=(Src rhs);
template <typename Src>
CheckedNumeric& operator>>=(Src rhs);
CheckedNumeric operator-() const {
RangeConstraint validity;
T value = CheckedNeg(state_.value(), &validity);
// Negation is always valid for floating point.
if (std::numeric_limits<T>::is_iec559)
return CheckedNumeric<T>(value);
validity = GetRangeConstraint(state_.validity() | validity);
return CheckedNumeric<T>(value, validity);
T value = 0;
bool is_valid = (std::numeric_limits<T>::is_iec559 || IsValid()) &&
CheckedNeg(state_.value(), &value);
return CheckedNumeric<T>(value, is_valid);
}
CheckedNumeric Abs() const {
RangeConstraint validity;
T value = CheckedAbs(state_.value(), &validity);
// Absolute value is always valid for floating point.
if (std::numeric_limits<T>::is_iec559)
return CheckedNumeric<T>(value);
validity = GetRangeConstraint(state_.validity() | validity);
return CheckedNumeric<T>(value, validity);
T value = 0;
bool is_valid = (std::numeric_limits<T>::is_iec559 || IsValid()) &&
CheckedAbs(state_.value(), &value);
return CheckedNumeric<T>(value, is_valid);
}
// This function is available only for integral types. It returns an unsigned
@ -151,7 +148,7 @@ class CheckedNumeric {
// of the source, and properly handling signed min.
CheckedNumeric<typename UnsignedOrFloatForSize<T>::type> UnsignedAbs() const {
return CheckedNumeric<typename UnsignedOrFloatForSize<T>::type>(
CheckedUnsignedAbs(state_.value()), state_.validity());
SafeUnsignedAbs(state_.value()), state_.is_valid());
}
CheckedNumeric& operator++() {
@ -190,23 +187,13 @@ class CheckedNumeric {
template <typename Src>
static CheckedNumeric<T> cast(
const CheckedNumeric<Src>& u,
typename std::enable_if<!is_same<Src, T>::value, int>::type = 0) {
typename std::enable_if<!std::is_same<Src, T>::value, int>::type = 0) {
return u;
}
static const CheckedNumeric<T>& cast(const CheckedNumeric<T>& u) { return u; }
private:
template <typename NumericType>
struct UnderlyingType {
using type = NumericType;
};
template <typename NumericType>
struct UnderlyingType<CheckedNumeric<NumericType>> {
using type = NumericType;
};
CheckedNumericState<T> state_;
};
@ -217,76 +204,53 @@ class CheckedNumeric {
// * We skip range checks for floating points.
// * We skip range checks for destination integers with sufficient range.
// TODO(jschuh): extract these out into templates.
#define BASE_NUMERIC_ARITHMETIC_OPERATORS(NAME, OP, COMPOUND_OP) \
#define BASE_NUMERIC_ARITHMETIC_OPERATORS(NAME, OP, COMPOUND_OP, PROMOTION) \
/* Binary arithmetic operator for CheckedNumerics of the same type. */ \
template <typename T> \
CheckedNumeric<typename ArithmeticPromotion<T>::type> operator OP( \
const CheckedNumeric<T>& lhs, const CheckedNumeric<T>& rhs) { \
typedef typename ArithmeticPromotion<T>::type Promotion; \
template <typename L, typename R> \
CheckedNumeric<typename ArithmeticPromotion<PROMOTION, L, R>::type> \
operator OP(const CheckedNumeric<L>& lhs, const CheckedNumeric<R>& rhs) { \
using P = typename ArithmeticPromotion<PROMOTION, L, R>::type; \
if (!rhs.IsValid() || !lhs.IsValid()) \
return CheckedNumeric<P>(0, false); \
/* Floating point always takes the fast path */ \
if (std::numeric_limits<T>::is_iec559) \
return CheckedNumeric<T>(lhs.ValueUnsafe() OP rhs.ValueUnsafe()); \
if (IsIntegerArithmeticSafe<Promotion, T, T>::value) \
return CheckedNumeric<Promotion>( \
lhs.ValueUnsafe() OP rhs.ValueUnsafe(), \
GetRangeConstraint(rhs.validity() | lhs.validity())); \
RangeConstraint validity = RANGE_VALID; \
T result = static_cast<T>(Checked##NAME( \
static_cast<Promotion>(lhs.ValueUnsafe()), \
static_cast<Promotion>(rhs.ValueUnsafe()), \
&validity)); \
return CheckedNumeric<Promotion>( \
result, \
GetRangeConstraint(validity | lhs.validity() | rhs.validity())); \
if (std::is_floating_point<L>::value || std::is_floating_point<R>::value) \
return CheckedNumeric<P>(lhs.ValueUnsafe() OP rhs.ValueUnsafe()); \
P result = 0; \
bool is_valid = \
Checked##NAME(lhs.ValueUnsafe(), rhs.ValueUnsafe(), &result); \
return CheckedNumeric<P>(result, is_valid); \
} \
/* Assignment arithmetic operator implementation from CheckedNumeric. */ \
template <typename T> \
template <typename Src> \
CheckedNumeric<T>& CheckedNumeric<T>::operator COMPOUND_OP(Src rhs) { \
*this = CheckedNumeric<T>::cast(*this) \
OP CheckedNumeric<typename UnderlyingType<Src>::type>::cast(rhs); \
template <typename L> \
template <typename R> \
CheckedNumeric<L>& CheckedNumeric<L>::operator COMPOUND_OP(R rhs) { \
*this = *this OP rhs; \
return *this; \
} \
/* Binary arithmetic operator for CheckedNumeric of different type. */ \
template <typename T, typename Src> \
CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP( \
const CheckedNumeric<Src>& lhs, const CheckedNumeric<T>& rhs) { \
typedef typename ArithmeticPromotion<T, Src>::type Promotion; \
if (IsIntegerArithmeticSafe<Promotion, T, Src>::value) \
return CheckedNumeric<Promotion>( \
lhs.ValueUnsafe() OP rhs.ValueUnsafe(), \
GetRangeConstraint(rhs.validity() | lhs.validity())); \
return CheckedNumeric<Promotion>::cast(lhs) \
OP CheckedNumeric<Promotion>::cast(rhs); \
} \
/* Binary arithmetic operator for left CheckedNumeric and right numeric. */ \
template <typename T, typename Src> \
CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP( \
const CheckedNumeric<T>& lhs, Src rhs) { \
typedef typename ArithmeticPromotion<T, Src>::type Promotion; \
if (IsIntegerArithmeticSafe<Promotion, T, Src>::value) \
return CheckedNumeric<Promotion>(lhs.ValueUnsafe() OP rhs, \
lhs.validity()); \
return CheckedNumeric<Promotion>::cast(lhs) \
OP CheckedNumeric<Promotion>::cast(rhs); \
template <typename L, typename R, \
typename std::enable_if<std::is_arithmetic<R>::value>::type* = \
nullptr> \
CheckedNumeric<typename ArithmeticPromotion<PROMOTION, L, R>::type> \
operator OP(const CheckedNumeric<L>& lhs, R rhs) { \
return lhs OP CheckedNumeric<R>(rhs); \
} \
/* Binary arithmetic operator for right numeric and left CheckedNumeric. */ \
template <typename T, typename Src> \
CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP( \
Src lhs, const CheckedNumeric<T>& rhs) { \
typedef typename ArithmeticPromotion<T, Src>::type Promotion; \
if (IsIntegerArithmeticSafe<Promotion, T, Src>::value) \
return CheckedNumeric<Promotion>(lhs OP rhs.ValueUnsafe(), \
rhs.validity()); \
return CheckedNumeric<Promotion>::cast(lhs) \
OP CheckedNumeric<Promotion>::cast(rhs); \
/* Binary arithmetic operator for left numeric and right CheckedNumeric. */ \
template <typename L, typename R, \
typename std::enable_if<std::is_arithmetic<L>::value>::type* = \
nullptr> \
CheckedNumeric<typename ArithmeticPromotion<PROMOTION, L, R>::type> \
operator OP(L lhs, const CheckedNumeric<R>& rhs) { \
return CheckedNumeric<L>(lhs) OP rhs; \
}
BASE_NUMERIC_ARITHMETIC_OPERATORS(Add, +, += )
BASE_NUMERIC_ARITHMETIC_OPERATORS(Sub, -, -= )
BASE_NUMERIC_ARITHMETIC_OPERATORS(Mul, *, *= )
BASE_NUMERIC_ARITHMETIC_OPERATORS(Div, /, /= )
BASE_NUMERIC_ARITHMETIC_OPERATORS(Mod, %, %= )
BASE_NUMERIC_ARITHMETIC_OPERATORS(Add, +, +=, MAX_EXPONENT_PROMOTION)
BASE_NUMERIC_ARITHMETIC_OPERATORS(Sub, -, -=, MAX_EXPONENT_PROMOTION)
BASE_NUMERIC_ARITHMETIC_OPERATORS(Mul, *, *=, MAX_EXPONENT_PROMOTION)
BASE_NUMERIC_ARITHMETIC_OPERATORS(Div, /, /=, MAX_EXPONENT_PROMOTION)
BASE_NUMERIC_ARITHMETIC_OPERATORS(Mod, %, %=, MAX_EXPONENT_PROMOTION)
BASE_NUMERIC_ARITHMETIC_OPERATORS(LeftShift, <<, <<=, LEFT_PROMOTION)
BASE_NUMERIC_ARITHMETIC_OPERATORS(RightShift, >>, >>=, LEFT_PROMOTION)
#undef BASE_NUMERIC_ARITHMETIC_OPERATORS

View File

@ -8,13 +8,13 @@
#include <stddef.h>
#include <stdint.h>
#include <climits>
#include <cmath>
#include <cstdlib>
#include <limits>
#include <type_traits>
#include "base/numerics/safe_conversions.h"
#include "base/template_util.h"
namespace base {
namespace internal {
@ -90,12 +90,12 @@ template <typename Integer>
struct PositionOfSignBit {
static const typename std::enable_if<std::numeric_limits<Integer>::is_integer,
size_t>::type value =
8 * sizeof(Integer) - 1;
CHAR_BIT * sizeof(Integer) - 1;
};
// This is used for UnsignedAbs, where we need to support floating-point
// template instantiations even though we don't actually support the operations.
// However, there is no corresponding implementation of e.g. CheckedUnsignedAbs,
// However, there is no corresponding implementation of e.g. SafeUnsignedAbs,
// so the float versions will not compile.
template <typename Numeric,
bool IsInteger = std::numeric_limits<Numeric>::is_integer,
@ -115,7 +115,7 @@ struct UnsignedOrFloatForSize<Numeric, false, true> {
// Helper templates for integer manipulations.
template <typename T>
bool HasSignBit(T x) {
constexpr bool HasSignBit(T x) {
// Cast to unsigned since right shift on signed is undefined.
return !!(static_cast<typename UnsignedIntegerForSize<T>::type>(x) >>
PositionOfSignBit<T>::value);
@ -123,58 +123,226 @@ bool HasSignBit(T x) {
// This wrapper undoes the standard integer promotions.
template <typename T>
T BinaryComplement(T x) {
return ~x;
constexpr T BinaryComplement(T x) {
return static_cast<T>(~x);
}
// Return if a numeric value is negative regardless of type.
template <typename T,
typename std::enable_if<std::is_arithmetic<T>::value &&
std::is_signed<T>::value>::type* = nullptr>
constexpr bool IsNegative(T x) {
return x < 0;
}
template <typename T,
typename std::enable_if<std::is_arithmetic<T>::value &&
!std::is_signed<T>::value>::type* = nullptr>
constexpr bool IsNegative(T x) {
return false;
}
enum ArithmeticPromotionCategory {
LEFT_PROMOTION, // Use the type of the left-hand argument.
RIGHT_PROMOTION, // Use the type of the right-hand argument.
MAX_EXPONENT_PROMOTION, // Use the type supporting the largest exponent.
BIG_ENOUGH_PROMOTION // Attempt to find a big enough type.
};
template <ArithmeticPromotionCategory Promotion,
typename Lhs,
typename Rhs = Lhs>
struct ArithmeticPromotion;
template <typename Lhs,
typename Rhs,
ArithmeticPromotionCategory Promotion =
(MaxExponent<Lhs>::value > MaxExponent<Rhs>::value)
? LEFT_PROMOTION
: RIGHT_PROMOTION>
struct MaxExponentPromotion;
template <typename Lhs, typename Rhs>
struct MaxExponentPromotion<Lhs, Rhs, LEFT_PROMOTION> {
using type = Lhs;
};
template <typename Lhs, typename Rhs>
struct MaxExponentPromotion<Lhs, Rhs, RIGHT_PROMOTION> {
using type = Rhs;
};
template <typename Lhs,
typename Rhs = Lhs,
bool is_intmax_type =
std::is_integral<
typename MaxExponentPromotion<Lhs, Rhs>::type>::value &&
sizeof(typename MaxExponentPromotion<Lhs, Rhs>::type) ==
sizeof(intmax_t),
bool is_max_exponent =
StaticDstRangeRelationToSrcRange<
typename MaxExponentPromotion<Lhs, Rhs>::type,
Lhs>::value ==
NUMERIC_RANGE_CONTAINED&& StaticDstRangeRelationToSrcRange<
typename MaxExponentPromotion<Lhs, Rhs>::type,
Rhs>::value == NUMERIC_RANGE_CONTAINED>
struct BigEnoughPromotion;
// The side with the max exponent is big enough.
template <typename Lhs, typename Rhs, bool is_intmax_type>
struct BigEnoughPromotion<Lhs, Rhs, is_intmax_type, true> {
using type = typename MaxExponentPromotion<Lhs, Rhs>::type;
static const bool is_contained = true;
};
// We can use a twice wider type to fit.
template <typename Lhs, typename Rhs>
struct BigEnoughPromotion<Lhs, Rhs, false, false> {
using type = typename IntegerForSizeAndSign<
sizeof(typename MaxExponentPromotion<Lhs, Rhs>::type) * 2,
std::is_signed<Lhs>::value || std::is_signed<Rhs>::value>::type;
static const bool is_contained = true;
};
// No type is large enough.
template <typename Lhs, typename Rhs>
struct BigEnoughPromotion<Lhs, Rhs, true, false> {
using type = typename MaxExponentPromotion<Lhs, Rhs>::type;
static const bool is_contained = false;
};
// These are the four supported promotion types.
// Use the type of the left-hand argument.
template <typename Lhs, typename Rhs>
struct ArithmeticPromotion<LEFT_PROMOTION, Lhs, Rhs> {
using type = Lhs;
static const bool is_contained = true;
};
// Use the type of the right-hand argument.
template <typename Lhs, typename Rhs>
struct ArithmeticPromotion<RIGHT_PROMOTION, Lhs, Rhs> {
using type = Rhs;
static const bool is_contained = true;
};
// Use the type supporting the largest exponent.
template <typename Lhs, typename Rhs>
struct ArithmeticPromotion<MAX_EXPONENT_PROMOTION, Lhs, Rhs> {
using type = typename MaxExponentPromotion<Lhs, Rhs>::type;
static const bool is_contained = true;
};
// Attempt to find a big enough type.
template <typename Lhs, typename Rhs>
struct ArithmeticPromotion<BIG_ENOUGH_PROMOTION, Lhs, Rhs> {
using type = typename BigEnoughPromotion<Lhs, Rhs>::type;
static const bool is_contained = BigEnoughPromotion<Lhs, Rhs>::is_contained;
};
// We can statically check if operations on the provided types can wrap, so we
// can skip the checked operations if they're not needed. So, for an integer we
// care if the destination type preserves the sign and is twice the width of
// the source.
template <typename T, typename Lhs, typename Rhs>
struct IsIntegerArithmeticSafe {
static const bool value = !std::numeric_limits<T>::is_iec559 &&
StaticDstRangeRelationToSrcRange<T, Lhs>::value ==
NUMERIC_RANGE_CONTAINED &&
sizeof(T) >= (2 * sizeof(Lhs)) &&
StaticDstRangeRelationToSrcRange<T, Rhs>::value !=
NUMERIC_RANGE_CONTAINED &&
sizeof(T) >= (2 * sizeof(Rhs));
};
// Here are the actual portable checked integer math implementations.
// TODO(jschuh): Break this code out from the enable_if pattern and find a clean
// way to coalesce things into the CheckedNumericState specializations below.
template <typename T>
typename std::enable_if<std::numeric_limits<T>::is_integer, T>::type
CheckedAdd(T x, T y, RangeConstraint* validity) {
typename std::enable_if<std::numeric_limits<T>::is_integer, bool>::type
CheckedAddImpl(T x, T y, T* result) {
// Since the value of x+y is undefined if we have a signed type, we compute
// it using the unsigned type of the same size.
typedef typename UnsignedIntegerForSize<T>::type UnsignedDst;
UnsignedDst ux = static_cast<UnsignedDst>(x);
UnsignedDst uy = static_cast<UnsignedDst>(y);
UnsignedDst uresult = ux + uy;
UnsignedDst uresult = static_cast<UnsignedDst>(ux + uy);
*result = static_cast<T>(uresult);
// Addition is valid if the sign of (x + y) is equal to either that of x or
// that of y.
if (std::numeric_limits<T>::is_signed) {
if (HasSignBit(BinaryComplement((uresult ^ ux) & (uresult ^ uy))))
*validity = RANGE_VALID;
else // Direction of wrap is inverse of result sign.
*validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW;
return (std::numeric_limits<T>::is_signed)
? HasSignBit(BinaryComplement(
static_cast<UnsignedDst>((uresult ^ ux) & (uresult ^ uy))))
: (BinaryComplement(x) >=
y); // Unsigned is either valid or underflow.
}
} else { // Unsigned is either valid or overflow.
*validity = BinaryComplement(x) >= y ? RANGE_VALID : RANGE_OVERFLOW;
template <typename T, typename U, typename V>
typename std::enable_if<std::numeric_limits<T>::is_integer &&
std::numeric_limits<U>::is_integer &&
std::numeric_limits<V>::is_integer,
bool>::type
CheckedAdd(T x, U y, V* result) {
using Promotion =
typename ArithmeticPromotion<BIG_ENOUGH_PROMOTION, T, U>::type;
Promotion presult;
// Fail if either operand is out of range for the promoted type.
// TODO(jschuh): This could be made to work for a broader range of values.
bool is_valid = IsValueInRangeForNumericType<Promotion>(x) &&
IsValueInRangeForNumericType<Promotion>(y);
if (IsIntegerArithmeticSafe<Promotion, U, V>::value) {
presult = static_cast<Promotion>(x) + static_cast<Promotion>(y);
} else {
is_valid &= CheckedAddImpl(static_cast<Promotion>(x),
static_cast<Promotion>(y), &presult);
}
return static_cast<T>(uresult);
*result = static_cast<V>(presult);
return is_valid && IsValueInRangeForNumericType<V>(presult);
}
template <typename T>
typename std::enable_if<std::numeric_limits<T>::is_integer, T>::type
CheckedSub(T x, T y, RangeConstraint* validity) {
typename std::enable_if<std::numeric_limits<T>::is_integer, bool>::type
CheckedSubImpl(T x, T y, T* result) {
// Since the value of x+y is undefined if we have a signed type, we compute
// it using the unsigned type of the same size.
typedef typename UnsignedIntegerForSize<T>::type UnsignedDst;
UnsignedDst ux = static_cast<UnsignedDst>(x);
UnsignedDst uy = static_cast<UnsignedDst>(y);
UnsignedDst uresult = ux - uy;
UnsignedDst uresult = static_cast<UnsignedDst>(ux - uy);
*result = static_cast<T>(uresult);
// Subtraction is valid if either x and y have same sign, or (x-y) and x have
// the same sign.
if (std::numeric_limits<T>::is_signed) {
if (HasSignBit(BinaryComplement((uresult ^ ux) & (ux ^ uy))))
*validity = RANGE_VALID;
else // Direction of wrap is inverse of result sign.
*validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW;
return (std::numeric_limits<T>::is_signed)
? HasSignBit(BinaryComplement(
static_cast<UnsignedDst>((uresult ^ ux) & (ux ^ uy))))
: (x >= y);
}
} else { // Unsigned is either valid or underflow.
*validity = x >= y ? RANGE_VALID : RANGE_UNDERFLOW;
template <typename T, typename U, typename V>
typename std::enable_if<std::numeric_limits<T>::is_integer &&
std::numeric_limits<U>::is_integer &&
std::numeric_limits<V>::is_integer,
bool>::type
CheckedSub(T x, U y, V* result) {
using Promotion =
typename ArithmeticPromotion<BIG_ENOUGH_PROMOTION, T, U>::type;
Promotion presult;
// Fail if either operand is out of range for the promoted type.
// TODO(jschuh): This could be made to work for a broader range of values.
bool is_valid = IsValueInRangeForNumericType<Promotion>(x) &&
IsValueInRangeForNumericType<Promotion>(y);
if (IsIntegerArithmeticSafe<Promotion, U, V>::value) {
presult = static_cast<Promotion>(x) - static_cast<Promotion>(y);
} else {
is_valid &= CheckedSubImpl(static_cast<Promotion>(x),
static_cast<Promotion>(y), &presult);
}
return static_cast<T>(uresult);
*result = static_cast<V>(presult);
return is_valid && IsValueInRangeForNumericType<V>(presult);
}
// Integer multiplication is a bit complicated. In the fast case we just
@ -184,139 +352,243 @@ CheckedSub(T x, T y, RangeConstraint* validity) {
template <typename T>
typename std::enable_if<std::numeric_limits<T>::is_integer &&
sizeof(T) * 2 <= sizeof(uintmax_t),
T>::type
CheckedMul(T x, T y, RangeConstraint* validity) {
bool>::type
CheckedMulImpl(T x, T y, T* result) {
typedef typename TwiceWiderInteger<T>::type IntermediateType;
IntermediateType tmp =
static_cast<IntermediateType>(x) * static_cast<IntermediateType>(y);
*validity = DstRangeRelationToSrcRange<T>(tmp);
return static_cast<T>(tmp);
*result = static_cast<T>(tmp);
return DstRangeRelationToSrcRange<T>(tmp) == RANGE_VALID;
}
template <typename T>
typename std::enable_if<std::numeric_limits<T>::is_integer &&
std::numeric_limits<T>::is_signed &&
(sizeof(T) * 2 > sizeof(uintmax_t)),
T>::type
CheckedMul(T x, T y, RangeConstraint* validity) {
// If either side is zero then the result will be zero.
if (!x || !y) {
return RANGE_VALID;
} else if (x > 0) {
if (y > 0)
*validity =
x <= std::numeric_limits<T>::max() / y ? RANGE_VALID : RANGE_OVERFLOW;
else
*validity = y >= std::numeric_limits<T>::min() / x ? RANGE_VALID
: RANGE_UNDERFLOW;
} else {
if (y > 0)
*validity = x >= std::numeric_limits<T>::min() / y ? RANGE_VALID
: RANGE_UNDERFLOW;
else
*validity =
y >= std::numeric_limits<T>::max() / x ? RANGE_VALID : RANGE_OVERFLOW;
bool>::type
CheckedMulImpl(T x, T y, T* result) {
if (x && y) {
if (x > 0) {
if (y > 0) {
if (x > std::numeric_limits<T>::max() / y)
return false;
} else {
if (y < std::numeric_limits<T>::min() / x)
return false;
}
} else {
if (y > 0) {
if (x < std::numeric_limits<T>::min() / y)
return false;
} else {
if (y < std::numeric_limits<T>::max() / x)
return false;
}
}
}
return x * y;
*result = x * y;
return true;
}
template <typename T>
typename std::enable_if<std::numeric_limits<T>::is_integer &&
!std::numeric_limits<T>::is_signed &&
(sizeof(T) * 2 > sizeof(uintmax_t)),
T>::type
CheckedMul(T x, T y, RangeConstraint* validity) {
*validity = (y == 0 || x <= std::numeric_limits<T>::max() / y)
? RANGE_VALID
: RANGE_OVERFLOW;
return x * y;
bool>::type
CheckedMulImpl(T x, T y, T* result) {
*result = x * y;
return (y == 0 || x <= std::numeric_limits<T>::max() / y);
}
// Division just requires a check for an invalid negation on signed min/-1.
template <typename T>
T CheckedDiv(T x,
T y,
RangeConstraint* validity,
typename std::enable_if<std::numeric_limits<T>::is_integer,
int>::type = 0) {
if (std::numeric_limits<T>::is_signed && x == std::numeric_limits<T>::min() &&
y == static_cast<T>(-1)) {
*validity = RANGE_OVERFLOW;
return std::numeric_limits<T>::min();
template <typename T, typename U, typename V>
typename std::enable_if<std::numeric_limits<T>::is_integer &&
std::numeric_limits<U>::is_integer &&
std::numeric_limits<V>::is_integer,
bool>::type
CheckedMul(T x, U y, V* result) {
using Promotion =
typename ArithmeticPromotion<BIG_ENOUGH_PROMOTION, T, U>::type;
Promotion presult;
// Fail if either operand is out of range for the promoted type.
// TODO(jschuh): This could be made to work for a broader range of values.
bool is_valid = IsValueInRangeForNumericType<Promotion>(x) &&
IsValueInRangeForNumericType<Promotion>(y);
if (IsIntegerArithmeticSafe<Promotion, U, V>::value) {
presult = static_cast<Promotion>(x) * static_cast<Promotion>(y);
} else {
is_valid &= CheckedMulImpl(static_cast<Promotion>(x),
static_cast<Promotion>(y), &presult);
}
*result = static_cast<V>(presult);
return is_valid && IsValueInRangeForNumericType<V>(presult);
}
*validity = RANGE_VALID;
return x / y;
// Division just requires a check for a zero denominator or an invalid negation
// on signed min/-1.
template <typename T>
typename std::enable_if<std::numeric_limits<T>::is_integer, bool>::type
CheckedDivImpl(T x, T y, T* result) {
if (y && (!std::numeric_limits<T>::is_signed ||
x != std::numeric_limits<T>::min() || y != static_cast<T>(-1))) {
*result = x / y;
return true;
}
return false;
}
template <typename T, typename U, typename V>
typename std::enable_if<std::numeric_limits<T>::is_integer &&
std::numeric_limits<U>::is_integer &&
std::numeric_limits<V>::is_integer,
bool>::type
CheckedDiv(T x, U y, V* result) {
using Promotion =
typename ArithmeticPromotion<BIG_ENOUGH_PROMOTION, T, U>::type;
Promotion presult;
// Fail if either operand is out of range for the promoted type.
// TODO(jschuh): This could be made to work for a broader range of values.
bool is_valid = IsValueInRangeForNumericType<Promotion>(x) &&
IsValueInRangeForNumericType<Promotion>(y);
is_valid &= CheckedDivImpl(static_cast<Promotion>(x),
static_cast<Promotion>(y), &presult);
*result = static_cast<V>(presult);
return is_valid && IsValueInRangeForNumericType<V>(presult);
}
template <typename T>
typename std::enable_if<std::numeric_limits<T>::is_integer &&
std::numeric_limits<T>::is_signed,
T>::type
CheckedMod(T x, T y, RangeConstraint* validity) {
*validity = y > 0 ? RANGE_VALID : RANGE_INVALID;
return x % y;
bool>::type
CheckedModImpl(T x, T y, T* result) {
if (y > 0) {
*result = static_cast<T>(x % y);
return true;
}
return false;
}
template <typename T>
typename std::enable_if<std::numeric_limits<T>::is_integer &&
!std::numeric_limits<T>::is_signed,
T>::type
CheckedMod(T x, T y, RangeConstraint* validity) {
*validity = RANGE_VALID;
return x % y;
bool>::type
CheckedModImpl(T x, T y, T* result) {
if (y != 0) {
*result = static_cast<T>(x % y);
return true;
}
return false;
}
template <typename T, typename U, typename V>
typename std::enable_if<std::numeric_limits<T>::is_integer &&
std::numeric_limits<U>::is_integer &&
std::numeric_limits<V>::is_integer,
bool>::type
CheckedMod(T x, U y, V* result) {
using Promotion =
typename ArithmeticPromotion<BIG_ENOUGH_PROMOTION, T, U>::type;
Promotion presult;
bool is_valid = CheckedModImpl(static_cast<Promotion>(x),
static_cast<Promotion>(y), &presult);
*result = static_cast<V>(presult);
return is_valid && IsValueInRangeForNumericType<V>(presult);
}
// Left shift. Shifts less than 0 or greater than or equal to the number
// of bits in the promoted type are undefined. Shifts of negative values
// are undefined. Otherwise it is defined when the result fits.
template <typename T, typename U, typename V>
typename std::enable_if<std::numeric_limits<T>::is_integer &&
std::numeric_limits<U>::is_integer &&
std::numeric_limits<V>::is_integer,
bool>::type
CheckedLeftShift(T x, U shift, V* result) {
using ShiftType = typename UnsignedIntegerForSize<T>::type;
static const ShiftType kBitWidth = CHAR_BIT * sizeof(T);
const ShiftType real_shift = static_cast<ShiftType>(shift);
// Signed shift is not legal on negative values.
if (!IsNegative(x) && real_shift < kBitWidth) {
// Just use a multiplication because it's easy.
// TODO(jschuh): This could probably be made more efficient.
if (!std::is_signed<T>::value || real_shift != kBitWidth - 1)
return CheckedMul(x, static_cast<T>(1) << shift, result);
return !x; // Special case zero for a full width signed shift.
}
return false;
}
// Right shift. Shifts less than 0 or greater than or equal to the number
// of bits in the promoted type are undefined. Otherwise, it is always defined,
// but a right shift of a negative value is implementation-dependent.
template <typename T, typename U, typename V>
typename std::enable_if<std::numeric_limits<T>::is_integer &&
std::numeric_limits<U>::is_integer &&
std::numeric_limits<V>::is_integer,
bool>::type
CheckedRightShift(T x, U shift, V* result) {
// Use the type conversion push negative values out of range.
using ShiftType = typename UnsignedIntegerForSize<T>::type;
if (static_cast<ShiftType>(shift) < (CHAR_BIT * sizeof(T))) {
T tmp = x >> shift;
*result = static_cast<V>(tmp);
return IsValueInRangeForNumericType<unsigned>(tmp);
}
return false;
}
template <typename T>
typename std::enable_if<std::numeric_limits<T>::is_integer &&
std::numeric_limits<T>::is_signed,
T>::type
CheckedNeg(T value, RangeConstraint* validity) {
*validity =
value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW;
bool>::type
CheckedNeg(T value, T* result) {
// The negation of signed min is min, so catch that one.
return -value;
if (value != std::numeric_limits<T>::min()) {
*result = static_cast<T>(-value);
return true;
}
return false;
}
template <typename T>
typename std::enable_if<std::numeric_limits<T>::is_integer &&
!std::numeric_limits<T>::is_signed,
T>::type
CheckedNeg(T value, RangeConstraint* validity) {
// The only legal unsigned negation is zero.
*validity = value ? RANGE_UNDERFLOW : RANGE_VALID;
return static_cast<T>(
-static_cast<typename SignedIntegerForSize<T>::type>(value));
bool>::type
CheckedNeg(T value, T* result) {
if (!value) { // The only legal unsigned negation is zero.
*result = static_cast<T>(0);
return true;
}
return false;
}
template <typename T>
typename std::enable_if<std::numeric_limits<T>::is_integer &&
std::numeric_limits<T>::is_signed,
T>::type
CheckedAbs(T value, RangeConstraint* validity) {
*validity =
value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW;
return static_cast<T>(std::abs(value));
bool>::type
CheckedAbs(T value, T* result) {
if (value != std::numeric_limits<T>::min()) {
*result = std::abs(value);
return true;
}
return false;
}
template <typename T>
typename std::enable_if<std::numeric_limits<T>::is_integer &&
!std::numeric_limits<T>::is_signed,
T>::type
CheckedAbs(T value, RangeConstraint* validity) {
bool>::type
CheckedAbs(T value, T* result) {
// T is unsigned, so |value| must already be positive.
*validity = RANGE_VALID;
return value;
*result = value;
return true;
}
template <typename T>
typename std::enable_if<std::numeric_limits<T>::is_integer &&
std::numeric_limits<T>::is_signed,
typename UnsignedIntegerForSize<T>::type>::type
CheckedUnsignedAbs(T value) {
SafeUnsignedAbs(T value) {
typedef typename UnsignedIntegerForSize<T>::type UnsignedT;
return value == std::numeric_limits<T>::min()
? static_cast<UnsignedT>(std::numeric_limits<T>::max()) + 1
@ -327,19 +599,36 @@ template <typename T>
typename std::enable_if<std::numeric_limits<T>::is_integer &&
!std::numeric_limits<T>::is_signed,
T>::type
CheckedUnsignedAbs(T value) {
SafeUnsignedAbs(T value) {
// T is unsigned, so |value| must already be positive.
return value;
return static_cast<T>(value);
}
// These are the floating point stubs that the compiler needs to see. Only the
// negation operation is ever called.
#define BASE_FLOAT_ARITHMETIC_STUBS(NAME) \
template <typename T> \
typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type \
Checked##NAME(T, T, RangeConstraint*) { \
NOTREACHED(); \
return 0; \
template <typename T>
typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedNeg(
T value,
bool*) {
NOTREACHED();
return static_cast<T>(-value);
}
template <typename T>
typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedAbs(
T value,
bool*) {
NOTREACHED();
return static_cast<T>(std::abs(value));
}
// These are the floating point stubs that the compiler needs to see.
#define BASE_FLOAT_ARITHMETIC_STUBS(NAME) \
template <typename T, typename U, typename V> \
typename std::enable_if<std::numeric_limits<T>::is_iec559 || \
std::numeric_limits<U>::is_iec559 || \
std::numeric_limits<V>::is_iec559, \
bool>::type Checked##NAME(T, U, V*) { \
NOTREACHED(); \
return static_cast<T>(false); \
}
BASE_FLOAT_ARITHMETIC_STUBS(Add)
@ -351,17 +640,17 @@ BASE_FLOAT_ARITHMETIC_STUBS(Mod)
#undef BASE_FLOAT_ARITHMETIC_STUBS
template <typename T>
typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedNeg(
T value,
RangeConstraint*) {
return -value;
typename std::enable_if<std::numeric_limits<T>::is_iec559, bool>::type
CheckedNeg(T value, T* result) {
*result = static_cast<T>(-value);
return true;
}
template <typename T>
typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedAbs(
T value,
RangeConstraint*) {
return std::abs(value);
typename std::enable_if<std::numeric_limits<T>::is_iec559, bool>::type
CheckedAbs(T value, T* result) {
*result = static_cast<T>(std::abs(value));
return true;
}
// Floats carry around their validity state with them, but integers do not. So,
@ -391,19 +680,19 @@ template <typename T>
class CheckedNumericState<T, NUMERIC_INTEGER> {
private:
T value_;
RangeConstraint validity_;
bool is_valid_;
public:
template <typename Src, NumericRepresentation type>
friend class CheckedNumericState;
CheckedNumericState() : value_(0), validity_(RANGE_VALID) {}
CheckedNumericState() : value_(0), is_valid_(true) {}
template <typename Src>
CheckedNumericState(Src value, RangeConstraint validity)
CheckedNumericState(Src value, bool is_valid)
: value_(static_cast<T>(value)),
validity_(GetRangeConstraint(validity |
DstRangeRelationToSrcRange<T>(value))) {
is_valid_(is_valid &&
(DstRangeRelationToSrcRange<T>(value) == RANGE_VALID)) {
static_assert(std::numeric_limits<Src>::is_specialized,
"Argument must be numeric.");
}
@ -411,9 +700,7 @@ class CheckedNumericState<T, NUMERIC_INTEGER> {
// Copy constructor.
template <typename Src>
CheckedNumericState(const CheckedNumericState<Src>& rhs)
: value_(static_cast<T>(rhs.value())),
validity_(GetRangeConstraint(
rhs.validity() | DstRangeRelationToSrcRange<T>(rhs.value()))) {}
: value_(static_cast<T>(rhs.value())), is_valid_(rhs.IsValid()) {}
template <typename Src>
explicit CheckedNumericState(
@ -421,9 +708,9 @@ class CheckedNumericState<T, NUMERIC_INTEGER> {
typename std::enable_if<std::numeric_limits<Src>::is_specialized,
int>::type = 0)
: value_(static_cast<T>(value)),
validity_(DstRangeRelationToSrcRange<T>(value)) {}
is_valid_(DstRangeRelationToSrcRange<T>(value) == RANGE_VALID) {}
RangeConstraint validity() const { return validity_; }
bool is_valid() const { return is_valid_; }
T value() const { return value_; }
};
@ -442,29 +729,12 @@ class CheckedNumericState<T, NUMERIC_FLOATING> {
template <typename Src>
CheckedNumericState(
Src value,
RangeConstraint validity,
bool is_valid,
typename std::enable_if<std::numeric_limits<Src>::is_integer, int>::type =
0) {
switch (DstRangeRelationToSrcRange<T>(value)) {
case RANGE_VALID:
value_ = static_cast<T>(value);
break;
case RANGE_UNDERFLOW:
value_ = -std::numeric_limits<T>::infinity();
break;
case RANGE_OVERFLOW:
value_ = std::numeric_limits<T>::infinity();
break;
case RANGE_INVALID:
value_ = std::numeric_limits<T>::quiet_NaN();
break;
default:
NOTREACHED();
}
value_ = (is_valid && (DstRangeRelationToSrcRange<T>(value) == RANGE_VALID))
? static_cast<T>(value)
: std::numeric_limits<T>::quiet_NaN();
}
template <typename Src>
@ -479,66 +749,10 @@ class CheckedNumericState<T, NUMERIC_FLOATING> {
CheckedNumericState(const CheckedNumericState<Src>& rhs)
: value_(static_cast<T>(rhs.value())) {}
RangeConstraint validity() const {
return GetRangeConstraint(value_ <= std::numeric_limits<T>::max(),
value_ >= -std::numeric_limits<T>::max());
}
bool is_valid() const { return std::isfinite(value_); }
T value() const { return value_; }
};
// For integers less than 128-bit and floats 32-bit or larger, we can distil
// C/C++ arithmetic promotions down to two simple rules:
// 1. The type with the larger maximum exponent always takes precedence.
// 2. The resulting type must be promoted to at least an int.
// The following template specializations implement that promotion logic.
enum ArithmeticPromotionCategory {
LEFT_PROMOTION,
RIGHT_PROMOTION,
DEFAULT_PROMOTION
};
template <typename Lhs,
typename Rhs = Lhs,
ArithmeticPromotionCategory Promotion =
(MaxExponent<Lhs>::value > MaxExponent<Rhs>::value)
? (MaxExponent<Lhs>::value > MaxExponent<int>::value
? LEFT_PROMOTION
: DEFAULT_PROMOTION)
: (MaxExponent<Rhs>::value > MaxExponent<int>::value
? RIGHT_PROMOTION
: DEFAULT_PROMOTION) >
struct ArithmeticPromotion;
template <typename Lhs, typename Rhs>
struct ArithmeticPromotion<Lhs, Rhs, LEFT_PROMOTION> {
typedef Lhs type;
};
template <typename Lhs, typename Rhs>
struct ArithmeticPromotion<Lhs, Rhs, RIGHT_PROMOTION> {
typedef Rhs type;
};
template <typename Lhs, typename Rhs>
struct ArithmeticPromotion<Lhs, Rhs, DEFAULT_PROMOTION> {
typedef int type;
};
// We can statically check if operations on the provided types can wrap, so we
// can skip the checked operations if they're not needed. So, for an integer we
// care if the destination type preserves the sign and is twice the width of
// the source.
template <typename T, typename Lhs, typename Rhs>
struct IsIntegerArithmeticSafe {
static const bool value = !std::numeric_limits<T>::is_iec559 &&
StaticDstRangeRelationToSrcRange<T, Lhs>::value ==
NUMERIC_RANGE_CONTAINED &&
sizeof(T) >= (2 * sizeof(Lhs)) &&
StaticDstRangeRelationToSrcRange<T, Rhs>::value !=
NUMERIC_RANGE_CONTAINED &&
sizeof(T) >= (2 * sizeof(Rhs));
};
} // namespace internal
} // namespace base

View File

@ -0,0 +1,146 @@
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This file contains routines to kill processes and get the exit code and
// termination status.
#ifndef BASE_PROCESS_KILL_H_
#define BASE_PROCESS_KILL_H_
#include "base/files/file_path.h"
#include "base/process/process.h"
#include "base/process/process_handle.h"
#include "base/time/time.h"
#include "build/build_config.h"
namespace base {
class ProcessFilter;
#if defined(OS_WIN)
namespace win {
// See definition in sandbox/win/src/sandbox_types.h
const DWORD kSandboxFatalMemoryExceeded = 7012;
} // namespace win
#endif // OS_WIN
// Return status values from GetTerminationStatus. Don't use these as
// exit code arguments to KillProcess*(), use platform/application
// specific values instead.
enum TerminationStatus {
TERMINATION_STATUS_NORMAL_TERMINATION, // zero exit status
TERMINATION_STATUS_ABNORMAL_TERMINATION, // non-zero exit status
TERMINATION_STATUS_PROCESS_WAS_KILLED, // e.g. SIGKILL or task manager kill
TERMINATION_STATUS_PROCESS_CRASHED, // e.g. Segmentation fault
TERMINATION_STATUS_STILL_RUNNING, // child hasn't exited yet
#if defined(OS_CHROMEOS)
// Used for the case when oom-killer kills a process on ChromeOS.
TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM,
#endif
#if defined(OS_ANDROID)
// On Android processes are spawned from the system Zygote and we do not get
// the termination status. We can't know if the termination was a crash or an
// oom kill for sure, but we can use status of the strong process bindings as
// a hint.
TERMINATION_STATUS_OOM_PROTECTED, // child was protected from oom kill
#endif
TERMINATION_STATUS_LAUNCH_FAILED, // child process never launched
TERMINATION_STATUS_OOM, // Process died due to oom
TERMINATION_STATUS_MAX_ENUM
};
// Attempts to kill all the processes on the current machine that were launched
// from the given executable name, ending them with the given exit code. If
// filter is non-null, then only processes selected by the filter are killed.
// Returns true if all processes were able to be killed off, false if at least
// one couldn't be killed.
BASE_EXPORT bool KillProcesses(const FilePath::StringType& executable_name,
int exit_code,
const ProcessFilter* filter);
#if defined(OS_POSIX)
// Attempts to kill the process group identified by |process_group_id|. Returns
// true on success.
BASE_EXPORT bool KillProcessGroup(ProcessHandle process_group_id);
#endif // defined(OS_POSIX)
// Get the termination status of the process by interpreting the
// circumstances of the child process' death. |exit_code| is set to
// the status returned by waitpid() on POSIX, and from
// GetExitCodeProcess() on Windows. |exit_code| may be NULL if the
// caller is not interested in it. Note that on Linux, this function
// will only return a useful result the first time it is called after
// the child exits (because it will reap the child and the information
// will no longer be available).
BASE_EXPORT TerminationStatus GetTerminationStatus(ProcessHandle handle,
int* exit_code);
#if defined(OS_POSIX)
// Send a kill signal to the process and then wait for the process to exit
// and get the termination status.
//
// This is used in situations where it is believed that the process is dead
// or dying (because communication with the child process has been cut).
// In order to avoid erroneously returning that the process is still running
// because the kernel is still cleaning it up, this will wait for the process
// to terminate. In order to avoid the risk of hanging while waiting for the
// process to terminate, send a SIGKILL to the process before waiting for the
// termination status.
//
// Note that it is not an option to call WaitForExitCode and then
// GetTerminationStatus as the child will be reaped when WaitForExitCode
// returns, and this information will be lost.
//
BASE_EXPORT TerminationStatus GetKnownDeadTerminationStatus(
ProcessHandle handle, int* exit_code);
#endif // defined(OS_POSIX)
// Wait for all the processes based on the named executable to exit. If filter
// is non-null, then only processes selected by the filter are waited on.
// Returns after all processes have exited or wait_milliseconds have expired.
// Returns true if all the processes exited, false otherwise.
BASE_EXPORT bool WaitForProcessesToExit(
const FilePath::StringType& executable_name,
base::TimeDelta wait,
const ProcessFilter* filter);
// Waits a certain amount of time (can be 0) for all the processes with a given
// executable name to exit, then kills off any of them that are still around.
// If filter is non-null, then only processes selected by the filter are waited
// on. Killed processes are ended with the given exit code. Returns false if
// any processes needed to be killed, true if they all exited cleanly within
// the wait_milliseconds delay.
BASE_EXPORT bool CleanupProcesses(const FilePath::StringType& executable_name,
base::TimeDelta wait,
int exit_code,
const ProcessFilter* filter);
// This method ensures that the specified process eventually terminates, and
// then it closes the given process handle.
//
// It assumes that the process has already been signalled to exit, and it
// begins by waiting a small amount of time for it to exit. If the process
// does not appear to have exited, then this function starts to become
// aggressive about ensuring that the process terminates.
//
// On Linux this method does not block the calling thread.
// On OS X this method may block for up to 2 seconds.
//
// NOTE: The process must have been opened with the PROCESS_TERMINATE and
// SYNCHRONIZE permissions.
//
BASE_EXPORT void EnsureProcessTerminated(Process process);
#if defined(OS_POSIX) && !defined(OS_MACOSX)
// The nicer version of EnsureProcessTerminated() that is patient and will
// wait for |pid| to finish and then reap it.
BASE_EXPORT void EnsureProcessGetsReaped(ProcessId pid);
#endif
} // namespace base
#endif // BASE_PROCESS_KILL_H_

View File

@ -0,0 +1,319 @@
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// This file contains functions for launching subprocesses.
#ifndef BASE_PROCESS_LAUNCH_H_
#define BASE_PROCESS_LAUNCH_H_
#include <stddef.h>
#include <string>
#include <utility>
#include <vector>
#include "base/base_export.h"
#include "base/environment.h"
#include "base/macros.h"
#include "base/process/process.h"
#include "base/process/process_handle.h"
#include "base/strings/string_piece.h"
#include "build/build_config.h"
#if defined(OS_POSIX)
#include "base/posix/file_descriptor_shuffle.h"
#elif defined(OS_WIN)
#include <windows.h>
#endif
namespace base {
class CommandLine;
#if defined(OS_WIN)
typedef std::vector<HANDLE> HandlesToInheritVector;
#endif
// TODO(viettrungluu): Only define this on POSIX?
typedef std::vector<std::pair<int, int> > FileHandleMappingVector;
// Options for launching a subprocess that are passed to LaunchProcess().
// The default constructor constructs the object with default options.
struct BASE_EXPORT LaunchOptions {
#if defined(OS_POSIX)
// Delegate to be run in between fork and exec in the subprocess (see
// pre_exec_delegate below)
class BASE_EXPORT PreExecDelegate {
public:
PreExecDelegate() {}
virtual ~PreExecDelegate() {}
// Since this is to be run between fork and exec, and fork may have happened
// while multiple threads were running, this function needs to be async
// safe.
virtual void RunAsyncSafe() = 0;
private:
DISALLOW_COPY_AND_ASSIGN(PreExecDelegate);
};
#endif // defined(OS_POSIX)
LaunchOptions();
LaunchOptions(const LaunchOptions&);
~LaunchOptions();
// If true, wait for the process to complete.
bool wait = false;
// If not empty, change to this directory before executing the new process.
base::FilePath current_directory;
#if defined(OS_WIN)
bool start_hidden = false;
// If non-null, inherit exactly the list of handles in this vector (these
// handles must be inheritable).
HandlesToInheritVector* handles_to_inherit = nullptr;
// If true, the new process inherits handles from the parent. In production
// code this flag should be used only when running short-lived, trusted
// binaries, because open handles from other libraries and subsystems will
// leak to the child process, causing errors such as open socket hangs.
// Note: If |handles_to_inherit| is non-null, this flag is ignored and only
// those handles will be inherited.
bool inherit_handles = false;
// If non-null, runs as if the user represented by the token had launched it.
// Whether the application is visible on the interactive desktop depends on
// the token belonging to an interactive logon session.
//
// To avoid hard to diagnose problems, when specified this loads the
// environment variables associated with the user and if this operation fails
// the entire call fails as well.
UserTokenHandle as_user = nullptr;
// If true, use an empty string for the desktop name.
bool empty_desktop_name = false;
// If non-null, launches the application in that job object. The process will
// be terminated immediately and LaunchProcess() will fail if assignment to
// the job object fails.
HANDLE job_handle = nullptr;
// Handles for the redirection of stdin, stdout and stderr. The handles must
// be inheritable. Caller should either set all three of them or none (i.e.
// there is no way to redirect stderr without redirecting stdin). The
// |inherit_handles| flag must be set to true when redirecting stdio stream.
HANDLE stdin_handle = nullptr;
HANDLE stdout_handle = nullptr;
HANDLE stderr_handle = nullptr;
// If set to true, ensures that the child process is launched with the
// CREATE_BREAKAWAY_FROM_JOB flag which allows it to breakout of the parent
// job if any.
bool force_breakaway_from_job_ = false;
#else // !defined(OS_WIN)
// Set/unset environment variables. These are applied on top of the parent
// process environment. Empty (the default) means to inherit the same
// environment. See AlterEnvironment().
EnvironmentMap environ;
// Clear the environment for the new process before processing changes from
// |environ|.
bool clear_environ = false;
// If non-null, remap file descriptors according to the mapping of
// src fd->dest fd to propagate FDs into the child process.
// This pointer is owned by the caller and must live through the
// call to LaunchProcess().
const FileHandleMappingVector* fds_to_remap = nullptr;
// Each element is an RLIMIT_* constant that should be raised to its
// rlim_max. This pointer is owned by the caller and must live through
// the call to LaunchProcess().
const std::vector<int>* maximize_rlimits = nullptr;
// If true, start the process in a new process group, instead of
// inheriting the parent's process group. The pgid of the child process
// will be the same as its pid.
bool new_process_group = false;
#if defined(OS_LINUX)
// If non-zero, start the process using clone(), using flags as provided.
// Unlike in clone, clone_flags may not contain a custom termination signal
// that is sent to the parent when the child dies. The termination signal will
// always be set to SIGCHLD.
int clone_flags = 0;
// By default, child processes will have the PR_SET_NO_NEW_PRIVS bit set. If
// true, then this bit will not be set in the new child process.
bool allow_new_privs = false;
// Sets parent process death signal to SIGKILL.
bool kill_on_parent_death = false;
#endif // defined(OS_LINUX)
#if defined(OS_POSIX)
// If not empty, launch the specified executable instead of
// cmdline.GetProgram(). This is useful when it is necessary to pass a custom
// argv[0].
base::FilePath real_path;
// If non-null, a delegate to be run immediately prior to executing the new
// program in the child process.
//
// WARNING: If LaunchProcess is called in the presence of multiple threads,
// code running in this delegate essentially needs to be async-signal safe
// (see man 7 signal for a list of allowed functions).
PreExecDelegate* pre_exec_delegate = nullptr;
#endif // defined(OS_POSIX)
#if defined(OS_CHROMEOS)
// If non-negative, the specified file descriptor will be set as the launched
// process' controlling terminal.
int ctrl_terminal_fd = -1;
#endif // defined(OS_CHROMEOS)
#endif // !defined(OS_WIN)
};
// Launch a process via the command line |cmdline|.
// See the documentation of LaunchOptions for details on |options|.
//
// Returns a valid Process upon success.
//
// Unix-specific notes:
// - All file descriptors open in the parent process will be closed in the
// child process except for any preserved by options::fds_to_remap, and
// stdin, stdout, and stderr. If not remapped by options::fds_to_remap,
// stdin is reopened as /dev/null, and the child is allowed to inherit its
// parent's stdout and stderr.
// - If the first argument on the command line does not contain a slash,
// PATH will be searched. (See man execvp.)
BASE_EXPORT Process LaunchProcess(const CommandLine& cmdline,
const LaunchOptions& options);
#if defined(OS_WIN)
// Windows-specific LaunchProcess that takes the command line as a
// string. Useful for situations where you need to control the
// command line arguments directly, but prefer the CommandLine version
// if launching Chrome itself.
//
// 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\"
BASE_EXPORT Process LaunchProcess(const string16& cmdline,
const LaunchOptions& options);
// Launches a process with elevated privileges. This does not behave exactly
// like LaunchProcess as it uses ShellExecuteEx instead of CreateProcess to
// create the process. This means the process will have elevated privileges
// and thus some common operations like OpenProcess will fail. Currently the
// only supported LaunchOptions are |start_hidden| and |wait|.
BASE_EXPORT Process LaunchElevatedProcess(const CommandLine& cmdline,
const LaunchOptions& options);
#elif defined(OS_POSIX)
// A POSIX-specific version of LaunchProcess that takes an argv array
// instead of a CommandLine. Useful for situations where you need to
// control the command line arguments directly, but prefer the
// CommandLine version if launching Chrome itself.
BASE_EXPORT Process LaunchProcess(const std::vector<std::string>& argv,
const LaunchOptions& options);
// Close all file descriptors, except those which are a destination in the
// given multimap. Only call this function in a child process where you know
// that there aren't any other threads.
BASE_EXPORT void CloseSuperfluousFds(const InjectiveMultimap& saved_map);
#endif // defined(OS_POSIX)
#if defined(OS_WIN)
// Set |job_object|'s JOBOBJECT_EXTENDED_LIMIT_INFORMATION
// BasicLimitInformation.LimitFlags to |limit_flags|.
BASE_EXPORT bool SetJobObjectLimitFlags(HANDLE job_object, DWORD limit_flags);
// Output multi-process printf, cout, cerr, etc to the cmd.exe console that ran
// chrome. This is not thread-safe: only call from main thread.
BASE_EXPORT void RouteStdioToConsole(bool create_console_if_not_found);
#endif // defined(OS_WIN)
// Executes the application specified by |cl| and wait for it to exit. Stores
// the output (stdout) in |output|. Redirects stderr to /dev/null. Returns true
// on success (application launched and exited cleanly, with exit code
// indicating success).
BASE_EXPORT bool GetAppOutput(const CommandLine& cl, std::string* output);
// Like GetAppOutput, but also includes stderr.
BASE_EXPORT bool GetAppOutputAndError(const CommandLine& cl,
std::string* output);
#if defined(OS_WIN)
// A Windows-specific version of GetAppOutput that takes a command line string
// instead of a CommandLine object. Useful for situations where you need to
// control the command line arguments directly.
BASE_EXPORT bool GetAppOutput(const StringPiece16& cl, std::string* output);
#endif
#if defined(OS_POSIX)
// A POSIX-specific version of GetAppOutput that takes an argv array
// instead of a CommandLine. Useful for situations where you need to
// control the command line arguments directly.
BASE_EXPORT bool GetAppOutput(const std::vector<std::string>& argv,
std::string* output);
// A version of |GetAppOutput()| which also returns the exit code of the
// executed command. Returns true if the application runs and exits cleanly. If
// this is the case the exit code of the application is available in
// |*exit_code|.
BASE_EXPORT bool GetAppOutputWithExitCode(const CommandLine& cl,
std::string* output, int* exit_code);
#endif // defined(OS_POSIX)
// If supported on the platform, and the user has sufficent rights, increase
// the current process's scheduling priority to a high priority.
BASE_EXPORT void RaiseProcessToHighPriority();
#if defined(OS_MACOSX)
// An implementation of LaunchProcess() that uses posix_spawn() instead of
// fork()+exec(). This does not support the |pre_exec_delegate| and
// |current_directory| options.
Process LaunchProcessPosixSpawn(const std::vector<std::string>& argv,
const LaunchOptions& options);
// Restore the default exception handler, setting it to Apple Crash Reporter
// (ReportCrash). When forking and execing a new process, the child will
// inherit the parent's exception ports, which may be set to the Breakpad
// instance running inside the parent. The parent's Breakpad instance should
// not handle the child's exceptions. Calling RestoreDefaultExceptionHandler
// in the child after forking will restore the standard exception handler.
// See http://crbug.com/20371/ for more details.
void RestoreDefaultExceptionHandler();
#endif // defined(OS_MACOSX)
// Creates a LaunchOptions object suitable for launching processes in a test
// binary. This should not be called in production/released code.
BASE_EXPORT LaunchOptions LaunchOptionsForTest();
#if defined(OS_LINUX) || defined(OS_NACL_NONSFI)
// A wrapper for clone with fork-like behavior, meaning that it returns the
// child's pid in the parent and 0 in the child. |flags|, |ptid|, and |ctid| are
// as in the clone system call (the CLONE_VM flag is not supported).
//
// This function uses the libc clone wrapper (which updates libc's pid cache)
// internally, so callers may expect things like getpid() to work correctly
// after in both the child and parent. An exception is when this code is run
// under Valgrind. Valgrind does not support the libc clone wrapper, so the libc
// pid cache may be incorrect after this function is called under Valgrind.
//
// As with fork(), callers should be extremely careful when calling this while
// multiple threads are running, since at the time the fork happened, the
// threads could have been in any state (potentially holding locks, etc.).
// Callers should most likely call execve() in the child soon after calling
// this.
BASE_EXPORT pid_t ForkWithFlags(unsigned long flags, pid_t* ptid, pid_t* ctid);
#endif
} // namespace base
#endif // BASE_PROCESS_LAUNCH_H_

View File

@ -0,0 +1,182 @@
// Copyright 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_PROCESS_PROCESS_H_
#define BASE_PROCESS_PROCESS_H_
#include "base/base_export.h"
#include "base/macros.h"
#include "base/process/process_handle.h"
#include "base/time/time.h"
#include "build/build_config.h"
#if defined(OS_WIN)
#include "base/win/scoped_handle.h"
#endif
#if defined(OS_MACOSX)
#include "base/feature_list.h"
#include "base/process/port_provider_mac.h"
#endif
namespace base {
#if defined(OS_MACOSX)
extern const Feature kMacAllowBackgroundingProcesses;
#endif
// Provides a move-only encapsulation of a process.
//
// This object is not tied to the lifetime of the underlying process: the
// process may be killed and this object may still around, and it will still
// claim to be valid. The actual behavior in that case is OS dependent like so:
//
// Windows: The underlying ProcessHandle will be valid after the process dies
// and can be used to gather some information about that process, but most
// methods will obviously fail.
//
// POSIX: The underlying PorcessHandle is not guaranteed to remain valid after
// the process dies, and it may be reused by the system, which means that it may
// end up pointing to the wrong process.
class BASE_EXPORT Process {
public:
explicit Process(ProcessHandle handle = kNullProcessHandle);
Process(Process&& other);
// The destructor does not terminate the process.
~Process();
Process& operator=(Process&& other);
// Returns an object for the current process.
static Process Current();
// Returns a Process for the given |pid|.
static Process Open(ProcessId pid);
// Returns a Process for the given |pid|. On Windows the handle is opened
// with more access rights and must only be used by trusted code (can read the
// address space and duplicate handles).
static Process OpenWithExtraPrivileges(ProcessId pid);
#if defined(OS_WIN)
// Returns a Process for the given |pid|, using some |desired_access|.
// See ::OpenProcess documentation for valid |desired_access|.
static Process OpenWithAccess(ProcessId pid, DWORD desired_access);
#endif
// Creates an object from a |handle| owned by someone else.
// Don't use this for new code. It is only intended to ease the migration to
// a strict ownership model.
// TODO(rvargas) crbug.com/417532: Remove this code.
static Process DeprecatedGetProcessFromHandle(ProcessHandle handle);
// Returns true if processes can be backgrounded.
static bool CanBackgroundProcesses();
// Returns true if this objects represents a valid process.
bool IsValid() const;
// Returns a handle for this process. There is no guarantee about when that
// handle becomes invalid because this object retains ownership.
ProcessHandle Handle() const;
// Returns a second object that represents this process.
Process Duplicate() const;
// Get the PID for this process.
ProcessId Pid() const;
// Returns true if this process is the current process.
bool is_current() const;
// Close the process handle. This will not terminate the process.
void Close();
// Terminates the process with extreme prejudice. The given |exit_code| will
// be the exit code of the process. If |wait| is true, this method will wait
// for up to one minute for the process to actually terminate.
// Returns true if the process terminates within the allowed time.
// NOTE: On POSIX |exit_code| is ignored.
bool Terminate(int exit_code, bool wait) const;
// Waits for the process to exit. Returns true on success.
// On POSIX, if the process has been signaled then |exit_code| is set to -1.
// On Linux this must be a child process, however on Mac and Windows it can be
// any process.
// NOTE: |exit_code| is optional, nullptr can be passed if the exit code is
// not required.
bool WaitForExit(int* exit_code);
// Same as WaitForExit() but only waits for up to |timeout|.
// NOTE: |exit_code| is optional, nullptr can be passed if the exit code
// is not required.
bool WaitForExitWithTimeout(TimeDelta timeout, int* exit_code);
#if defined(OS_MACOSX)
// The Mac needs a Mach port in order to manipulate a process's priority,
// and there's no good way to get that from base given the pid. These Mac
// variants of the IsProcessBackgrounded and SetProcessBackgrounded API take
// a port provider for this reason. See crbug.com/460102
//
// A process is backgrounded when its task priority is
// |TASK_BACKGROUND_APPLICATION|.
//
// Returns true if the port_provider can locate a task port for the process
// and it is backgrounded. If port_provider is null, returns false.
bool IsProcessBackgrounded(PortProvider* port_provider) const;
// Set the process as backgrounded. If value is
// true, the priority of the associated task will be set to
// TASK_BACKGROUND_APPLICATION. If value is false, the
// priority of the process will be set to TASK_FOREGROUND_APPLICATION.
//
// Returns true if the priority was changed, false otherwise. If
// |port_provider| is null, this is a no-op and it returns false.
bool SetProcessBackgrounded(PortProvider* port_provider, bool value);
#else
// A process is backgrounded when it's priority is lower than normal.
// Return true if this process is backgrounded, false otherwise.
bool IsProcessBackgrounded() const;
// Set a process as backgrounded. If value is true, the priority of the
// process will be lowered. If value is false, the priority of the process
// will be made "normal" - equivalent to default process priority.
// Returns true if the priority was changed, false otherwise.
bool SetProcessBackgrounded(bool value);
#endif // defined(OS_MACOSX)
// Returns an integer representing the priority of a process. The meaning
// of this value is OS dependent.
int GetPriority() const;
#if defined(OS_CHROMEOS)
// Get the PID in its PID namespace.
// If the process is not in a PID namespace or /proc/<pid>/status does not
// report NSpid, kNullProcessId is returned.
ProcessId GetPidInNamespace() const;
#endif
private:
#if defined(OS_WIN)
bool is_current_process_;
win::ScopedHandle process_;
#else
ProcessHandle process_;
#endif
DISALLOW_COPY_AND_ASSIGN(Process);
};
#if defined(OS_CHROMEOS)
// Exposed for testing.
// Given the contents of the /proc/<pid>/cgroup file, determine whether the
// process is backgrounded or not.
BASE_EXPORT bool IsProcessBackgroundedCGroup(
const StringPiece& cgroup_contents);
#endif // defined(OS_CHROMEOS)
} // namespace base
#endif // BASE_PROCESS_PROCESS_H_

View File

@ -0,0 +1,44 @@
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/process/process_handle.h"
#include <windows.h>
#include <tlhelp32.h>
#include "base/win/scoped_handle.h"
#include "base/win/windows_version.h"
namespace base {
ProcessId GetCurrentProcId() {
return ::GetCurrentProcessId();
}
ProcessHandle GetCurrentProcessHandle() {
return ::GetCurrentProcess();
}
ProcessId GetProcId(ProcessHandle process) {
// This returns 0 if we have insufficient rights to query the process handle.
return GetProcessId(process);
}
ProcessId GetParentProcessId(ProcessHandle process) {
ProcessId child_pid = GetProcId(process);
PROCESSENTRY32 process_entry;
process_entry.dwSize = sizeof(PROCESSENTRY32);
win::ScopedHandle snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0));
if (snapshot.IsValid() && Process32First(snapshot.Get(), &process_entry)) {
do {
if (process_entry.th32ProcessID == child_pid)
return process_entry.th32ParentProcessID;
} while (Process32Next(snapshot.Get(), &process_entry));
}
return 0u;
}
} // namespace base

View File

@ -0,0 +1,45 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/rand_util.h"
#include <windows.h>
#include <stddef.h>
#include <stdint.h>
// #define needed to link in RtlGenRandom(), a.k.a. SystemFunction036. See the
// "Community Additions" comment on MSDN here:
// http://msdn.microsoft.com/en-us/library/windows/desktop/aa387694.aspx
#define SystemFunction036 NTAPI SystemFunction036
#include <NTSecAPI.h>
#undef SystemFunction036
#include <algorithm>
#include <limits>
#include "base/logging.h"
namespace base {
// NOTE: This function must be cryptographically secure. http://crbug.com/140076
uint64_t RandUint64() {
uint64_t number;
RandBytes(&number, sizeof(number));
return number;
}
void RandBytes(void* output, size_t output_length) {
char* output_ptr = static_cast<char*>(output);
while (output_length > 0) {
const ULONG output_bytes_this_pass = static_cast<ULONG>(std::min(
output_length, static_cast<size_t>(std::numeric_limits<ULONG>::max())));
const bool success =
RtlGenRandom(output_ptr, output_bytes_this_pass) != FALSE;
CHECK(success);
output_length -= output_bytes_this_pass;
output_ptr += output_bytes_this_pass;
}
}
} // namespace base

View File

@ -5,13 +5,6 @@
#ifndef BASE_SEQUENCE_CHECKER_H_
#define BASE_SEQUENCE_CHECKER_H_
// See comments for the similar block in thread_checker.h.
#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON))
#define ENABLE_SEQUENCE_CHECKER 1
#else
#define ENABLE_SEQUENCE_CHECKER 0
#endif
#include "base/sequence_checker_impl.h"
namespace base {
@ -22,23 +15,22 @@ namespace base {
// the right version for your build configuration.
class SequenceCheckerDoNothing {
public:
bool CalledOnValidSequencedThread() const {
return true;
}
bool CalledOnValidSequence() const { return true; }
void DetachFromSequence() {}
};
// SequenceChecker is a helper class used to help verify that some
// methods of a class are called in sequence -- that is, called from
// the same SequencedTaskRunner. It is a generalization of
// ThreadChecker; see comments in sequence_checker_impl.h for details.
// SequenceChecker is a helper class to verify that calls to some methods of a
// class are sequenced. Calls are sequenced when they are issued:
// - From tasks posted to SequencedTaskRunners or SingleThreadTaskRunners bound
// to the same sequence, or,
// - From a single thread outside of any task.
//
// Example:
// class MyClass {
// public:
// void Foo() {
// DCHECK(sequence_checker_.CalledOnValidSequencedThread());
// DCHECK(sequence_checker_.CalledOnValidSequence());
// ... (do stuff) ...
// }
//
@ -46,16 +38,14 @@ class SequenceCheckerDoNothing {
// SequenceChecker sequence_checker_;
// }
//
// In Release mode, CalledOnValidSequencedThread() will always return true.
#if ENABLE_SEQUENCE_CHECKER
// In Release mode, CalledOnValidSequence() will always return true.
#if DCHECK_IS_ON()
class SequenceChecker : public SequenceCheckerImpl {
};
#else
class SequenceChecker : public SequenceCheckerDoNothing {
};
#endif // ENABLE_SEQUENCE_CHECKER
#undef ENABLE_SEQUENCE_CHECKER
#endif // DCHECK_IS_ON()
} // namespace base

View File

@ -6,30 +6,32 @@
#define BASE_SEQUENCE_CHECKER_IMPL_H_
#include "base/base_export.h"
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/sequence_token.h"
#include "base/synchronization/lock.h"
#include "base/threading/sequenced_worker_pool.h"
#include "base/threading/thread_checker_impl.h"
namespace base {
// SequenceCheckerImpl is used to help verify that some methods of a
// class are called in sequence -- that is, called from the same
// SequencedTaskRunner. It is a generalization of ThreadChecker; in
// particular, it behaves exactly like ThreadChecker if constructed
// on a thread that is not part of a SequencedWorkerPool.
// Real implementation of SequenceChecker for use in debug mode or for temporary
// use in release mode (e.g. to CHECK on a threading issue seen only in the
// wild).
//
// Note: You should almost always use the SequenceChecker class to get the right
// version for your build configuration.
class BASE_EXPORT SequenceCheckerImpl {
public:
SequenceCheckerImpl();
~SequenceCheckerImpl();
// Returns whether the we are being called on the same sequence token
// as previous calls. If there is no associated sequence, then returns
// whether we are being called on the underlying ThreadChecker's thread.
bool CalledOnValidSequencedThread() const;
// Returns true if called in sequence with previous calls to this method and
// the constructor.
bool CalledOnValidSequence() const WARN_UNUSED_RESULT;
// Unbinds the checker from the currently associated sequence. The
// checker will be re-bound on the next call to CalledOnValidSequence().
// Unbinds the checker from the currently associated sequence. The checker
// will be re-bound on the next call to CalledOnValidSequence().
void DetachFromSequence();
private:
@ -38,11 +40,17 @@ class BASE_EXPORT SequenceCheckerImpl {
// Guards all variables below.
mutable Lock lock_;
// Used if |sequence_token_| is not valid.
ThreadCheckerImpl thread_checker_;
mutable bool sequence_token_assigned_;
// True when the SequenceChecker is bound to a sequence or a thread.
mutable bool is_assigned_ = false;
mutable SequencedWorkerPool::SequenceToken sequence_token_;
mutable SequenceToken sequence_token_;
// TODO(gab): Remove this when SequencedWorkerPool is deprecated in favor of
// TaskScheduler. crbug.com/622400
mutable SequencedWorkerPool::SequenceToken sequenced_worker_pool_token_;
// Used when |sequenced_worker_pool_token_| and |sequence_token_| are invalid.
ThreadCheckerImpl thread_checker_;
DISALLOW_COPY_AND_ASSIGN(SequenceCheckerImpl);
};

View File

@ -0,0 +1,115 @@
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_SEQUENCE_TOKEN_H_
#define BASE_SEQUENCE_TOKEN_H_
#include "base/base_export.h"
#include "base/macros.h"
namespace base {
// A token that identifies a series of sequenced tasks (i.e. tasks that run one
// at a time in posting order).
class BASE_EXPORT SequenceToken {
public:
// Instantiates an invalid SequenceToken.
SequenceToken() = default;
// Explicitly allow copy.
SequenceToken(const SequenceToken& other) = default;
SequenceToken& operator=(const SequenceToken& other) = default;
// An invalid SequenceToken is not equal to any other SequenceToken, including
// other invalid SequenceTokens.
bool operator==(const SequenceToken& other) const;
bool operator!=(const SequenceToken& other) const;
// Returns true if this is a valid SequenceToken.
bool IsValid() const;
// Returns the integer uniquely representing this SequenceToken. This method
// should only be used for tracing and debugging.
int ToInternalValue() const;
// Returns a valid SequenceToken which isn't equal to any previously returned
// SequenceToken.
static SequenceToken Create();
// Returns the SequenceToken associated with the task running on the current
// thread, as determined by the active ScopedSetSequenceTokenForCurrentThread
// if any.
static SequenceToken GetForCurrentThread();
private:
explicit SequenceToken(int token) : token_(token) {}
static constexpr int kInvalidSequenceToken = -1;
int token_ = kInvalidSequenceToken;
};
// A token that identifies a task.
//
// This is used by ThreadCheckerImpl to determine whether calls to
// CalledOnValidThread() come from the same task and hence are deterministically
// single-threaded (vs. calls coming from different sequenced or parallel tasks,
// which may or may not run on the same thread).
class BASE_EXPORT TaskToken {
public:
// Instantiates an invalid TaskToken.
TaskToken() = default;
// Explicitly allow copy.
TaskToken(const TaskToken& other) = default;
TaskToken& operator=(const TaskToken& other) = default;
// An invalid TaskToken is not equal to any other TaskToken, including
// other invalid TaskTokens.
bool operator==(const TaskToken& other) const;
bool operator!=(const TaskToken& other) const;
// Returns true if this is a valid TaskToken.
bool IsValid() const;
// In the scope of a ScopedSetSequenceTokenForCurrentThread, returns a valid
// TaskToken which isn't equal to any TaskToken returned in the scope of a
// different ScopedSetSequenceTokenForCurrentThread. Otherwise, returns an
// invalid TaskToken.
static TaskToken GetForCurrentThread();
private:
friend class ScopedSetSequenceTokenForCurrentThread;
explicit TaskToken(int token) : token_(token) {}
// Returns a valid TaskToken which isn't equal to any previously returned
// TaskToken. This is private as it only meant to be instantiated by
// ScopedSetSequenceTokenForCurrentThread.
static TaskToken Create();
static constexpr int kInvalidTaskToken = -1;
int token_ = kInvalidTaskToken;
};
// Instantiate this in the scope where a single task runs.
class BASE_EXPORT ScopedSetSequenceTokenForCurrentThread {
public:
// Throughout the lifetime of the constructed object,
// SequenceToken::GetForCurrentThread() will return |sequence_token| and
// TaskToken::GetForCurrentThread() will return a TaskToken which is not equal
// to any TaskToken returned in the scope of another
// ScopedSetSequenceTokenForCurrentThread.
ScopedSetSequenceTokenForCurrentThread(const SequenceToken& sequence_token);
~ScopedSetSequenceTokenForCurrentThread();
private:
const SequenceToken sequence_token_;
const TaskToken task_token_;
DISALLOW_COPY_AND_ASSIGN(ScopedSetSequenceTokenForCurrentThread);
};
} // namespace base
#endif // BASE_SEQUENCE_TOKEN_H_

View File

@ -154,6 +154,24 @@ class BASE_EXPORT SequencedTaskRunner : public TaskRunner {
const void* object);
};
struct BASE_EXPORT OnTaskRunnerDeleter {
explicit OnTaskRunnerDeleter(scoped_refptr<SequencedTaskRunner> task_runner);
~OnTaskRunnerDeleter();
OnTaskRunnerDeleter(OnTaskRunnerDeleter&&);
OnTaskRunnerDeleter& operator=(OnTaskRunnerDeleter&&);
template <typename T>
void operator()(const T* ptr) {
if (task_runner_->RunsTasksOnCurrentThread())
delete ptr;
else if (ptr)
task_runner_->DeleteSoon(FROM_HERE, ptr);
}
scoped_refptr<SequencedTaskRunner> task_runner_;
};
} // namespace base
#endif // BASE_SEQUENCED_TASK_RUNNER_H_

View File

@ -15,6 +15,8 @@
#include "base/logging.h"
namespace base {
// Clears 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.
@ -27,69 +29,6 @@ void STLClearObject(T* obj) {
obj->reserve(0);
}
// 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;
}
}
// 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;
}
}
// 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;
}
}
// For a range within a container of pairs, calls delete.
// NOTE: Like STLDeleteContainerPointers, deleting behind the iterator.
// Deleting the value does not always invalidate the iterator, but it may
// do so if the key is a pointer into the value object.
template <class ForwardIterator>
void STLDeleteContainerPairSecondPointers(ForwardIterator begin,
ForwardIterator end) {
while (begin != end) {
ForwardIterator temp = begin;
++begin;
delete temp->second;
}
}
// Counts the number of instances of val in a container.
template <typename Container, typename T>
typename std::iterator_traits<
@ -124,15 +63,17 @@ inline char* string_as_array(std::string* str) {
// 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());
for (auto it = container->begin(); it != container->end();) {
auto temp = it;
++it;
delete *temp;
}
container->clear();
}
@ -143,46 +84,16 @@ template <class T>
void STLDeleteValues(T* container) {
if (!container)
return;
STLDeleteContainerPairSecondPointers(container->begin(), container->end());
for (auto it = container->begin(); it != container->end();) {
auto temp = it;
++it;
delete temp->second;
}
container->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 T>
class STLElementDeleter {
public:
STLElementDeleter<T>(T* container) : container_(container) {}
~STLElementDeleter<T>() { STLDeleteElements(container_); }
private:
T* container_;
};
// Given a pointer to an STL container this class will delete all the value
// pointers when it goes out of scope.
template<class T>
class STLValueDeleter {
public:
STLValueDeleter<T>(T* container) : container_(container) {}
~STLValueDeleter<T>() { STLDeleteValues(container_); }
private:
T* container_;
};
// Test to see if a set, map, hash_set or hash_map contains a particular key.
// Returns true if the key is in the collection.
template <typename Collection, typename Key>
@ -198,8 +109,6 @@ bool ContainsValue(const Collection& collection, const Value& value) {
collection.end();
}
namespace base {
// Returns true if the container is sorted.
template <typename Container>
bool STLIsSorted(const Container& cont) {

View File

@ -10,10 +10,10 @@
#include <string.h>
#include <limits>
#include <memory>
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
@ -205,7 +205,7 @@ TEST(SafeSPrintfTest, ASANFriendlyBufferTest) {
// There is a more complicated test in PrintLongString() that covers a lot
// more edge case, but it is also harder to debug in case of a failure.
const char kTestString[] = "This is a test";
scoped_ptr<char[]> buf(new char[sizeof(kTestString)]);
std::unique_ptr<char[]> buf(new char[sizeof(kTestString)]);
EXPECT_EQ(static_cast<ssize_t>(sizeof(kTestString) - 1),
SafeSNPrintf(buf.get(), sizeof(kTestString), kTestString));
EXPECT_EQ(std::string(kTestString), std::string(buf.get()));
@ -369,7 +369,7 @@ void PrintLongString(char* buf, size_t sz) {
// Allocate slightly more space, so that we can verify that SafeSPrintf()
// never writes past the end of the buffer.
scoped_ptr<char[]> tmp(new char[sz+2]);
std::unique_ptr<char[]> tmp(new char[sz + 2]);
memset(tmp.get(), 'X', sz+2);
// Use SafeSPrintf() to output a complex list of arguments:
@ -383,7 +383,7 @@ void PrintLongString(char* buf, size_t sz) {
char* out = tmp.get();
size_t out_sz = sz;
size_t len;
for (scoped_ptr<char[]> perfect_buf;;) {
for (std::unique_ptr<char[]> perfect_buf;;) {
size_t needed = SafeSNPrintf(out, out_sz,
#if defined(NDEBUG)
"A%2cong %s: %d %010X %d %p%7s", 'l', "string", "",

View File

@ -29,6 +29,8 @@
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <functional>
#include <string>
#include "base/base_export.h"
@ -46,6 +48,8 @@ typedef std::char_traits<wchar_t> string16_char_traits;
#elif defined(WCHAR_T_IS_UTF32)
#include <wchar.h> // for mbstate_t
namespace base {
typedef uint16_t char16;
@ -182,6 +186,21 @@ BASE_EXPORT extern void PrintTo(const string16& str, std::ostream* out);
extern template
class BASE_EXPORT std::basic_string<base::char16, base::string16_char_traits>;
// Specialize std::hash for base::string16. Although the style guide forbids
// this in general, it is necessary for consistency with WCHAR_T_IS_UTF16
// platforms, where base::string16 is a type alias for std::wstring.
namespace std {
template <>
struct hash<base::string16> {
std::size_t operator()(const base::string16& s) const {
std::size_t result = 0;
for (base::char16 c : s)
result = (result * 131) + c;
return result;
}
};
} // namespace std
#endif // WCHAR_T_IS_UTF32
#endif // BASE_STRINGS_STRING16_H_

View File

@ -12,10 +12,8 @@
#include <limits>
#include "base/logging.h"
#include "base/numerics/safe_conversions.h"
#include "base/numerics/safe_math.h"
#include "base/scoped_clear_errno.h"
#include "base/strings/utf_string_conversions.h"
#include "base/third_party/dmg_fp/dmg_fp.h"
namespace base {
@ -146,6 +144,7 @@ class IteratorRangeToNumber {
if (begin != end && *begin == '-') {
if (!std::numeric_limits<value_type>::is_signed) {
*output = 0;
valid = false;
} else if (!Negative::Invoke(begin + 1, end, output)) {
valid = false;

View File

@ -25,6 +25,14 @@
// Please do not add "convenience" functions for converting strings to integers
// that return the value and ignore success/failure. That encourages people to
// write code that doesn't properly handle the error conditions.
//
// DO NOT use these functions in any UI unless it's NOT localized on purpose.
// Instead, use base::MessageFormatter for a complex message with numbers
// (integer, float, double) embedded or base::Format{Number,Double,Percent} to
// just format a single number/percent. Note that some languages use native
// digits instead of ASCII digits while others use a group separator or decimal
// point different from ',' and '.'. Using these functions in the UI would lead
// numbers to be formatted in a non-native way.
// ----------------------------------------------------------------------------
namespace base {

View File

@ -28,7 +28,6 @@
#include <string>
#include "base/base_export.h"
#include "base/containers/hash_tables.h"
#include "base/logging.h"
#include "base/strings/string16.h"
@ -224,6 +223,8 @@ template <typename STRING_TYPE> class BasicStringPiece {
}
value_type operator[](size_type i) const { return ptr_[i]; }
value_type front() const { return ptr_[0]; }
value_type back() const { return ptr_[length_ - 1]; }
void remove_prefix(size_type n) {
ptr_ += n;
@ -432,38 +433,32 @@ inline bool operator>=(const StringPiece16& x, const StringPiece16& y) {
BASE_EXPORT std::ostream& operator<<(std::ostream& o,
const StringPiece& piece);
} // namespace base
// Hashing ---------------------------------------------------------------------
// We provide appropriate hash functions so StringPiece and StringPiece16 can
// be used as keys in hash sets and maps.
// This hash function is copied from base/containers/hash_tables.h. We don't
// use the ones already defined for string and string16 directly because it
// would require the string constructors to be called, which we don't want.
#define HASH_STRING_PIECE(StringPieceType, string_piece) \
std::size_t result = 0; \
for (StringPieceType::const_iterator i = string_piece.begin(); \
i != string_piece.end(); ++i) \
result = (result * 131) + *i; \
return result; \
// This hash function is copied from base/strings/string16.h. We don't use the
// ones already defined for string and string16 directly because it would
// require the string constructors to be called, which we don't want.
#define HASH_STRING_PIECE(StringPieceType, string_piece) \
std::size_t result = 0; \
for (StringPieceType::const_iterator i = string_piece.begin(); \
i != string_piece.end(); ++i) \
result = (result * 131) + *i; \
return result;
namespace BASE_HASH_NAMESPACE {
template<>
struct hash<base::StringPiece> {
std::size_t operator()(const base::StringPiece& sp) const {
HASH_STRING_PIECE(base::StringPiece, sp);
struct StringPieceHash {
std::size_t operator()(const StringPiece& sp) const {
HASH_STRING_PIECE(StringPiece, sp);
}
};
template<>
struct hash<base::StringPiece16> {
std::size_t operator()(const base::StringPiece16& sp16) const {
HASH_STRING_PIECE(base::StringPiece16, sp16);
struct StringPiece16Hash {
std::size_t operator()(const StringPiece16& sp16) const {
HASH_STRING_PIECE(StringPiece16, sp16);
}
};
} // namespace BASE_HASH_NAMESPACE
} // namespace base
#endif // BASE_STRINGS_STRING_PIECE_H_

View File

@ -227,18 +227,22 @@ bool SplitStringIntoKeyValuePairs(StringPiece input,
return success;
}
void SplitStringUsingSubstr(StringPiece16 input,
StringPiece16 delimiter,
std::vector<string16>* result) {
SplitStringUsingSubstrT(input, delimiter, TRIM_WHITESPACE, SPLIT_WANT_ALL,
result);
std::vector<string16> SplitStringUsingSubstr(StringPiece16 input,
StringPiece16 delimiter,
WhitespaceHandling whitespace,
SplitResult result_type) {
std::vector<string16> result;
SplitStringUsingSubstrT(input, delimiter, whitespace, result_type, &result);
return result;
}
void SplitStringUsingSubstr(StringPiece input,
StringPiece delimiter,
std::vector<std::string>* result) {
SplitStringUsingSubstrT(input, delimiter, TRIM_WHITESPACE, SPLIT_WANT_ALL,
result);
std::vector<std::string> SplitStringUsingSubstr(StringPiece input,
StringPiece delimiter,
WhitespaceHandling whitespace,
SplitResult result_type) {
std::vector<std::string> result;
SplitStringUsingSubstrT(input, delimiter, whitespace, result_type, &result);
return result;
}
std::vector<StringPiece16> SplitStringPieceUsingSubstr(

View File

@ -90,16 +90,16 @@ BASE_EXPORT bool SplitStringIntoKeyValuePairs(StringPiece input,
// Similar to SplitString, but use a substring delimiter instead of a list of
// characters that are all possible delimiters.
//
// TODO(brettw) this should probably be changed and expanded to provide a
// mirror of the SplitString[Piece] API above, just with the different
// delimiter handling.
BASE_EXPORT void SplitStringUsingSubstr(StringPiece16 input,
StringPiece16 delimiter,
std::vector<string16>* result);
BASE_EXPORT void SplitStringUsingSubstr(StringPiece input,
StringPiece delimiter,
std::vector<std::string>* result);
BASE_EXPORT std::vector<string16> SplitStringUsingSubstr(
StringPiece16 input,
StringPiece16 delimiter,
WhitespaceHandling whitespace,
SplitResult result_type);
BASE_EXPORT std::vector<std::string> SplitStringUsingSubstr(
StringPiece input,
StringPiece delimiter,
WhitespaceHandling whitespace,
SplitResult result_type);
// Like SplitStringUsingSubstr above except it returns a vector of StringPieces
// which reference the original buffer without copying. Although you have to be

View File

@ -23,7 +23,6 @@
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/singleton.h"
#include "base/strings/string_split.h"
#include "base/strings/utf_string_conversion_utils.h"
#include "base/strings/utf_string_conversions.h"
#include "base/third_party/icu/icu_utf.h"
@ -888,6 +887,7 @@ OutStringType DoReplaceStringPlaceholders(
const std::vector<OutStringType>& subst,
std::vector<size_t>* offsets) {
size_t substitutions = subst.size();
DCHECK_LT(substitutions, 10U);
size_t sub_length = 0;
for (const auto& cur : subst)
@ -901,7 +901,6 @@ OutStringType DoReplaceStringPlaceholders(
if ('$' == *i) {
if (i + 1 != format_string.end()) {
++i;
DCHECK('$' == *i || '1' <= *i) << "Invalid placeholder: " << *i;
if ('$' == *i) {
while (i != format_string.end() && '$' == *i) {
formatted.push_back('$');
@ -909,14 +908,11 @@ OutStringType DoReplaceStringPlaceholders(
}
--i;
} else {
uintptr_t index = 0;
while (i != format_string.end() && '0' <= *i && *i <= '9') {
index *= 10;
index += *i - '0';
++i;
if (*i < '1' || *i > '9') {
DLOG(ERROR) << "Invalid placeholder: $" << *i;
continue;
}
--i;
index -= 1;
uintptr_t index = *i - '1';
if (offsets) {
ReplacementOffset r_offset(index,
static_cast<int>(formatted.size()));

View File

@ -337,7 +337,15 @@ inline bool IsAsciiWhitespace(Char c) {
}
template <typename Char>
inline bool IsAsciiAlpha(Char c) {
return ((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z'));
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');
}
template <typename Char>
inline bool IsAsciiUpper(Char c) {
return c >= 'A' && c <= 'Z';
}
template <typename Char>
inline bool IsAsciiLower(Char c) {
return c >= 'a' && c <= 'z';
}
template <typename Char>
inline bool IsAsciiDigit(Char c) {
@ -429,7 +437,7 @@ BASE_EXPORT std::string JoinString(const std::vector<std::string>& parts,
BASE_EXPORT string16 JoinString(const std::vector<string16>& parts,
StringPiece16 separator);
// Replace $1-$2-$3..$9 in the format string with |a|-|b|-|c|..|i| respectively.
// Replace $1-$2-$3..$9 in the format string with values from |subst|.
// Additionally, any number of consecutive '$' characters is replaced by that
// number less one. Eg $$->$, $$$->$$, etc. The offsets parameter here can be
// NULL. This only allows you to use up to nine replacements.

View File

@ -5,7 +5,8 @@
#ifndef BASE_STRINGS_UTF_STRING_CONVERSION_UTILS_H_
#define BASE_STRINGS_UTF_STRING_CONVERSION_UTILS_H_
// This should only be used by the various UTF string conversion files.
// Low-level UTF handling functions. Most code will want to use the functions
// in utf_string_conversions.h
#include <stddef.h>
#include <stdint.h>

View File

@ -75,9 +75,12 @@
#include <pthread.h>
#endif
#if defined(OS_WIN)
#include <windows.h>
#endif
namespace base {
class ConditionVarImpl;
class TimeDelta;
class BASE_EXPORT ConditionVariable {
@ -88,11 +91,13 @@ class BASE_EXPORT ConditionVariable {
~ConditionVariable();
// Wait() releases the caller's critical section atomically as it starts to
// sleep, and the reacquires it when it is signaled.
// 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 TimeDelta& max_time);
// Broadcast() revives all waiting threads.
// Broadcast() revives all waiting threads. (See usage note 2 for more
// details.)
void Broadcast();
// Signal() revives one waiting thread.
void Signal();
@ -100,14 +105,15 @@ class BASE_EXPORT ConditionVariable {
private:
#if defined(OS_WIN)
ConditionVarImpl* impl_;
CONDITION_VARIABLE cv_;
SRWLOCK* const srwlock_;
#elif defined(OS_POSIX)
pthread_cond_t condition_;
pthread_mutex_t* user_mutex_;
#if DCHECK_IS_ON()
base::Lock* user_lock_; // Needed to adjust shadow lock state on wait.
#endif
#if DCHECK_IS_ON() && (defined(OS_WIN) || defined(OS_POSIX))
base::Lock* const user_lock_; // Needed to adjust shadow lock state on wait.
#endif
DISALLOW_COPY_AND_ASSIGN(ConditionVariable);

View File

@ -118,6 +118,8 @@ void ConditionVariable::TimedWait(const TimeDelta& max_time) {
#endif // OS_ANDROID && HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC
#endif // OS_MACOSX
// 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);
#if DCHECK_IS_ON()
user_lock_->CheckUnheldAndMark();

View File

@ -38,9 +38,9 @@ class BASE_EXPORT Lock {
Lock();
~Lock();
// NOTE: Although windows critical sections support recursive locks, we do not
// allow this, and we will commonly fire a DCHECK() if a thread attempts to
// acquire the lock a second time (while already holding it).
// NOTE: We do not permit recursive locks and will commonly fire a DCHECK() if
// a thread attempts to acquire the lock a second time (while already holding
// it).
void Acquire() {
lock_.Lock();
CheckUnheldAndMark();
@ -61,15 +61,28 @@ class BASE_EXPORT Lock {
void AssertAcquired() const;
#endif // DCHECK_IS_ON()
// Whether Lock mitigates priority inversion when used from different thread
// priorities.
static bool HandlesMultipleThreadPriorities() {
#if defined(OS_POSIX)
// The posix implementation of ConditionVariable needs to be able
// to see our lock and tweak our debugging counters, as it releases
// and acquires locks inside of pthread_cond_{timed,}wait.
friend class ConditionVariable;
// 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 internal::LockImpl::PriorityInheritanceAvailable();
#elif defined(OS_WIN)
// The Windows Vista implementation of ConditionVariable needs the
// native handle of the critical section.
friend class WinVistaCondVar;
// Windows mitigates priority inversion by randomly boosting the priority of
// ready threads.
// https://msdn.microsoft.com/library/windows/desktop/ms684831.aspx
return true;
#else
#error Unsupported platform
#endif
}
#if defined(OS_POSIX) || defined(OS_WIN)
// 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;
#endif
private:

View File

@ -24,9 +24,9 @@ namespace internal {
class BASE_EXPORT LockImpl {
public:
#if defined(OS_WIN)
typedef CRITICAL_SECTION NativeHandle;
using NativeHandle = SRWLOCK;
#elif defined(OS_POSIX)
typedef pthread_mutex_t NativeHandle;
using NativeHandle = pthread_mutex_t;
#endif
LockImpl();
@ -48,6 +48,11 @@ class BASE_EXPORT LockImpl {
// unnecessary.
NativeHandle* native_handle() { return &native_handle_; }
#if defined(OS_POSIX)
// Whether this lock will attempt to use priority inheritance.
static bool PriorityInheritanceAvailable();
#endif
private:
NativeHandle native_handle_;

View File

@ -7,27 +7,45 @@
#include <errno.h>
#include <string.h>
#include "base/debug/activity_tracker.h"
#include "base/logging.h"
#include "base/synchronization/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(OS_NACL) || defined(OS_ANDROID)
#define PRIORITY_INHERITANCE_LOCKS_POSSIBLE() 0
#else
#define PRIORITY_INHERITANCE_LOCKS_POSSIBLE() 1
#endif
LockImpl::LockImpl() {
#ifndef NDEBUG
// In debug, setup attributes for lock error checking.
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);
#else
// In release, go with the default lock attributes.
pthread_mutex_init(&native_handle_, NULL);
#endif
}
LockImpl::~LockImpl() {
@ -42,6 +60,7 @@ bool LockImpl::Try() {
}
void LockImpl::Lock() {
base::debug::ScopedLockAcquireActivity lock_activity(this);
int rv = pthread_mutex_lock(&native_handle_);
DCHECK_EQ(rv, 0) << ". " << strerror(rv);
}
@ -51,5 +70,29 @@ void LockImpl::Unlock() {
DCHECK_EQ(rv, 0) << ". " << strerror(rv);
}
// static
bool LockImpl::PriorityInheritanceAvailable() {
#if PRIORITY_INHERITANCE_LOCKS_POSSIBLE() && defined(OS_MACOSX)
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

View File

@ -4,32 +4,26 @@
#include "base/synchronization/lock_impl.h"
#include "base/debug/activity_tracker.h"
namespace base {
namespace internal {
LockImpl::LockImpl() {
// The second parameter is the spin count, for short-held locks it avoid the
// contending thread from going to sleep which helps performance greatly.
::InitializeCriticalSectionAndSpinCount(&native_handle_, 2000);
}
LockImpl::LockImpl() : native_handle_(SRWLOCK_INIT) {}
LockImpl::~LockImpl() {
::DeleteCriticalSection(&native_handle_);
}
LockImpl::~LockImpl() = default;
bool LockImpl::Try() {
if (::TryEnterCriticalSection(&native_handle_) != FALSE) {
return true;
}
return false;
return !!::TryAcquireSRWLockExclusive(&native_handle_);
}
void LockImpl::Lock() {
::EnterCriticalSection(&native_handle_);
base::debug::ScopedLockAcquireActivity lock_activity(this);
::AcquireSRWLockExclusive(&native_handle_);
}
void LockImpl::Unlock() {
::LeaveCriticalSection(&native_handle_);
::ReleaseSRWLockExclusive(&native_handle_);
}
} // namespace internal

View File

@ -43,11 +43,18 @@ class TimeDelta;
// be better off just using an Windows event directly.
class BASE_EXPORT WaitableEvent {
public:
// If manual_reset is true, then to set the event state to non-signaled, a
// consumer must call the Reset method. If this parameter is false, then the
// system automatically resets the event state to non-signaled after a single
// waiting thread has been released.
WaitableEvent(bool manual_reset, bool initially_signaled);
// Indicates whether a WaitableEvent should automatically reset the event
// state after a single waiting thread has been released or remain signaled
// until Reset() is manually invoked.
enum class ResetPolicy { MANUAL, AUTOMATIC };
// Indicates whether a new WaitableEvent should start in a signaled state or
// not.
enum class InitialState { SIGNALED, NOT_SIGNALED };
// Constructs a WaitableEvent with policy and initial state as detailed in
// the above enums.
WaitableEvent(ResetPolicy reset_policy, InitialState initial_state);
#if defined(OS_WIN)
// Create a WaitableEvent from an Event HANDLE which has already been
@ -150,7 +157,7 @@ class BASE_EXPORT WaitableEvent {
struct WaitableEventKernel :
public RefCountedThreadSafe<WaitableEventKernel> {
public:
WaitableEventKernel(bool manual_reset, bool initially_signaled);
WaitableEventKernel(ResetPolicy reset_policy, InitialState initial_state);
bool Dequeue(Waiter* waiter, void* tag);

View File

@ -7,6 +7,7 @@
#include <algorithm>
#include <vector>
#include "base/debug/activity_tracker.h"
#include "base/logging.h"
#include "base/synchronization/condition_variable.h"
#include "base/synchronization/lock.h"
@ -39,12 +40,11 @@ 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(ResetPolicy reset_policy,
InitialState initial_state)
: kernel_(new WaitableEventKernel(reset_policy, initial_state)) {}
WaitableEvent::~WaitableEvent() {
}
WaitableEvent::~WaitableEvent() = default;
void WaitableEvent::Reset() {
base::AutoLock locked(kernel_->lock_);
@ -158,6 +158,9 @@ void WaitableEvent::Wait() {
}
bool WaitableEvent::TimedWait(const TimeDelta& max_time) {
// Record the event that this thread is blocking upon (for hang diagnosis).
base::debug::ScopedEventWaitActivity event_activity(this);
base::ThreadRestrictions::AssertWaitAllowed();
const TimeTicks end_time(TimeTicks::Now() + max_time);
const bool finite_time = max_time.ToInternalValue() >= 0;
@ -233,6 +236,9 @@ size_t WaitableEvent::WaitMany(WaitableEvent** raw_waitables,
base::ThreadRestrictions::AssertWaitAllowed();
DCHECK(count) << "Cannot wait on no events";
// Record an event (the first) that this thread is blocking upon.
base::debug::ScopedEventWaitActivity event_activity(raw_waitables[0]);
// 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.
@ -348,14 +354,13 @@ size_t WaitableEvent::EnqueueMany
// -----------------------------------------------------------------------------
// Private functions...
WaitableEvent::WaitableEventKernel::WaitableEventKernel(bool manual_reset,
bool initially_signaled)
: manual_reset_(manual_reset),
signaled_(initially_signaled) {
}
WaitableEvent::WaitableEventKernel::WaitableEventKernel(
ResetPolicy reset_policy,
InitialState initial_state)
: manual_reset_(reset_policy == ResetPolicy::MANUAL),
signaled_(initial_state == InitialState::SIGNALED) {}
WaitableEvent::WaitableEventKernel::~WaitableEventKernel() {
}
WaitableEvent::WaitableEventKernel::~WaitableEventKernel() = default;
// -----------------------------------------------------------------------------
// Wake all waiting waiters. Called with lock held.

View File

@ -9,13 +9,10 @@
#include "base/base_export.h"
#include "base/callback_forward.h"
#include "base/location.h"
#include "base/memory/ref_counted.h"
#include "base/time/time.h"
namespace tracked_objects {
class Location;
} // namespace tracked_objects
namespace base {
struct TaskRunnerTraits;

View File

@ -0,0 +1,132 @@
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef BASE_TASK_SCHEDULER_TASK_TRAITS_H_
#define BASE_TASK_SCHEDULER_TASK_TRAITS_H_
#include <stdint.h>
#include <iosfwd>
#include "base/base_export.h"
#include "build/build_config.h"
namespace base {
// Valid priorities supported by the task scheduler. Note: internal algorithms
// depend on priorities being expressed as a continuous zero-based list from
// lowest to highest priority. Users of this API shouldn't otherwise care about
// nor use the underlying values.
enum class TaskPriority {
// This will always be equal to the lowest priority available.
LOWEST = 0,
// User won't notice if this task takes an arbitrarily long time to complete.
BACKGROUND = LOWEST,
// This task affects UI or responsiveness of future user interactions. It is
// not an immediate response to a user interaction.
// Examples:
// - Updating the UI to reflect progress on a long task.
// - Loading data that might be shown in the UI after a future user
// interaction.
USER_VISIBLE,
// This task affects UI immediately after a user interaction.
// Example: Generating data shown in the UI immediately after a click.
USER_BLOCKING,
// This will always be equal to the highest priority available.
HIGHEST = USER_BLOCKING,
};
// Valid shutdown behaviors supported by the task scheduler.
enum class TaskShutdownBehavior {
// Tasks posted with this mode which have not started executing before
// shutdown is initiated will never run. Tasks with this mode running at
// shutdown will be ignored (the worker will not be joined).
//
// This option provides a nice way to post stuff you don't want blocking
// shutdown. For example, you might be doing a slow DNS lookup and if it's
// blocked on the OS, you may not want to stop shutdown, since the result
// doesn't really matter at that point.
//
// However, you need to be very careful what you do in your callback when you
// use this option. Since the thread will continue to run until the OS
// terminates the process, the app can be in the process of tearing down when
// you're running. This means any singletons or global objects you use may
// suddenly become invalid out from under you. For this reason, it's best to
// use this only for slow but simple operations like the DNS example.
CONTINUE_ON_SHUTDOWN,
// Tasks posted with this mode that have not started executing at
// shutdown will never run. However, any task that has already begun
// executing when shutdown is invoked will be allowed to continue and
// will block shutdown until completion.
//
// Note: Because TaskScheduler::Shutdown() may block while these tasks are
// executing, care must be taken to ensure that they do not block on the
// thread that called TaskScheduler::Shutdown(), as this may lead to deadlock.
SKIP_ON_SHUTDOWN,
// Tasks posted with this mode before shutdown is complete will block shutdown
// until they're executed. Generally, this should be used only to save
// critical user data.
//
// Note: Tasks with BACKGROUND priority that block shutdown will be promoted
// to USER_VISIBLE priority during shutdown.
BLOCK_SHUTDOWN,
};
// Describes metadata for a single task or a group of tasks.
class BASE_EXPORT TaskTraits {
public:
// Constructs a default TaskTraits for tasks with
// (1) no I/O,
// (2) low priority, and
// (3) may block shutdown or be skipped on shutdown.
// Tasks that require stricter guarantees should highlight those by requesting
// explicit traits below.
TaskTraits();
TaskTraits(const TaskTraits& other) = default;
TaskTraits& operator=(const TaskTraits& other) = default;
~TaskTraits();
// Allows tasks with these traits to do file I/O.
TaskTraits& WithFileIO();
// Applies |priority| to tasks with these traits.
TaskTraits& WithPriority(TaskPriority priority);
// Applies |shutdown_behavior| to tasks with these traits.
TaskTraits& WithShutdownBehavior(TaskShutdownBehavior shutdown_behavior);
// Returns true if file I/O is allowed by these traits.
bool with_file_io() const { return with_file_io_; }
// Returns the priority of tasks with these traits.
TaskPriority priority() const { return priority_; }
// Returns the shutdown behavior of tasks with these traits.
TaskShutdownBehavior shutdown_behavior() const { return shutdown_behavior_; }
private:
bool with_file_io_;
TaskPriority priority_;
TaskShutdownBehavior shutdown_behavior_;
};
// Returns string literals for the enums defined in this file. These methods
// should only be used for tracing and debugging.
BASE_EXPORT const char* TaskPriorityToString(TaskPriority task_priority);
BASE_EXPORT const char* TaskShutdownBehaviorToString(
TaskShutdownBehavior task_priority);
// Stream operators so that the enums defined in this file can be used in
// DCHECK and EXPECT statements.
BASE_EXPORT std::ostream& operator<<(std::ostream& os,
const TaskPriority& shutdown_behavior);
BASE_EXPORT std::ostream& operator<<(
std::ostream& os,
const TaskShutdownBehavior& shutdown_behavior);
} // namespace base
#endif // BASE_TASK_SCHEDULER_TASK_TRAITS_H_

View File

@ -6,117 +6,128 @@
#define BASE_TEMPLATE_UTIL_H_
#include <stddef.h>
#include <iosfwd>
#include <type_traits>
#include <utility>
#include "build/build_config.h"
// This hacks around libstdc++ 4.6 missing stuff in type_traits, while we need
// to support it.
#define CR_GLIBCXX_4_7_0 20120322
#define CR_GLIBCXX_4_5_4 20120702
#define CR_GLIBCXX_4_6_4 20121127
#if defined(__GLIBCXX__) && \
(__GLIBCXX__ < CR_GLIBCXX_4_7_0 || __GLIBCXX__ == CR_GLIBCXX_4_5_4 || \
__GLIBCXX__ == CR_GLIBCXX_4_6_4)
#define CR_USE_FALLBACKS_FOR_OLD_GLIBCXX
#endif
namespace base {
// template definitions from tr1
template <class T> struct is_non_const_reference : std::false_type {};
template <class T> struct is_non_const_reference<T&> : std::true_type {};
template <class T> struct is_non_const_reference<const T&> : std::false_type {};
template<class T, T v>
struct integral_constant {
static const T value = v;
typedef T value_type;
typedef integral_constant<T, v> type;
};
template <class T, T v> const T integral_constant<T, v>::value;
typedef integral_constant<bool, true> true_type;
typedef integral_constant<bool, false> false_type;
template <class T> struct is_pointer : false_type {};
template <class T> struct is_pointer<T*> : true_type {};
// Member function pointer detection. This is built-in to C++ 11's stdlib, and
// we can remove this when we switch to it.
template<typename T>
struct is_member_function_pointer : false_type {};
template <typename R, typename Z, typename... A>
struct is_member_function_pointer<R(Z::*)(A...)> : true_type {};
template <typename R, typename Z, typename... A>
struct is_member_function_pointer<R(Z::*)(A...) const> : true_type {};
template <class T, class U> struct is_same : public false_type {};
template <class T> struct is_same<T,T> : true_type {};
template<class> struct is_array : public false_type {};
template<class T, size_t n> struct is_array<T[n]> : public true_type {};
template<class T> struct is_array<T[]> : public true_type {};
template <class T> struct is_non_const_reference : false_type {};
template <class T> struct is_non_const_reference<T&> : true_type {};
template <class T> struct is_non_const_reference<const T&> : false_type {};
template <class T> struct is_const : false_type {};
template <class T> struct is_const<const T> : true_type {};
template <class T> struct is_void : false_type {};
template <> struct is_void<void> : true_type {};
// is_assignable
namespace internal {
// Types YesType and NoType are guaranteed such that sizeof(YesType) <
// sizeof(NoType).
typedef char YesType;
struct NoType {
YesType dummy[2];
template <typename First, typename Second>
struct SelectSecond {
using type = Second;
};
// This class is an implementation detail for is_convertible, and you
// don't need to know how it works to use is_convertible. For those
// who care: we declare two different functions, one whose argument is
// of type To and one with a variadic argument list. We give them
// return types of different size, so we can use sizeof to trick the
// compiler into telling us which function it would have chosen if we
// had called it with an argument of type From. See Alexandrescu's
// _Modern C++ Design_ for more details on this sort of trick.
struct ConvertHelper {
template <typename To>
static YesType Test(To);
template <typename To>
static NoType Test(...);
template <typename From>
static From& Create();
struct Any {
Any(...);
};
// Used to determine if a type is a struct/union/class. Inspired by Boost's
// is_class type_trait implementation.
struct IsClassHelper {
template <typename C>
static YesType Test(void(C::*)(void));
// True case: If |Lvalue| can be assigned to from |Rvalue|, then the return
// value is a true_type.
template <class Lvalue, class Rvalue>
typename internal::SelectSecond<
decltype((std::declval<Lvalue>() = std::declval<Rvalue>())),
std::true_type>::type
IsAssignableTest(Lvalue&&, Rvalue&&);
template <typename C>
static NoType Test(...);
};
// False case: Otherwise the return value is a false_type.
template <class Rvalue>
std::false_type IsAssignableTest(internal::Any, Rvalue&&);
// Default case: Neither Lvalue nor Rvalue is void. Uses IsAssignableTest to
// determine the type of IsAssignableImpl.
template <class Lvalue,
class Rvalue,
bool = std::is_void<Lvalue>::value || std::is_void<Rvalue>::value>
struct IsAssignableImpl
: public std::common_type<decltype(
internal::IsAssignableTest(std::declval<Lvalue>(),
std::declval<Rvalue>()))>::type {};
// Void case: Either Lvalue or Rvalue is void. Then the type of IsAssignableTest
// is false_type.
template <class Lvalue, class Rvalue>
struct IsAssignableImpl<Lvalue, Rvalue, true> : public std::false_type {};
// Uses expression SFINAE to detect whether using operator<< would work.
template <typename T, typename = void>
struct SupportsOstreamOperator : std::false_type {};
template <typename T>
struct SupportsOstreamOperator<T,
decltype(void(std::declval<std::ostream&>()
<< std::declval<T>()))>
: std::true_type {};
} // namespace internal
// Inherits from true_type if From is convertible to To, false_type otherwise.
//
// Note that if the type is convertible, this will be a true_type REGARDLESS
// of whether or not the conversion would emit a warning.
template <typename From, typename To>
struct is_convertible
: integral_constant<bool,
sizeof(internal::ConvertHelper::Test<To>(
internal::ConvertHelper::Create<From>())) ==
sizeof(internal::YesType)> {
// TODO(crbug.com/554293): Remove this when all platforms have this in the std
// namespace.
template <class Lvalue, class Rvalue>
struct is_assignable : public internal::IsAssignableImpl<Lvalue, Rvalue> {};
// is_copy_assignable is true if a T const& is assignable to a T&.
// TODO(crbug.com/554293): Remove this when all platforms have this in the std
// namespace.
template <class T>
struct is_copy_assignable
: public is_assignable<typename std::add_lvalue_reference<T>::type,
typename std::add_lvalue_reference<
typename std::add_const<T>::type>::type> {};
// is_move_assignable is true if a T&& is assignable to a T&.
// TODO(crbug.com/554293): Remove this when all platforms have this in the std
// namespace.
template <class T>
struct is_move_assignable
: public is_assignable<typename std::add_lvalue_reference<T>::type,
const typename std::add_rvalue_reference<T>::type> {
};
// underlying_type produces the integer type backing an enum type.
// TODO(crbug.com/554293): Remove this when all platforms have this in the std
// namespace.
#if defined(CR_USE_FALLBACKS_FOR_OLD_GLIBCXX)
template <typename T>
struct is_class
: integral_constant<bool,
sizeof(internal::IsClassHelper::Test<T>(0)) ==
sizeof(internal::YesType)> {
struct underlying_type {
using type = __underlying_type(T);
};
#else
template <typename T>
using underlying_type = std::underlying_type<T>;
#endif
// TODO(crbug.com/554293): Remove this when all platforms have this in the std
// namespace.
#if defined(CR_USE_FALLBACKS_FOR_OLD_GLIBCXX)
template <class T>
using is_trivially_destructible = std::has_trivial_destructor<T>;
#else
template <class T>
using is_trivially_destructible = std::is_trivially_destructible<T>;
#endif
} // namespace base
#undef CR_USE_FALLBACKS_FOR_OLD_GLIBCXX
#endif // BASE_TEMPLATE_UTIL_H_

View File

@ -32,6 +32,7 @@
*/
/* strtod for IEEE-, VAX-, and IBM-arithmetic machines.
* (Note that IEEE arithmetic is disabled by gcc's -ffast-math flag.)
*
* This strtod returns a nearest machine number to the input decimal
* string (or sets errno to ERANGE). With IEEE arithmetic, ties are
@ -70,7 +71,8 @@
* #define IBM for IBM mainframe-style floating-point arithmetic.
* #define VAX for VAX-style floating-point arithmetic (D_floating).
* #define No_leftright to omit left-right logic in fast floating-point
* computation of dtoa.
* computation of dtoa. This will cause dtoa modes 4 and 5 to be
* treated the same as modes 2 and 3 for some inputs.
* #define Honor_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3
* and strtod and dtoa should round accordingly. Unless Trust_FLT_ROUNDS
* is also #defined, fegetround() will be queried for the rounding mode.
@ -78,13 +80,18 @@
* standard (and are specified to be consistent, with fesetround()
* affecting the value of FLT_ROUNDS), but that some (Linux) systems
* do not work correctly in this regard, so using fegetround() is more
* portable than using FLT_FOUNDS directly.
* portable than using FLT_ROUNDS directly.
* #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3
* and Honor_FLT_ROUNDS is not #defined.
* #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines
* that use extended-precision instructions to compute rounded
* products and quotients) with IBM.
* #define ROUND_BIASED for IEEE-format with biased rounding.
* #define ROUND_BIASED for IEEE-format with biased rounding and arithmetic
* that rounds toward +Infinity.
* #define ROUND_BIASED_without_Round_Up for IEEE-format with biased
* rounding when the underlying floating-point arithmetic uses
* unbiased rounding. This prevent using ordinary floating-point
* arithmetic when the result could be computed with one rounding error.
* #define Inaccurate_Divide for IEEE-format with correctly rounded
* products but inaccurate quotients, e.g., for Intel i860.
* #define NO_LONG_LONG on machines that do not have a "long long"
@ -458,6 +465,11 @@ extern int strtod_diglim;
#ifndef IEEE_Arith
#define ROUND_BIASED
#else
#ifdef ROUND_BIASED_without_Round_Up
#undef ROUND_BIASED
#define ROUND_BIASED
#endif
#endif
#ifdef RND_PRODQUOT
@ -663,7 +675,7 @@ s2b
#ifdef KR_headers
(s, nd0, nd, y9, dplen) CONST char *s; int nd0, nd, dplen; ULong y9;
#else
(CONST char *s, int nd0, int nd, ULong y9, int dplen)
(const char *s, int nd0, int nd, ULong y9, int dplen)
#endif
{
Bigint *b;
@ -1500,14 +1512,11 @@ static CONST double tinytens[] = { 1e-16, 1e-32 };
#endif
#ifdef Need_Hexdig /*{*/
#if 0
static unsigned char hexdig[256];
static void
#ifdef KR_headers
htinit(h, s, inc) unsigned char *h; unsigned char *s; int inc;
#else
htinit(unsigned char *h, unsigned char *s, int inc)
#endif
{
int i, j;
for(i = 0; (j = s[i]) !=0; i++)
@ -1515,17 +1524,34 @@ htinit(unsigned char *h, unsigned char *s, int inc)
}
static void
#ifdef KR_headers
hexdig_init()
#else
hexdig_init(void)
#endif
hexdig_init(void) /* Use of hexdig_init omitted 20121220 to avoid a */
/* race condition when multiple threads are used. */
{
#define USC (unsigned char *)
htinit(hexdig, USC "0123456789", 0x10);
htinit(hexdig, USC "abcdef", 0x10 + 10);
htinit(hexdig, USC "ABCDEF", 0x10 + 10);
}
#else
static const unsigned char hexdig[256] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
16,17,18,19,20,21,22,23,24,25,0,0,0,0,0,0,
0,26,27,28,29,30,31,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,26,27,28,29,30,31,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};
#endif
#endif /* } Need_Hexdig */
#ifdef INFNAN_CHECK
@ -1543,7 +1569,7 @@ match
#ifdef KR_headers
(sp, t) char **sp, *t;
#else
(CONST char **sp, CONST char *t)
(const char **sp, const char *t)
#endif
{
int c, d;
@ -1565,15 +1591,14 @@ hexnan
#ifdef KR_headers
(rvp, sp) U *rvp; CONST char **sp;
#else
(U *rvp, CONST char **sp)
(U *rvp, const char **sp)
#endif
{
ULong c, x[2];
CONST char *s;
int c1, havedig, udx0, xshift;
if (!hexdig['0'])
hexdig_init();
/**** if (!hexdig['0']) hexdig_init(); ****/
x[0] = x[1] = 0;
havedig = xshift = 0;
udx0 = 1;
@ -1640,6 +1665,41 @@ hexnan
#define kshift 4
#define kmask 15
#endif
#if !defined(NO_HEX_FP) || defined(Honor_FLT_ROUNDS) /*{*/
static Bigint *
#ifdef KR_headers
increment(b) Bigint *b;
#else
increment(Bigint *b)
#endif
{
ULong *x, *xe;
Bigint *b1;
x = b->x;
xe = x + b->wds;
do {
if (*x < (ULong)0xffffffffL) {
++*x;
return b;
}
*x++ = 0;
} while(x < xe);
{
if (b->wds >= b->maxwds) {
b1 = Balloc(b->k+1);
Bcopy(b1,b);
Bfree(b);
b = b1;
}
b->x[b->wds++] = 1;
}
return b;
}
#endif /*}*/
#ifndef NO_HEX_FP /*{*/
static void
@ -1712,37 +1772,6 @@ enum { /* rounding values: same as FLT_ROUNDS */
Round_down = 3
};
static Bigint *
#ifdef KR_headers
increment(b) Bigint *b;
#else
increment(Bigint *b)
#endif
{
ULong *x, *xe;
Bigint *b1;
x = b->x;
xe = x + b->wds;
do {
if (*x < (ULong)0xffffffffL) {
++*x;
return b;
}
*x++ = 0;
} while(x < xe);
{
if (b->wds >= b->maxwds) {
b1 = Balloc(b->k+1);
Bcopy(b1,b);
Bfree(b);
b = b1;
}
b->x[b->wds++] = 1;
}
return b;
}
void
#ifdef KR_headers
gethex(sp, rvp, rounding, sign)
@ -1793,8 +1822,7 @@ gethex( CONST char **sp, U *rvp, int rounding, int sign)
#endif
#endif
if (!hexdig['0'])
hexdig_init();
/**** if (!hexdig['0']) hexdig_init(); ****/
havedig = 0;
s0 = *(CONST unsigned char **)sp + 2;
while(s0[havedig] == '0')
@ -1894,6 +1922,8 @@ gethex( CONST char **sp, U *rvp, int rounding, int sign)
#endif
goto retz;
#ifdef IEEE_Arith
ret_tinyf:
Bfree(b);
ret_tiny:
#ifndef NO_ERRNO
errno = ERANGE;
@ -1994,15 +2024,15 @@ gethex( CONST char **sp, U *rvp, int rounding, int sign)
switch (rounding) {
case Round_near:
if (n == nbits && (n < 2 || any_on(b,n-1)))
goto ret_tiny;
goto ret_tinyf;
break;
case Round_up:
if (!sign)
goto ret_tiny;
goto ret_tinyf;
break;
case Round_down:
if (sign)
goto ret_tiny;
goto ret_tinyf;
}
#endif /* } IEEE_Arith */
Bfree(b);
@ -2102,7 +2132,7 @@ gethex( CONST char **sp, U *rvp, int rounding, int sign)
#endif
Bfree(b);
}
#endif /*}!NO_HEX_FP*/
#endif /*!NO_HEX_FP}*/
static int
#ifdef KR_headers
@ -2149,7 +2179,13 @@ quorem
bxe = bx + n;
q = *bxe / (*sxe + 1); /* ensure q <= true quotient */
#ifdef DEBUG
#ifdef NO_STRTOD_BIGCOMP
/*debug*/ if (q > 9)
#else
/* An oversized q is possible when quorem is called from bigcomp and */
/* the input is near, e.g., twice the smallest denormalized number. */
/*debug*/ if (q > 15)
#endif
/*debug*/ Bug("oversized quotient in quorem");
#endif
if (q) {
@ -2235,15 +2271,36 @@ quorem
return q;
}
#ifndef NO_STRTOD_BIGCOMP
#if defined(Avoid_Underflow) || !defined(NO_STRTOD_BIGCOMP) /*{*/
static double
sulp
#ifdef KR_headers
(x, bc) U *x; BCinfo *bc;
#else
(U *x, BCinfo *bc)
#endif
{
U u;
double rv;
int i;
rv = ulp(x);
if (!bc->scale || (i = 2*P + 1 - ((word0(x) & Exp_mask) >> Exp_shift)) <= 0)
return rv; /* Is there an example where i <= 0 ? */
word0(&u) = Exp_1 + (i << Exp_shift);
word1(&u) = 0;
return rv * u.d;
}
#endif /*}*/
#ifndef NO_STRTOD_BIGCOMP
static void
bigcomp
#ifdef KR_headers
(rv, s0, bc)
U *rv; CONST char *s0; BCinfo *bc;
#else
(U *rv, CONST char *s0, BCinfo *bc)
(U *rv, const char *s0, BCinfo *bc)
#endif
{
Bigint *b, *d;
@ -2375,7 +2432,7 @@ bigcomp
b = multadd(b, 10, 0);
dig = quorem(b,d);
}
if (b->x[0] || b->wds > 1)
if (dig > 0 || b->x[0] || b->wds > 1)
dd = -1;
ret:
Bfree(b);
@ -2398,7 +2455,7 @@ bigcomp
}
if (!dsign)
goto rethi1;
dval(rv) += 2.*ulp(rv);
dval(rv) += 2.*sulp(rv,bc);
}
else {
bc->inexact = 0;
@ -2415,17 +2472,27 @@ bigcomp
else if (dd < 0) {
if (!dsign) /* does not happen for round-near */
retlow1:
dval(rv) -= ulp(rv);
dval(rv) -= sulp(rv,bc);
}
else if (dd > 0) {
if (dsign) {
rethi1:
dval(rv) += ulp(rv);
dval(rv) += sulp(rv,bc);
}
}
else {
/* Exact half-way case: apply round-even rule. */
if (word1(rv) & 1) {
if ((j = ((word0(rv) & Exp_mask) >> Exp_shift) - bc->scale) <= 0) {
i = 1 - j;
if (i <= 31) {
if (word1(rv) & (0x1 << i))
goto odd;
}
else if (word0(rv) & (0x1 << (i-32)))
goto odd;
}
else if (word1(rv) & 1) {
odd:
if (dsign)
goto rethi1;
goto retlow1;
@ -2444,21 +2511,27 @@ strtod
#ifdef KR_headers
(s00, se) CONST char *s00; char **se;
#else
(CONST char *s00, char **se)
(const char *s00, char **se)
#endif
{
int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, e, e1;
int esign, i, j, k, nd, nd0, nf, nz, nz0, sign;
int esign, i, j, k, nd, nd0, nf, nz, nz0, nz1, sign;
CONST char *s, *s0, *s1;
double aadj, aadj1;
Long L;
U aadj2, adj, rv, rv0;
ULong y, z;
BCinfo bc;
Bigint *bb, *bb1, *bd, *bd0, *bs, *delta;
Bigint *bb = nullptr, *bb1, *bd = nullptr, *bd0, *bs = nullptr, *delta = nullptr;
#ifdef Avoid_Underflow
ULong Lsb, Lsb1;
#endif
#ifdef SET_INEXACT
int oldinexact;
#endif
#ifndef NO_STRTOD_BIGCOMP
int req_bigcomp = 0;
#endif
#ifdef Honor_FLT_ROUNDS /*{*/
#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */
bc.rounding = Flt_Rounds;
@ -2475,7 +2548,7 @@ strtod
CONST char *s2;
#endif
sign = nz0 = nz = bc.dplen = bc.uflchk = 0;
sign = nz0 = nz1 = nz = bc.dplen = bc.uflchk = 0;
dval(&rv) = 0.;
for(s = s00;;s++) switch(*s) {
case '-':
@ -2521,10 +2594,12 @@ strtod
for(nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++)
if (nd < 9)
y = 10*y + c - '0';
else if (nd < 16)
else if (nd < DBL_DIG + 2)
z = 10*z + c - '0';
nd0 = nd;
bc.dp0 = bc.dp1 = s - s0;
for(s1 = s; s1 > s0 && *--s1 == '0'; )
++nz1;
#ifdef USE_LOCALE
s1 = localeconv()->decimal_point;
if (c == *s1) {
@ -2552,6 +2627,8 @@ strtod
for(; c == '0'; c = *++s)
nz++;
if (c > '0' && c <= '9') {
bc.dp0 = s0 - s;
bc.dp1 = bc.dp0 + bc.dplen;
s0 = s;
nf += nz;
nz = 0;
@ -2567,13 +2644,13 @@ strtod
for(i = 1; i < nz; i++)
if (nd++ < 9)
y *= 10;
else if (nd <= DBL_DIG + 1)
else if (nd <= DBL_DIG + 2)
z *= 10;
if (nd++ < 9)
y = 10*y + c;
else if (nd <= DBL_DIG + 1)
else if (nd <= DBL_DIG + 2)
z = 10*z + c;
nz = 0;
nz = nz1 = 0;
}
}
}
@ -2597,8 +2674,11 @@ strtod
if (c > '0' && c <= '9') {
L = c - '0';
s1 = s;
while((c = *++s) >= '0' && c <= '9')
L = 10*L + c - '0';
while((c = *++s) >= '0' && c <= '9') {
if (L < (INT_MAX - 10) / 10) {
L = 10*L + (c - '0');
}
}
if (s - s1 > 8 || L > 19999)
/* Avoid confusion from exponents
* so large that e might overflow.
@ -2660,7 +2740,7 @@ strtod
if (!nd0)
nd0 = nd;
k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1;
k = nd < DBL_DIG + 2 ? nd : DBL_DIG + 2;
dval(&rv) = y;
if (k > 9) {
#ifdef SET_INEXACT
@ -2679,6 +2759,7 @@ strtod
) {
if (!e)
goto ret;
#ifndef ROUND_BIASED_without_Round_Up
if (e > 0) {
if (e <= Ten_pmax) {
#ifdef VAX
@ -2739,6 +2820,7 @@ strtod
goto ret;
}
#endif
#endif /* ROUND_BIASED_without_Round_Up */
}
e1 += nd - k;
@ -2771,9 +2853,6 @@ strtod
if (e1 &= ~15) {
if (e1 > DBL_MAX_10_EXP) {
ovfl:
#ifndef NO_ERRNO
errno = ERANGE;
#endif
/* Can't trust HUGE_VAL */
#ifdef IEEE_Arith
#ifdef Honor_FLT_ROUNDS
@ -2800,6 +2879,17 @@ strtod
word0(&rv) = Big0;
word1(&rv) = Big1;
#endif /*IEEE_Arith*/
range_err:
if (bd0) {
Bfree(bb);
Bfree(bd);
Bfree(bs);
Bfree(bd0);
Bfree(delta);
}
#ifndef NO_ERRNO
errno = ERANGE;
#endif
goto ret;
}
e1 >>= 4;
@ -2840,6 +2930,8 @@ strtod
>> Exp_shift)) > 0) {
/* scaled rv is denormal; clear j low bits */
if (j >= 32) {
if (j > 54)
goto undfl;
word1(&rv) = 0;
if (j >= 53)
word0(&rv) = (P+2)*Exp_msk1;
@ -2863,10 +2955,7 @@ strtod
if (!dval(&rv)) {
undfl:
dval(&rv) = 0.;
#ifndef NO_ERRNO
errno = ERANGE;
#endif
goto ret;
goto range_err;
}
#ifndef Avoid_Underflow
word0(&rv) = Tiny0;
@ -2883,7 +2972,7 @@ strtod
/* Put digits into bd: true value = bd * 10^e */
bc.nd = nd;
bc.nd = nd - nz1;
#ifndef NO_STRTOD_BIGCOMP
bc.nd0 = nd0; /* Only needed if nd > strtod_diglim, but done here */
/* to silence an erroneous warning about bc.nd0 */
@ -2896,7 +2985,7 @@ strtod
if (i > nd0)
j += bc.dplen;
for(;;) {
if (--j <= bc.dp1 && j >= bc.dp0)
if (--j < bc.dp1 && j >= bc.dp0)
j = bc.dp0 - 1;
if (s0[j] != '0')
break;
@ -2941,12 +3030,21 @@ strtod
bs2++;
#endif
#ifdef Avoid_Underflow
Lsb = LSB;
Lsb1 = 0;
j = bbe - bc.scale;
i = j + bbbits - 1; /* logb(rv) */
if (i < Emin) /* denormal */
j += P - Emin;
else
j = P + 1 - bbbits;
j = P + 1 - bbbits;
if (i < Emin) { /* denormal */
i = Emin - i;
j -= i;
if (i < 32)
Lsb <<= i;
else if (i < 52)
Lsb1 = Lsb << (i-32);
else
Lsb1 = Exp_mask;
}
#else /*Avoid_Underflow*/
#ifdef Sudden_Underflow
#ifdef IBM
@ -2994,24 +3092,26 @@ strtod
bc.dsign = delta->sign;
delta->sign = 0;
i = cmp(delta, bs);
#ifndef NO_STRTOD_BIGCOMP
#ifndef NO_STRTOD_BIGCOMP /*{*/
if (bc.nd > nd && i <= 0) {
if (bc.dsign)
break; /* Must use bigcomp(). */
if (bc.dsign) {
/* Must use bigcomp(). */
req_bigcomp = 1;
break;
}
#ifdef Honor_FLT_ROUNDS
if (bc.rounding != 1) {
if (i < 0)
if (i < 0) {
req_bigcomp = 1;
break;
}
}
else
#endif
{
bc.nd = nd;
i = -1; /* Discarded digits make delta smaller. */
}
}
#endif
#ifdef Honor_FLT_ROUNDS
#endif /*}*/
#ifdef Honor_FLT_ROUNDS /*{*/
if (bc.rounding != 1) {
if (i < 0) {
/* Error is less than an ulp */
@ -3045,7 +3145,7 @@ strtod
}
}
apply_adj:
#ifdef Avoid_Underflow
#ifdef Avoid_Underflow /*{*/
if (bc.scale && (y = word0(&rv) & Exp_mask)
<= 2*P*Exp_msk1)
word0(&adj) += (2*P+1)*Exp_msk1 - y;
@ -3059,7 +3159,7 @@ strtod
}
else
#endif /*Sudden_Underflow*/
#endif /*Avoid_Underflow*/
#endif /*Avoid_Underflow}*/
dval(&rv) += adj.d*ulp(&rv);
}
break;
@ -3076,7 +3176,7 @@ strtod
adj.d = y;
}
}
#ifdef Avoid_Underflow
#ifdef Avoid_Underflow /*{*/
if (bc.scale && (y = word0(&rv) & Exp_mask) <= 2*P*Exp_msk1)
word0(&adj) += (2*P+1)*Exp_msk1 - y;
#else
@ -3092,7 +3192,7 @@ strtod
goto cont;
}
#endif /*Sudden_Underflow*/
#endif /*Avoid_Underflow*/
#endif /*Avoid_Underflow}*/
adj.d *= ulp(&rv);
if (bc.dsign) {
if (word0(&rv) == Big0 && word1(&rv) == Big1)
@ -3103,20 +3203,20 @@ strtod
dval(&rv) -= adj.d;
goto cont;
}
#endif /*Honor_FLT_ROUNDS*/
#endif /*}Honor_FLT_ROUNDS*/
if (i < 0) {
/* Error is less than half an ulp -- check for
* special case of mantissa a power of two.
*/
if (bc.dsign || word1(&rv) || word0(&rv) & Bndry_mask
#ifdef IEEE_Arith
#ifdef IEEE_Arith /*{*/
#ifdef Avoid_Underflow
|| (word0(&rv) & Exp_mask) <= (2*P+1)*Exp_msk1
#else
|| (word0(&rv) & Exp_mask) <= Exp_msk1
#endif
#endif
#endif /*}*/
) {
#ifdef SET_INEXACT
if (!delta->x[0] && delta->wds <= 1)
@ -3147,6 +3247,8 @@ strtod
#endif
0xffffffff)) {
/*boundary case -- increment exponent*/
if (word0(&rv) == Big0 && word1(&rv) == Big1)
goto ovfl;
word0(&rv) = (word0(&rv) & Exp_mask)
+ Exp_msk1
#ifdef IBM
@ -3207,18 +3309,39 @@ strtod
#ifdef IBM
goto cont;
#else
#ifndef NO_STRTOD_BIGCOMP
if (bc.nd > nd)
goto cont;
#endif
break;
#endif
}
#ifndef ROUND_BIASED
#ifdef Avoid_Underflow
if (Lsb1) {
if (!(word0(&rv) & Lsb1))
break;
}
else if (!(word1(&rv) & Lsb))
break;
#else
if (!(word1(&rv) & LSB))
break;
#endif
#endif
if (bc.dsign)
#ifdef Avoid_Underflow
dval(&rv) += sulp(&rv, &bc);
#else
dval(&rv) += ulp(&rv);
#endif
#ifndef ROUND_BIASED
else {
#ifdef Avoid_Underflow
dval(&rv) -= sulp(&rv, &bc);
#else
dval(&rv) -= ulp(&rv);
#endif
#ifndef Sudden_Underflow
if (!dval(&rv)) {
if (bc.nd >nd) {
@ -3311,9 +3434,22 @@ strtod
dval(&aadj2) = aadj1;
word0(&aadj2) += (2*P+1)*Exp_msk1 - y;
aadj1 = dval(&aadj2);
adj.d = aadj1 * ulp(&rv);
dval(&rv) += adj.d;
if (rv.d == 0.)
#ifdef NO_STRTOD_BIGCOMP
goto undfl;
#else
{
req_bigcomp = 1;
break;
}
#endif
}
else {
adj.d = aadj1 * ulp(&rv);
dval(&rv) += adj.d;
}
adj.d = aadj1 * ulp(&rv);
dval(&rv) += adj.d;
#else
#ifdef Sudden_Underflow
if ((word0(&rv) & Exp_mask) <= P*Exp_msk1) {
@ -3396,8 +3532,16 @@ strtod
Bfree(bd0);
Bfree(delta);
#ifndef NO_STRTOD_BIGCOMP
if (bc.nd > nd)
if (req_bigcomp) {
bd0 = 0;
bc.e0 += nz1;
bigcomp(&rv, s0, &bc);
y = word0(&rv) & Exp_mask;
if (y == Exp_mask)
goto ovfl;
if (y == 0 && rv.d == 0.)
goto undfl;
}
#endif
#ifdef SET_INEXACT
if (bc.inexact) {
@ -3470,7 +3614,7 @@ rv_alloc(int i)
#ifdef KR_headers
nrv_alloc(s, rve, n) char *s, **rve; int n;
#else
nrv_alloc(CONST char *s, char **rve, int n)
nrv_alloc(const char *s, char **rve, int n)
#endif
{
char *rv, *t;
@ -3582,7 +3726,7 @@ dtoa
*/
int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1,
j, j1, k, k0, k_check, leftright, m2, m5, s2, s5,
j, j1 = 0, k, k0, k_check, leftright, m2, m5, s2, s5,
spec_case, try_quick;
Long L;
#ifndef Sudden_Underflow
@ -3593,6 +3737,11 @@ dtoa
U d2, eps, u;
double ds;
char *s, *s0;
#ifndef No_leftright
#ifdef IEEE_Arith
U eps1;
#endif
#endif
#ifdef SET_INEXACT
int inexact, oldinexact;
#endif
@ -3858,14 +4007,26 @@ dtoa
* generating digits needed.
*/
dval(&eps) = 0.5/tens[ilim-1] - dval(&eps);
#ifdef IEEE_Arith
if (k0 < 0 && j1 >= 307) {
eps1.d = 1.01e256; /* 1.01 allows roundoff in the next few lines */
word0(&eps1) -= Exp_msk1 * (Bias+P-1);
dval(&eps1) *= tens[j1 & 0xf];
for(i = 0, j = (j1-256) >> 4; j; j >>= 1, i++)
if (j & 1)
dval(&eps1) *= bigtens[i];
if (eps.d < eps1.d)
eps.d = eps1.d;
}
#endif
for(i = 0;;) {
L = (long)dval(&u);
L = dval(&u);
dval(&u) -= L;
*s++ = '0' + (char)L;
if (dval(&u) < dval(&eps))
goto ret1;
*s++ = '0' + (int)L;
if (1. - dval(&u) < dval(&eps))
goto bump_up;
if (dval(&u) < dval(&eps))
goto ret1;
if (++i >= ilim)
break;
dval(&eps) *= 10.;
@ -3913,7 +4074,7 @@ dtoa
goto no_digits;
goto one_digit;
}
for(i = 1; i <= k + 1; i++, dval(&u) *= 10.) {
for(i = 1;; i++, dval(&u) *= 10.) {
L = (Long)(dval(&u) / ds);
dval(&u) -= L*ds;
#ifdef Check_FLT_ROUNDS
@ -3939,7 +4100,12 @@ dtoa
}
#endif
dval(&u) += dval(&u);
if (dval(&u) > ds || (dval(&u) == ds && L & 1)) {
#ifdef ROUND_BIASED
if (dval(&u) >= ds)
#else
if (dval(&u) > ds || (dval(&u) == ds && L & 1))
#endif
{
bump_up:
while(*--s == '9')
if (s == s0) {
@ -4024,16 +4190,6 @@ dtoa
* and for all and pass them and a shift to quorem, so it
* can do shifts and ors to compute the numerator for q.
*/
#ifdef Pack_32
i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f;
if (i)
i = 32 - i;
#define iInc 28
#else
if (i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf)
i = 16 - i;
#define iInc 12
#endif
i = dshift(S, s2);
b2 += i;
m2 += i;
@ -4126,7 +4282,11 @@ dtoa
if (j1 > 0) {
b = lshift(b, 1);
j1 = cmp(b, S);
#ifdef ROUND_BIASED
if (j1 >= 0 /*)*/
#else
if ((j1 > 0 || (j1 == 0 && dig & 1))
#endif
&& dig++ == '9')
goto round_9_up;
}
@ -4187,7 +4347,12 @@ dtoa
#endif
b = lshift(b, 1);
j = cmp(b, S);
if (j > 0 || (j == 0 && dig & 1)) {
#ifdef ROUND_BIASED
if (j >= 0)
#else
if (j > 0 || (j == 0 && dig & 1))
#endif
{
roundoff:
while(*--s == '9')
if (s == s0) {

View File

@ -99,7 +99,7 @@ const PlatformThreadId kInvalidThreadId(0);
// Valid values for priority of Thread::Options and SimpleThread::Options, and
// SetCurrentThreadPriority(), listed in increasing order of importance.
enum class ThreadPriority {
enum class ThreadPriority : int {
// Suitable for threads that shouldn't disrupt high priority work.
BACKGROUND,
// Default priority level.
@ -142,8 +142,8 @@ class BASE_EXPORT PlatformThread {
// Sleeps for the specified duration.
static void Sleep(base::TimeDelta duration);
// Sets the thread name visible to debuggers/tools. This has no effect
// otherwise.
// Sets the thread name visible to debuggers/tools. This will try to
// initialize the context for current thread unless it's a WorkerThread.
static void SetName(const std::string& name);
// Gets the thread name, if previously set by SetName.
@ -175,14 +175,29 @@ class BASE_EXPORT PlatformThread {
// PlatformThreadHandle.
static bool CreateNonJoinable(size_t stack_size, Delegate* delegate);
// CreateNonJoinableWithPriority() does the same thing as CreateNonJoinable()
// except the priority of the thread is set based on |priority|.
static bool CreateNonJoinableWithPriority(size_t stack_size,
Delegate* delegate,
ThreadPriority priority);
// 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);
// Detaches and releases the thread handle. The thread is no longer joinable
// and |thread_handle| is invalidated after this call.
static void Detach(PlatformThreadHandle thread_handle);
// Returns true if SetCurrentThreadPriority() can be used to increase the
// priority of the current thread.
static bool CanIncreaseCurrentThreadPriority();
// Toggles the current thread's priority at runtime. A thread may not be able
// to raise its priority back up after lowering it if the process does not
// have a proper permission, e.g. CAP_SYS_NICE on Linux.
// have a proper permission, e.g. CAP_SYS_NICE on Linux. A thread may not be
// able to lower its priority back down after raising it to REALTIME_AUDIO.
// Since changing other threads' priority is not permitted in favor of
// security, this interface is restricted to change only the current thread
// priority (https://crbug.com/399473).
@ -190,6 +205,20 @@ class BASE_EXPORT PlatformThread {
static ThreadPriority GetCurrentThreadPriority();
#if defined(OS_LINUX)
// Toggles a specific thread's priority at runtime. This can be used to
// change the priority of a thread in a different process and will fail
// if the calling process does not have proper permissions. The
// SetCurrentThreadPriority() function above is preferred in favor of
// security but on platforms where sandboxed processes are not allowed to
// change priority this function exists to allow a non-sandboxed process
// to change the priority of sandboxed threads for improved performance.
// Warning: Don't use this for a main thread because that will change the
// whole thread group's (i.e. process) priority.
static void SetThreadPriority(PlatformThreadId thread_id,
ThreadPriority priority);
#endif
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(PlatformThread);
};

View File

@ -4,6 +4,7 @@
#include "base/threading/platform_thread_internal_posix.h"
#include "base/containers/adapters.h"
#include "base/logging.h"
namespace base {
@ -11,8 +12,7 @@ namespace base {
namespace internal {
int ThreadPriorityToNiceValue(ThreadPriority priority) {
for (const ThreadPriorityToNiceValuePair& pair :
kThreadPriorityToNiceValueMap) {
for (const auto& pair : kThreadPriorityToNiceValueMap) {
if (pair.priority == priority)
return pair.nice_value;
}
@ -21,13 +21,17 @@ int ThreadPriorityToNiceValue(ThreadPriority priority) {
}
ThreadPriority NiceValueToThreadPriority(int nice_value) {
for (const ThreadPriorityToNiceValuePair& pair :
kThreadPriorityToNiceValueMap) {
if (pair.nice_value == nice_value)
// Try to find a priority that best describes |nice_value|. If there isn't
// an exact match, this method returns the closest priority whose nice value
// is higher (lower priority) than |nice_value|.
for (const auto& pair : Reversed(kThreadPriorityToNiceValueMap)) {
if (pair.nice_value >= nice_value)
return pair.priority;
}
NOTREACHED() << "Unknown nice value";
return ThreadPriority::NORMAL;
// Reaching here means |nice_value| is more than any of the defined
// priorities. The lowest priority is suitable in this case.
return ThreadPriority::BACKGROUND;
}
} // namespace internal

Some files were not shown because too many files have changed in this diff Show More