зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
85b254f54b
Коммит
94bf554716
|
@ -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__
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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"
|
|
@ -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_
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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_
|
|
@ -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_
|
|
@ -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
|
|
@ -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_
|
|
@ -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();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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_
|
|
@ -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:
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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[];
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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_
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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_
|
|
@ -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_
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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_;
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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, \
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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());
|
||||
//
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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_
|
|
@ -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_
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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
|
|
@ -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
|
|
@ -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();
|
||||
|
|
|
@ -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_);
|
||||
|
|
|
@ -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_
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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_
|
|
@ -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_
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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", "",
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()));
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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_;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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_
|
|
@ -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_
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче