Support for Signal calls.

Merge in RedPhone

// FREEBIE
This commit is contained in:
Moxie Marlinspike
2015-09-09 13:54:29 -07:00
parent 3d4ae60d81
commit d83a3d71bc
2585 changed files with 803492 additions and 45 deletions

View File

@@ -0,0 +1,228 @@
# Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
#
# Use of this source code is governed by a BSD-style license
# that can be found in the LICENSE file in the root of the source
# tree. An additional intellectual property rights grant can be found
# in the file PATENTS. All contributing project authors may
# be found in the AUTHORS file in the root of the source tree.
import("//build/config/android/config.gni")
import("../build/webrtc.gni")
config("system_wrappers_inherited_config") {
include_dirs = [
"interface",
]
}
static_library("system_wrappers") {
sources = [
"interface/aligned_malloc.h",
"interface/atomic32.h",
"interface/clock.h",
"interface/compile_assert.h",
"interface/condition_variable_wrapper.h",
"interface/cpu_info.h",
"interface/cpu_features_wrapper.h",
"interface/critical_section_wrapper.h",
"interface/data_log.h",
"interface/data_log_c.h",
"interface/data_log_impl.h",
"interface/event_tracer.h",
"interface/event_wrapper.h",
"interface/field_trial.h",
"interface/file_wrapper.h",
"interface/fix_interlocked_exchange_pointer_win.h",
"interface/logging.h",
"interface/ref_count.h",
"interface/rtp_to_ntp.h",
"interface/rw_lock_wrapper.h",
"interface/scoped_ptr.h",
"interface/scoped_refptr.h",
"interface/scoped_vector.h",
"interface/sleep.h",
"interface/sort.h",
"interface/static_instance.h",
"interface/stl_util.h",
"interface/stringize_macros.h",
"interface/thread_annotations.h",
"interface/thread_wrapper.h",
"interface/tick_util.h",
"interface/timestamp_extrapolator.h",
"interface/trace.h",
"interface/trace_event.h",
"interface/utf_util_win.h",
"source/aligned_malloc.cc",
"source/atomic32_mac.cc",
"source/atomic32_win.cc",
"source/clock.cc",
"source/condition_variable.cc",
"source/condition_variable_posix.cc",
"source/condition_variable_posix.h",
"source/condition_variable_event_win.cc",
"source/condition_variable_event_win.h",
"source/condition_variable_native_win.cc",
"source/condition_variable_native_win.h",
"source/cpu_info.cc",
"source/cpu_features.cc",
"source/critical_section.cc",
"source/critical_section_posix.cc",
"source/critical_section_posix.h",
"source/critical_section_win.cc",
"source/critical_section_win.h",
"source/data_log_c.cc",
"source/event.cc",
"source/event_posix.cc",
"source/event_posix.h",
"source/event_tracer.cc",
"source/event_win.cc",
"source/event_win.h",
"source/file_impl.cc",
"source/file_impl.h",
"source/logging.cc",
"source/rtp_to_ntp.cc",
"source/rw_lock.cc",
"source/rw_lock_generic.cc",
"source/rw_lock_generic.h",
"source/rw_lock_posix.cc",
"source/rw_lock_posix.h",
"source/rw_lock_win.cc",
"source/rw_lock_win.h",
"source/set_thread_name_win.h",
"source/sleep.cc",
"source/sort.cc",
"source/tick_util.cc",
"source/thread.cc",
"source/thread_posix.cc",
"source/thread_posix.h",
"source/thread_win.cc",
"source/thread_win.h",
"source/timestamp_extrapolator.cc",
"source/trace_impl.cc",
"source/trace_impl.h",
"source/trace_posix.cc",
"source/trace_posix.h",
"source/trace_win.cc",
"source/trace_win.h",
]
configs += [ "..:common_config" ]
if (is_clang) {
# Suppress warnings from Chrome's Clang plugins.
# See http://code.google.com/p/webrtc/issues/detail?id=163 for details.
configs -= [ "//build/config/clang:find_bad_constructs" ]
}
direct_dependent_configs = [
"..:common_inherited_config",
":system_wrappers_inherited_config",
]
if (enable_data_logging) {
sources += [ "source/data_log.cc" ]
} else {
sources += [ "source/data_log_no_op.cc" ]
}
defines = []
libs = []
deps = []
if (is_android) {
sources += [
"interface/logcat_trace_context.h",
"source/logcat_trace_context.cc",
]
defines += [
"WEBRTC_THREAD_RR",
# TODO(leozwang): Investigate CLOCK_REALTIME and CLOCK_MONOTONIC
# support on Android. Keep WEBRTC_CLOCK_TYPE_REALTIME for now,
# remove it after I verify that CLOCK_MONOTONIC is fully functional
# with condition and event functions in system_wrappers.
"WEBRTC_CLOCK_TYPE_REALTIME",
]
deps += [ ":cpu_features_android" ]
libs += [ "log" ]
}
if (is_linux) {
defines += [
"WEBRTC_THREAD_RR",
# TODO(andrew): can we select this automatically?
# Define this if the Linux system does not support CLOCK_MONOTONIC.
#"WEBRTC_CLOCK_TYPE_REALTIME",
]
libs += [ "rt" ]
}
if (!is_mac && !is_ios) {
sources += [
"source/atomic32_posix.cc",
]
}
if (is_ios || is_mac) {
defines += [
"WEBRTC_THREAD_RR",
"WEBRTC_CLOCK_TYPE_REALTIME",
]
}
if (is_ios) {
sources += [
"source/atomic32_mac.cc",
]
}
if (is_win) {
libs += [ "winmm.lib" ]
cflags = [
"/wd4267", # size_t to int truncation.
"/wd4334", # Ignore warning on shift operator promotion.
]
}
include_dirs = [
"source/spreadsortlib",
]
deps += [
"../base:webrtc_base",
]
}
source_set("field_trial_default") {
sources = [
"source/field_trial_default.cc",
]
if (is_clang) {
# Suppress warnings from Chrome's Clang plugins.
# See http://code.google.com/p/webrtc/issues/detail?id=163 for details.
configs -= [ "//build/config/clang:find_bad_constructs" ]
}
deps = [
":system_wrappers",
]
}
if (is_android) {
source_set("cpu_features_android") {
sources = [
"source/cpu_features_android.c",
]
if (is_android_webview_build) {
libs += [ "cpufeatures.a" ]
} else {
deps = [ "//third_party/android_tools:cpu_features" ]
}
}
}

View File

@@ -0,0 +1,8 @@
henrike@webrtc.org
perkj@webrtc.org
henrika@webrtc.org
henrikg@webrtc.org
mflodman@webrtc.org
niklas.enbom@webrtc.org
per-file BUILD.gn=kjellander@webrtc.org

View File

@@ -0,0 +1,59 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_ALIGNED_MALLOC_H_
#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_ALIGNED_MALLOC_H_
// The functions declared here
// 1) Allocates block of aligned memory.
// 2) Re-calculates a pointer such that it is aligned to a higher or equal
// address.
// Note: alignment must be a power of two. The alignment is in bytes.
#include <stddef.h>
namespace webrtc {
// Returns a pointer to the first boundry of |alignment| bytes following the
// address of |ptr|.
// Note that there is no guarantee that the memory in question is available.
// |ptr| has no requirements other than it can't be NULL.
void* GetRightAlign(const void* ptr, size_t alignment);
// Allocates memory of |size| bytes aligned on an |alignment| boundry.
// The return value is a pointer to the memory. Note that the memory must
// be de-allocated using AlignedFree.
void* AlignedMalloc(size_t size, size_t alignment);
// De-allocates memory created using the AlignedMalloc() API.
void AlignedFree(void* mem_block);
// Templated versions to facilitate usage of aligned malloc without casting
// to and from void*.
template<typename T>
T* GetRightAlign(const T* ptr, size_t alignment) {
return reinterpret_cast<T*>(GetRightAlign(reinterpret_cast<const void*>(ptr),
alignment));
}
template<typename T>
T* AlignedMalloc(size_t size, size_t alignment) {
return reinterpret_cast<T*>(AlignedMalloc(size, alignment));
}
// Deleter for use with scoped_ptr. E.g., use as
// scoped_ptr<Foo, AlignedFreeDeleter> foo;
struct AlignedFreeDeleter {
inline void operator()(void* ptr) const {
AlignedFree(ptr);
}
};
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_ALIGNED_MALLOC_H_

View File

@@ -0,0 +1,59 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_ASM_DEFINES_H_
#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_ASM_DEFINES_H_
#if defined(__linux__) && defined(__ELF__)
.section .note.GNU-stack,"",%progbits
#endif
// Define the macros used in ARM assembly code, so that for Mac or iOS builds
// we add leading underscores for the function names.
#ifdef __APPLE__
.macro GLOBAL_FUNCTION name
.global _\name
.endm
.macro DEFINE_FUNCTION name
_\name:
.endm
.macro CALL_FUNCTION name
bl _\name
.endm
.macro GLOBAL_LABEL name
.global _\name
.endm
#else
.macro GLOBAL_FUNCTION name
.global \name
.endm
.macro DEFINE_FUNCTION name
\name:
.endm
.macro CALL_FUNCTION name
bl \name
.endm
.macro GLOBAL_LABEL name
.global \name
.endm
#endif
// With Apple's clang compiler, for instructions ldrb, strh, etc.,
// the condition code is after the width specifier. Here we define
// only the ones that are actually used in the assembly files.
#if (defined __llvm__) && (defined __APPLE__)
.macro streqh reg1, reg2, num
strheq \reg1, \reg2, \num
.endm
#endif
.text
#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_ASM_DEFINES_H_

View File

@@ -0,0 +1,66 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// Atomic, system independent 32-bit integer. Unless you know what you're
// doing, use locks instead! :-)
//
// Note: assumes 32-bit (or higher) system
#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_ATOMIC32_H_
#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_ATOMIC32_H_
#include <stddef.h>
#include "webrtc/base/constructormagic.h"
#include "webrtc/common_types.h"
namespace webrtc {
// 32 bit atomic variable. Note that this class relies on the compiler to
// align the 32 bit value correctly (on a 32 bit boundary), so as long as you're
// not doing things like reinterpret_cast over some custom allocated memory
// without being careful with alignment, you should be fine.
class Atomic32 {
public:
Atomic32(int32_t initial_value = 0);
~Atomic32();
// Prefix operator!
int32_t operator++();
int32_t operator--();
int32_t operator+=(int32_t value);
int32_t operator-=(int32_t value);
// Sets the value atomically to new_value if the value equals compare value.
// The function returns true if the exchange happened.
bool CompareExchange(int32_t new_value, int32_t compare_value);
int32_t Value() {
return *this += 0;
}
private:
// Disable the + and - operator since it's unclear what these operations
// should do.
Atomic32 operator+(const Atomic32& other);
Atomic32 operator-(const Atomic32& other);
// Checks if |_value| is 32bit aligned.
inline bool Is32bitAligned() const {
return (reinterpret_cast<ptrdiff_t>(&value_) & 3) == 0;
}
DISALLOW_COPY_AND_ASSIGN(Atomic32);
int32_t value_;
};
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_ATOMIC32_H_

View File

@@ -0,0 +1,85 @@
/*
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CLOCK_H_
#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CLOCK_H_
#include "webrtc/system_wrappers/interface/rw_lock_wrapper.h"
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
#include "webrtc/typedefs.h"
namespace webrtc {
// January 1970, in NTP seconds.
const uint32_t kNtpJan1970 = 2208988800UL;
// Magic NTP fractional unit.
const double kMagicNtpFractionalUnit = 4.294967296E+9;
// A clock interface that allows reading of absolute and relative timestamps.
class Clock {
public:
virtual ~Clock() {}
// Return a timestamp in milliseconds relative to some arbitrary source; the
// source is fixed for this clock.
virtual int64_t TimeInMilliseconds() const = 0;
// Return a timestamp in microseconds relative to some arbitrary source; the
// source is fixed for this clock.
virtual int64_t TimeInMicroseconds() const = 0;
// Retrieve an NTP absolute timestamp in seconds and fractions of a second.
virtual void CurrentNtp(uint32_t& seconds, uint32_t& fractions) const = 0;
// Retrieve an NTP absolute timestamp in milliseconds.
virtual int64_t CurrentNtpInMilliseconds() const = 0;
// Converts an NTP timestamp to a millisecond timestamp.
static int64_t NtpToMs(uint32_t seconds, uint32_t fractions);
// Returns an instance of the real-time system clock implementation.
static Clock* GetRealTimeClock();
};
class SimulatedClock : public Clock {
public:
explicit SimulatedClock(int64_t initial_time_us);
virtual ~SimulatedClock();
// Return a timestamp in milliseconds relative to some arbitrary source; the
// source is fixed for this clock.
virtual int64_t TimeInMilliseconds() const OVERRIDE;
// Return a timestamp in microseconds relative to some arbitrary source; the
// source is fixed for this clock.
virtual int64_t TimeInMicroseconds() const OVERRIDE;
// Retrieve an NTP absolute timestamp in milliseconds.
virtual void CurrentNtp(uint32_t& seconds,
uint32_t& fractions) const OVERRIDE;
// Converts an NTP timestamp to a millisecond timestamp.
virtual int64_t CurrentNtpInMilliseconds() const OVERRIDE;
// Advance the simulated clock with a given number of milliseconds or
// microseconds.
void AdvanceTimeMilliseconds(int64_t milliseconds);
void AdvanceTimeMicroseconds(int64_t microseconds);
private:
int64_t time_us_;
scoped_ptr<RWLockWrapper> lock_;
};
}; // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CLOCK_H_

View File

@@ -0,0 +1,90 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// Borrowed from Chromium's src/base/macros.h.
#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_COMPILE_ASSERT_H_
#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_COMPILE_ASSERT_H_
// The COMPILE_ASSERT macro can be used to verify that a compile time
// expression is true. For example, you could use it to verify the
// size of a static array:
//
// COMPILE_ASSERT(ARRAYSIZE_UNSAFE(content_type_names) == CONTENT_NUM_TYPES,
// content_type_names_incorrect_size);
//
// or to make sure a struct is smaller than a certain size:
//
// COMPILE_ASSERT(sizeof(foo) < 128, foo_too_large);
//
// The second argument to the macro is the name of the variable. If
// the expression is false, most compilers will issue a warning/error
// containing the name of the variable.
// TODO(ajm): Hack to avoid multiple definitions until the base/ of webrtc and
// libjingle are merged.
#if !defined(COMPILE_ASSERT)
#if __cplusplus >= 201103L
// Under C++11, just use static_assert.
#define COMPILE_ASSERT(expr, msg) static_assert(expr, #msg)
#else
template <bool>
struct CompileAssert {
};
#define COMPILE_ASSERT(expr, msg) \
typedef CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1]
#endif // __cplusplus >= 201103L
#endif // !defined(COMPILE_ASSERT)
// Implementation details of COMPILE_ASSERT:
//
// - COMPILE_ASSERT works by defining an array type that has -1
// elements (and thus is invalid) when the expression is false.
//
// - The simpler definition
//
// #define COMPILE_ASSERT(expr, msg) typedef char msg[(expr) ? 1 : -1]
//
// does not work, as gcc supports variable-length arrays whose sizes
// are determined at run-time (this is gcc's extension and not part
// of the C++ standard). As a result, gcc fails to reject the
// following code with the simple definition:
//
// int foo;
// COMPILE_ASSERT(foo, msg); // not supposed to compile as foo is
// // not a compile-time constant.
//
// - By using the type CompileAssert<(bool(expr))>, we ensures that
// expr is a compile-time constant. (Template arguments must be
// determined at compile-time.)
//
// - The outer parentheses in CompileAssert<(bool(expr))> are necessary
// to work around a bug in gcc 3.4.4 and 4.0.1. If we had written
//
// CompileAssert<bool(expr)>
//
// instead, these compilers will refuse to compile
//
// COMPILE_ASSERT(5 > 0, some_message);
//
// (They seem to think the ">" in "5 > 0" marks the end of the
// template argument list.)
//
// - The array size is (bool(expr) ? 1 : -1), instead of simply
//
// ((expr) ? 1 : -1).
//
// This is to avoid running into a bug in MS VC 7.1, which
// causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1.
#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_COMPILE_ASSERT_H_

View File

@@ -0,0 +1,22 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_COMPILE_ASSERT_H_
#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_COMPILE_ASSERT_H_
// Only use this for C files. For C++, use compile_assert.h.
//
// Use this macro to verify at compile time that certain restrictions are met.
// The argument is the boolean expression to evaluate.
// Example:
// COMPILE_ASSERT(sizeof(foo) < 128);
#define COMPILE_ASSERT(expression) switch (0) {case 0: case expression:;}
#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_COMPILE_ASSERT_H_

View File

@@ -0,0 +1,42 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CONDITION_VARIABLE_WRAPPER_H_
#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CONDITION_VARIABLE_WRAPPER_H_
namespace webrtc {
class CriticalSectionWrapper;
class ConditionVariableWrapper {
public:
// Factory method, constructor disabled.
static ConditionVariableWrapper* CreateConditionVariable();
virtual ~ConditionVariableWrapper() {}
// Calling thread will atomically release crit_sect and wait until next
// some other thread calls Wake() or WakeAll().
virtual void SleepCS(CriticalSectionWrapper& crit_sect) = 0;
// Same as above but with a timeout.
virtual bool SleepCS(CriticalSectionWrapper& crit_sect,
unsigned long max_time_in_ms) = 0;
// Wakes one thread calling SleepCS().
virtual void Wake() = 0;
// Wakes all threads calling SleepCS().
virtual void WakeAll() = 0;
};
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CONDITION_VARIABLE_WRAPPER_H_

View File

@@ -0,0 +1,51 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CPU_FEATURES_WRAPPER_H_
#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CPU_FEATURES_WRAPPER_H_
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
#include "webrtc/typedefs.h"
// List of features in x86.
typedef enum {
kSSE2,
kSSE3
} CPUFeature;
// List of features in ARM.
enum {
kCPUFeatureARMv7 = (1 << 0),
kCPUFeatureVFPv3 = (1 << 1),
kCPUFeatureNEON = (1 << 2),
kCPUFeatureLDREXSTREX = (1 << 3)
};
typedef int (*WebRtc_CPUInfo)(CPUFeature feature);
// Returns true if the CPU supports the feature.
extern WebRtc_CPUInfo WebRtc_GetCPUInfo;
// No CPU feature is available => straight C path.
extern WebRtc_CPUInfo WebRtc_GetCPUInfoNoASM;
// Return the features in an ARM device.
// It detects the features in the hardware platform, and returns supported
// values in the above enum definition as a bitmask.
extern uint64_t WebRtc_GetCPUFeaturesARM(void);
#if defined(__cplusplus) || defined(c_plusplus)
} // extern "C"
#endif
#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CPU_FEATURES_WRAPPER_H_

View File

@@ -0,0 +1,29 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CPU_INFO_H_
#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CPU_INFO_H_
#include "webrtc/typedefs.h"
namespace webrtc {
class CpuInfo {
public:
static uint32_t DetectNumberOfCores();
private:
CpuInfo() {}
static uint32_t number_of_cores_;
};
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CPU_INFO_H_

View File

@@ -0,0 +1,54 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CRITICAL_SECTION_WRAPPER_H_
#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CRITICAL_SECTION_WRAPPER_H_
// If the critical section is heavily contended it may be beneficial to use
// read/write locks instead.
#include "webrtc/common_types.h"
#include "webrtc/system_wrappers/interface/thread_annotations.h"
namespace webrtc {
class LOCKABLE CriticalSectionWrapper {
public:
// Factory method, constructor disabled
static CriticalSectionWrapper* CreateCriticalSection();
virtual ~CriticalSectionWrapper() {}
// Tries to grab lock, beginning of a critical section. Will wait for the
// lock to become available if the grab failed.
virtual void Enter() EXCLUSIVE_LOCK_FUNCTION() = 0;
// Returns a grabbed lock, end of critical section.
virtual void Leave() UNLOCK_FUNCTION() = 0;
};
// RAII extension of the critical section. Prevents Enter/Leave mismatches and
// provides more compact critical section syntax.
class SCOPED_LOCKABLE CriticalSectionScoped {
public:
explicit CriticalSectionScoped(CriticalSectionWrapper* critsec)
EXCLUSIVE_LOCK_FUNCTION(critsec)
: ptr_crit_sec_(critsec) {
ptr_crit_sec_->Enter();
}
~CriticalSectionScoped() UNLOCK_FUNCTION() { ptr_crit_sec_->Leave(); }
private:
CriticalSectionWrapper* ptr_crit_sec_;
};
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CRITICAL_SECTION_WRAPPER_H_

View File

@@ -0,0 +1,119 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// This singleton can be used for logging data for offline processing. Data
// logged with it can conveniently be parsed and processed with e.g. Matlab.
//
// Following is an example of the log file format, starting with the header
// row at line 1, and the data rows following.
// col1,col2,col3,multi-value-col4[3],,,col5
// 123,10.2,-243,1,2,3,100
// 241,12.3,233,1,2,3,200
// 13,16.4,-13,1,2,3,300
//
// As can be seen in the example, a multi-value-column is specified with the
// name followed the number of elements it contains. This followed by
// number of elements - 1 empty columns.
//
// Without multi-value-columns this format can be natively by Matlab. With
// multi-value-columns a small Matlab script is needed, available at
// trunk/tools/matlab/parseLog.m.
//
// Table names and column names are case sensitive.
#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_DATA_LOG_H_
#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_DATA_LOG_H_
#include <string>
#include "webrtc/system_wrappers/interface/data_log_impl.h"
namespace webrtc {
class DataLog {
public:
// Creates a log which uses a separate thread (referred to as the file
// writer thread) for writing log rows to file.
//
// Calls to this function after the log object has been created will only
// increment the reference counter.
static int CreateLog();
// Decrements the reference counter and deletes the log when the counter
// reaches 0. Should be called equal number of times as successful calls to
// CreateLog or memory leak will occur.
static void ReturnLog();
// Combines the string table_name and the integer table_id into a new string
// table_name + _ + table_id. The new string will be lower-case.
static std::string Combine(const std::string& table_name, int table_id);
// Adds a new table, with the name table_name, and creates the file, with the
// name table_name + ".txt", to which the table will be written.
// table_name is treated in a case sensitive way.
static int AddTable(const std::string& table_name);
// Adds a new column to a table. The column will be a multi-value-column
// if multi_value_length is greater than 1.
// table_name and column_name are treated in a case sensitive way.
static int AddColumn(const std::string& table_name,
const std::string& column_name,
int multi_value_length);
// Inserts a single value into a table with name table_name at the column with
// name column_name.
// Note that the ValueContainer makes use of the copy constructor,
// operator= and operator<< of the type T, and that the template type must
// implement a deep copy copy constructor and operator=.
// Copy constructor and operator= must not be disabled for the type T.
// table_name and column_name are treated in a case sensitive way.
template<class T>
static int InsertCell(const std::string& table_name,
const std::string& column_name,
T value) {
DataLogImpl* data_log = DataLogImpl::StaticInstance();
if (data_log == NULL)
return -1;
return data_log->InsertCell(
table_name,
column_name,
new ValueContainer<T>(value));
}
// Inserts an array of values into a table with name table_name at the
// column specified by column_name, which must be a multi-value-column.
// Note that the MultiValueContainer makes use of the copy constructor,
// operator= and operator<< of the type T, and that the template type
// must implement a deep copy copy constructor and operator=.
// Copy constructor and operator= must not be disabled for the type T.
// table_name and column_name are treated in a case sensitive way.
template<class T>
static int InsertCell(const std::string& table_name,
const std::string& column_name,
const T* array,
int length) {
DataLogImpl* data_log = DataLogImpl::StaticInstance();
if (data_log == NULL)
return -1;
return data_log->InsertCell(
table_name,
column_name,
new MultiValueContainer<T>(array, length));
}
// For the table with name table_name: Writes the current row to file.
// Starts a new empty row.
// table_name is treated in a case-sensitive way.
static int NextRow(const std::string& table_name);
};
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_DATA_LOG_H_

View File

@@ -0,0 +1,85 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// This is a pure C wrapper of the DataLog class. The functions are directly
// mapped here except for InsertCell as C does not support templates.
// See data_log.h for a description of the functions.
#ifndef SRC_SYSTEM_WRAPPERS_INTERFACE_DATA_LOG_C_H_
#define SRC_SYSTEM_WRAPPERS_INTERFACE_DATA_LOG_C_H_
#include <stddef.h> // size_t
#include "webrtc/typedefs.h"
#ifdef __cplusplus
extern "C" {
#endif
// All char* parameters in this file are expected to be null-terminated
// character sequences.
int WebRtcDataLog_CreateLog();
void WebRtcDataLog_ReturnLog();
char* WebRtcDataLog_Combine(char* combined_name, size_t combined_len,
const char* table_name, int table_id);
int WebRtcDataLog_AddTable(const char* table_name);
int WebRtcDataLog_AddColumn(const char* table_name, const char* column_name,
int multi_value_length);
int WebRtcDataLog_InsertCell_int(const char* table_name,
const char* column_name,
int value);
int WebRtcDataLog_InsertArray_int(const char* table_name,
const char* column_name,
const int* values,
int length);
int WebRtcDataLog_InsertCell_float(const char* table_name,
const char* column_name,
float value);
int WebRtcDataLog_InsertArray_float(const char* table_name,
const char* column_name,
const float* values,
int length);
int WebRtcDataLog_InsertCell_double(const char* table_name,
const char* column_name,
double value);
int WebRtcDataLog_InsertArray_double(const char* table_name,
const char* column_name,
const double* values,
int length);
int WebRtcDataLog_InsertCell_int32(const char* table_name,
const char* column_name,
int32_t value);
int WebRtcDataLog_InsertArray_int32(const char* table_name,
const char* column_name,
const int32_t* values,
int length);
int WebRtcDataLog_InsertCell_uint32(const char* table_name,
const char* column_name,
uint32_t value);
int WebRtcDataLog_InsertArray_uint32(const char* table_name,
const char* column_name,
const uint32_t* values,
int length);
int WebRtcDataLog_InsertCell_int64(const char* table_name,
const char* column_name,
int64_t value);
int WebRtcDataLog_InsertArray_int64(const char* table_name,
const char* column_name,
const int64_t* values,
int length);
int WebRtcDataLog_NextRow(const char* table_name);
#ifdef __cplusplus
} // end of extern "C"
#endif
#endif // SRC_SYSTEM_WRAPPERS_INTERFACE_DATA_LOG_C_H_ // NOLINT

View File

@@ -0,0 +1,155 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// This file contains the helper classes for the DataLog APIs. See data_log.h
// for the APIs.
//
// These classes are helper classes used for logging data for offline
// processing. Data logged with these classes can conveniently be parsed and
// processed with e.g. Matlab.
#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_DATA_LOG_IMPL_H_
#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_DATA_LOG_IMPL_H_
#include <map>
#include <sstream>
#include <string>
#include <vector>
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
#include "webrtc/typedefs.h"
namespace webrtc {
class CriticalSectionWrapper;
class EventWrapper;
class LogTable;
class RWLockWrapper;
class ThreadWrapper;
// All container classes need to implement a ToString-function to be
// writable to file. Enforce this via the Container interface.
class Container {
public:
virtual ~Container() {}
virtual void ToString(std::string* container_string) const = 0;
};
template<class T>
class ValueContainer : public Container {
public:
explicit ValueContainer(T data) : data_(data) {}
virtual void ToString(std::string* container_string) const {
*container_string = "";
std::stringstream ss;
ss << data_ << ",";
ss >> *container_string;
}
private:
T data_;
};
template<class T>
class MultiValueContainer : public Container {
public:
MultiValueContainer(const T* data, int length)
: data_(data, data + length) {
}
virtual void ToString(std::string* container_string) const {
*container_string = "";
std::stringstream ss;
for (size_t i = 0; i < data_.size(); ++i)
ss << data_[i] << ",";
*container_string += ss.str();
}
private:
std::vector<T> data_;
};
class DataLogImpl {
public:
~DataLogImpl();
// The implementation of the CreateLog() method declared in data_log.h.
// See data_log.h for a description.
static int CreateLog();
// The implementation of the StaticInstance() method declared in data_log.h.
// See data_log.h for a description.
static DataLogImpl* StaticInstance();
// The implementation of the ReturnLog() method declared in data_log.h. See
// data_log.h for a description.
static void ReturnLog();
// The implementation of the AddTable() method declared in data_log.h. See
// data_log.h for a description.
int AddTable(const std::string& table_name);
// The implementation of the AddColumn() method declared in data_log.h. See
// data_log.h for a description.
int AddColumn(const std::string& table_name,
const std::string& column_name,
int multi_value_length);
// Inserts a Container into a table with name table_name at the column
// with name column_name.
// column_name is treated in a case sensitive way.
int InsertCell(const std::string& table_name,
const std::string& column_name,
const Container* value_container);
// The implementation of the NextRow() method declared in data_log.h. See
// data_log.h for a description.
int NextRow(const std::string& table_name);
private:
DataLogImpl();
// Initializes the DataLogImpl object, allocates and starts the
// thread file_writer_thread_.
int Init();
// Write all complete rows in every table to file.
// This function should only be called by the file_writer_thread_ if that
// thread is running to avoid race conditions.
void Flush();
// Run() is called by the thread file_writer_thread_.
static bool Run(void* obj);
// This function writes data to file. Note, it blocks if there is no data
// that should be written to file availble. Flush is the non-blocking
// version of this function.
void Process();
// Stops the continuous calling of Process().
void StopThread();
// Collection of tables indexed by the table name as std::string.
typedef std::map<std::string, LogTable*> TableMap;
typedef webrtc::scoped_ptr<CriticalSectionWrapper> CritSectScopedPtr;
static CritSectScopedPtr crit_sect_;
static DataLogImpl* instance_;
int counter_;
TableMap tables_;
EventWrapper* flush_event_;
ThreadWrapper* file_writer_thread_;
RWLockWrapper* tables_lock_;
};
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_DATA_LOG_IMPL_H_

View File

@@ -0,0 +1,73 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// This file defines the interface for event tracing in WebRTC.
//
// Event log handlers are set through SetupEventTracer(). User of this API will
// provide two function pointers to handle event tracing calls.
//
// * GetCategoryEnabledPtr
// Event tracing system calls this function to determine if a particular
// event category is enabled.
//
// * AddTraceEventPtr
// Adds a tracing event. It is the user's responsibility to log the data
// provided.
//
// Parameters for the above two functions are described in trace_event.h.
#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_EVENT_TRACER_H_
#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_EVENT_TRACER_H_
#include "webrtc/common_types.h"
namespace webrtc {
typedef const unsigned char* (*GetCategoryEnabledPtr)(const char* name);
typedef void (*AddTraceEventPtr)(char phase,
const unsigned char* category_enabled,
const char* name,
unsigned long long id,
int num_args,
const char** arg_names,
const unsigned char* arg_types,
const unsigned long long* arg_values,
unsigned char flags);
// User of WebRTC can call this method to setup event tracing.
//
// This method must be called before any WebRTC methods. Functions
// provided should be thread-safe.
WEBRTC_DLLEXPORT void SetupEventTracer(
GetCategoryEnabledPtr get_category_enabled_ptr,
AddTraceEventPtr add_trace_event_ptr);
// This class defines interface for the event tracing system to call
// internally. Do not call these methods directly.
class EventTracer {
public:
static const unsigned char* GetCategoryEnabled(
const char* name);
static void AddTraceEvent(
char phase,
const unsigned char* category_enabled,
const char* name,
unsigned long long id,
int num_args,
const char** arg_names,
const unsigned char* arg_types,
const unsigned long long* arg_values,
unsigned char flags);
};
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_EVENT_TRACER_H_

View File

@@ -0,0 +1,60 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_EVENT_WRAPPER_H_
#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_EVENT_WRAPPER_H_
namespace webrtc {
enum EventTypeWrapper {
kEventSignaled = 1,
kEventError = 2,
kEventTimeout = 3
};
#define WEBRTC_EVENT_10_SEC 10000
#define WEBRTC_EVENT_INFINITE 0xffffffff
class EventWrapper {
public:
// Factory method. Constructor disabled.
static EventWrapper* Create();
virtual ~EventWrapper() {}
// Releases threads who are calling Wait() and has started waiting. Please
// note that a thread calling Wait() will not start waiting immediately.
// assumptions to the contrary is a very common source of issues in
// multithreaded programming.
// Set is sticky in the sense that it will release at least one thread
// either immediately or some time in the future.
virtual bool Set() = 0;
// Prevents future Wait() calls from finishing without a new Set() call.
virtual bool Reset() = 0;
// Puts the calling thread into a wait state. The thread may be released
// by a Set() call depending on if other threads are waiting and if so on
// timing. The thread that was released will call Reset() before leaving
// preventing more threads from being released. If multiple threads
// are waiting for the same Set(), only one (random) thread is guaranteed to
// be released. It is possible that multiple (random) threads are released
// Depending on timing.
virtual EventTypeWrapper Wait(unsigned long max_time) = 0;
// Starts a timer that will call a non-sticky version of Set() either once
// or periodically. If the timer is periodic it ensures that there is no
// drift over time relative to the system clock.
virtual bool StartTimer(bool periodic, unsigned long time) = 0;
virtual bool StopTimer() = 0;
};
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_EVENT_WRAPPER_H_

View File

@@ -0,0 +1,70 @@
//
// Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
//
#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_FIELD_TRIAL_H_
#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_FIELD_TRIAL_H_
#include <string>
#include "webrtc/common_types.h"
// Field trials allow webrtc clients (such as Chrome) to turn on feature code
// in binaries out in the field and gather information with that.
//
// WebRTC clients MUST provide an implementation of:
//
// std::string webrtc::field_trial::FindFullName(const std::string& trial).
//
// Or link with a default one provided in:
//
// system_wrappers/source/system_wrappers.gyp:field_trial_default
//
//
// They are designed to wire up directly to chrome field trials and to speed up
// developers by reducing the need to wire APIs to control whether a feature is
// on/off. E.g. to experiment with a new method that could lead to a different
// trade-off between CPU/bandwidth:
//
// 1 - Develop the feature with default behaviour off:
//
// if (FieldTrial::FindFullName("WebRTCExperimenMethod2") == "Enabled")
// method2();
// else
// method1();
//
// 2 - Once the changes are rolled to chrome, the new code path can be
// controlled as normal chrome field trials.
//
// 3 - Evaluate the new feature and clean the code paths.
//
// Notes:
// - NOT every feature is a candidate to be controlled by this mechanism as
// it may require negotation between involved parties (e.g. SDP).
//
// TODO(andresp): since chrome --force-fieldtrials does not marks the trial
// as active it does not gets propaged to renderer process. For now one
// needs to push a config with start_active:true or run a local finch
// server.
//
// TODO(andresp): find out how to get bots to run tests with trials enabled.
namespace webrtc {
namespace field_trial {
// Returns the group name chosen for the named trial, or the empty string
// if the trial does not exists.
//
// Note: To keep things tidy append all the trial names with WebRTC.
std::string FindFullName(const std::string& name);
} // namespace field_trial
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_FIELD_TRIAL_H_

View File

@@ -0,0 +1,87 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_FILE_WRAPPER_H_
#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_FILE_WRAPPER_H_
#include <stddef.h>
#include <stdio.h>
#include "webrtc/common_types.h"
#include "webrtc/typedefs.h"
// Implementation of an InStream and OutStream that can read (exclusive) or
// write from/to a file.
namespace webrtc {
class FileWrapper : public InStream, public OutStream {
public:
static const size_t kMaxFileNameSize = 1024;
// Factory method. Constructor disabled.
static FileWrapper* Create();
// Returns true if a file has been opened.
virtual bool Open() const = 0;
// Opens a file in read or write mode, decided by the read_only parameter.
virtual int OpenFile(const char* file_name_utf8,
bool read_only,
bool loop = false,
bool text = false) = 0;
// Initializes the wrapper from an existing handle. |read_only| must match in
// the mode the file was opened in. If |manage_file| is true, the wrapper
// takes ownership of |handle| and closes it in CloseFile().
virtual int OpenFromFileHandle(FILE* handle,
bool manage_file,
bool read_only,
bool loop = false) = 0;
virtual int CloseFile() = 0;
// Limits the file size to |bytes|. Writing will fail after the cap
// is hit. Pass zero to use an unlimited size.
virtual int SetMaxFileSize(size_t bytes) = 0;
// Flush any pending writes.
virtual int Flush() = 0;
// Returns the opened file's name in |file_name_utf8|. Provide the size of
// the buffer in bytes in |size|. The name will be truncated if |size| is
// too small.
virtual int FileName(char* file_name_utf8,
size_t size) const = 0;
// Write |format| to the opened file. Arguments are taken in the same manner
// as printf. That is, supply a format string containing text and
// specifiers. Returns the number of characters written or -1 on error.
virtual int WriteText(const char* format, ...) = 0;
// Inherited from Instream.
// Reads |length| bytes from file to |buf|. Returns the number of bytes read
// or -1 on error.
virtual int Read(void* buf, int length) = 0;
// Inherited from OutStream.
// Writes |length| bytes from |buf| to file. The actual writing may happen
// some time later. Call Flush() to force a write.
virtual bool Write(const void* buf, int length) = 0;
// Inherited from both Instream and OutStream.
// Rewinds the file to the start. Only available when OpenFile() has been
// called with |loop| == true or |readOnly| == true.
virtual int Rewind() = 0;
};
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_FILE_WRAPPER_H_

View File

@@ -0,0 +1,39 @@
/*
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// Various inline functions and macros to fix compilation of 32 bit target
// on MSVC with /Wp64 flag enabled.
// The original code can be found here:
// http://src.chromium.org/svn/trunk/src/base/fix_wp64.h
#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_FIX_INTERLOCKED_EXCHANGE_POINTER_WINDOWS_H_
#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_FIX_INTERLOCKED_EXCHANGE_POINTER_WINDOWS_H_
#include <windows.h>
// Platform SDK fixes when building with /Wp64 for a 32 bits target.
#if !defined(_WIN64) && defined(_Wp64)
#ifdef InterlockedExchangePointer
#undef InterlockedExchangePointer
// The problem is that the macro provided for InterlockedExchangePointer() is
// doing a (LONG) C-style cast that triggers invariably the warning C4312 when
// building on 32 bits.
inline void* InterlockedExchangePointer(void* volatile* target, void* value) {
return reinterpret_cast<void*>(static_cast<LONG_PTR>(InterlockedExchange(
reinterpret_cast<volatile LONG*>(target),
static_cast<LONG>(reinterpret_cast<LONG_PTR>(value)))));
}
#endif // #ifdef InterlockedExchangePointer
#endif // #if !defined(_WIN64) && defined(_Wp64)
#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_FIX_INTERLOCKED_EXCHANGE_POINTER_WINDOWS_H_

View File

@@ -0,0 +1,35 @@
/*
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_LOGCAT_TRACE_CONTEXT_H_
#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_LOGCAT_TRACE_CONTEXT_H_
#include "webrtc/system_wrappers/interface/trace.h"
#ifndef ANDROID
#error This file only makes sense to include on Android!
#endif
namespace webrtc {
// Scoped helper class for directing Traces to Android's logcat facility. While
// this object lives, Trace output will be sent to logcat.
class LogcatTraceContext : public webrtc::TraceCallback {
public:
LogcatTraceContext();
virtual ~LogcatTraceContext();
// TraceCallback impl.
virtual void Print(TraceLevel level, const char* message, int length);
};
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_LOGCAT_TRACE_CONTEXT_H_

View File

@@ -0,0 +1,161 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// This is a highly stripped-down version of libjingle's talk/base/logging.h.
// It is a thin wrapper around WEBRTC_TRACE, maintaining the libjingle log
// semantics to ease a transition to that format.
// NOTE: LS_INFO maps to a new trace level which should be reserved for
// infrequent, non-verbose logs. The other levels below kTraceWarning have been
// rendered essentially useless due to their verbosity. Carefully consider the
// impact of adding a new LS_INFO log. If it will be logged at anything
// approaching a frame or packet frequency, use LS_VERBOSE if necessary, or
// preferably, do not log at all.
// LOG(...) an ostream target that can be used to send formatted
// output to a variety of logging targets, such as debugger console, stderr,
// file, or any StreamInterface.
// The severity level passed as the first argument to the LOGging
// functions is used as a filter, to limit the verbosity of the logging.
// Static members of LogMessage documented below are used to control the
// verbosity and target of the output.
// There are several variations on the LOG macro which facilitate logging
// of common error conditions, detailed below.
// LOG(sev) logs the given stream at severity "sev", which must be a
// compile-time constant of the LoggingSeverity type, without the namespace
// prefix.
// LOG_V(sev) Like LOG(), but sev is a run-time variable of the LoggingSeverity
// type (basically, it just doesn't prepend the namespace).
// LOG_F(sev) Like LOG(), but includes the name of the current function.
// Additional helper macros added by WebRTC:
// LOG_API is a shortcut for API call logging. Pass in the input parameters of
// the method. For example:
// Foo(int bar, int baz) {
// LOG_API2(bar, baz);
// }
//
// LOG_FERR is a shortcut for logging a failed function call. For example:
// if (!Foo(bar)) {
// LOG_FERR1(LS_WARNING, Foo, bar);
// }
#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_LOGGING_H_
#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_LOGGING_H_
#include <sstream>
namespace webrtc {
//////////////////////////////////////////////////////////////////////
// Note that the non-standard LoggingSeverity aliases exist because they are
// still in broad use. The meanings of the levels are:
// LS_SENSITIVE: Information which should only be logged with the consent
// of the user, due to privacy concerns.
// LS_VERBOSE: This level is for data which we do not want to appear in the
// normal debug log, but should appear in diagnostic logs.
// LS_INFO: Chatty level used in debugging for all sorts of things, the default
// in debug builds.
// LS_WARNING: Something that may warrant investigation.
// LS_ERROR: Something that should not have occurred.
enum LoggingSeverity {
LS_SENSITIVE, LS_VERBOSE, LS_INFO, LS_WARNING, LS_ERROR
};
class LogMessage {
public:
LogMessage(const char* file, int line, LoggingSeverity sev);
~LogMessage();
static bool Loggable(LoggingSeverity sev);
std::ostream& stream() { return print_stream_; }
private:
// The ostream that buffers the formatted message before output
std::ostringstream print_stream_;
// The severity level of this message
LoggingSeverity severity_;
};
//////////////////////////////////////////////////////////////////////
// Macros which automatically disable logging when WEBRTC_LOGGING == 0
//////////////////////////////////////////////////////////////////////
#ifndef LOG
// The following non-obvious technique for implementation of a
// conditional log stream was stolen from google3/base/logging.h.
// This class is used to explicitly ignore values in the conditional
// logging macros. This avoids compiler warnings like "value computed
// is not used" and "statement has no effect".
class LogMessageVoidify {
public:
LogMessageVoidify() { }
// This has to be an operator with a precedence lower than << but
// higher than ?:
void operator&(std::ostream&) { }
};
#if defined(WEBRTC_RESTRICT_LOGGING)
// This should compile away logs matching the following condition.
#define RESTRICT_LOGGING_PRECONDITION(sev) \
sev < webrtc::LS_INFO ? (void) 0 :
#else
#define RESTRICT_LOGGING_PRECONDITION(sev)
#endif
#define LOG_SEVERITY_PRECONDITION(sev) \
RESTRICT_LOGGING_PRECONDITION(sev) !(webrtc::LogMessage::Loggable(sev)) \
? (void) 0 \
: webrtc::LogMessageVoidify() &
#define LOG(sev) \
LOG_SEVERITY_PRECONDITION(webrtc::sev) \
webrtc::LogMessage(__FILE__, __LINE__, webrtc::sev).stream()
// The _V version is for when a variable is passed in. It doesn't do the
// namespace concatination.
#define LOG_V(sev) \
LOG_SEVERITY_PRECONDITION(sev) \
webrtc::LogMessage(__FILE__, __LINE__, sev).stream()
// The _F version prefixes the message with the current function name.
#if (defined(__GNUC__) && defined(_DEBUG)) || defined(WANT_PRETTY_LOG_F)
#define LOG_F(sev) LOG(sev) << __PRETTY_FUNCTION__ << ": "
#else
#define LOG_F(sev) LOG(sev) << __FUNCTION__ << ": "
#endif
#define LOG_API0() LOG_F(LS_VERBOSE)
#define LOG_API1(v1) LOG_API0() << #v1 << "=" << v1
#define LOG_API2(v1, v2) LOG_API1(v1) \
<< ", " << #v2 << "=" << v2
#define LOG_API3(v1, v2, v3) LOG_API2(v1, v2) \
<< ", " << #v3 << "=" << v3
#define LOG_FERR0(sev, func) LOG(sev) << #func << " failed"
#define LOG_FERR1(sev, func, v1) LOG_FERR0(sev, func) \
<< ": " << #v1 << "=" << v1
#define LOG_FERR2(sev, func, v1, v2) LOG_FERR1(sev, func, v1) \
<< ", " << #v2 << "=" << v2
#define LOG_FERR3(sev, func, v1, v2, v3) LOG_FERR2(sev, func, v1, v2) \
<< ", " << #v3 << "=" << v3
#define LOG_FERR4(sev, func, v1, v2, v3, v4) LOG_FERR3(sev, func, v1, v2, v3) \
<< ", " << #v4 << "=" << v4
#endif // LOG
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_LOGGING_H_

View File

@@ -0,0 +1,82 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef SYSTEM_WRAPPERS_INTERFACE_REF_COUNT_H_
#define SYSTEM_WRAPPERS_INTERFACE_REF_COUNT_H_
#include "webrtc/system_wrappers/interface/atomic32.h"
namespace webrtc {
// This class can be used for instantiating
// reference counted objects.
// int32_t AddRef() and int32_t Release().
// Usage:
// RefCountImpl<T>* implementation = new RefCountImpl<T>(p);
//
// Example:
// class MyInterface {
// public:
// virtual void DoSomething() = 0;
// virtual int32_t AddRef() = 0;
// virtual int32_t Release() = 0:
// private:
// virtual ~MyInterface(){};
// }
// class MyImplementation : public MyInterface {
// public:
// virtual DoSomething() { printf("hello"); };
// };
// MyImplementation* CreateMyImplementation() {
// RefCountImpl<MyImplementation>* implementation =
// new RefCountImpl<MyImplementation>();
// return implementation;
// }
template <class T>
class RefCountImpl : public T {
public:
RefCountImpl() : ref_count_(0) {}
template<typename P>
explicit RefCountImpl(P p) : T(p), ref_count_(0) {}
template<typename P1, typename P2>
RefCountImpl(P1 p1, P2 p2) : T(p1, p2), ref_count_(0) {}
template<typename P1, typename P2, typename P3>
RefCountImpl(P1 p1, P2 p2, P3 p3) : T(p1, p2, p3), ref_count_(0) {}
template<typename P1, typename P2, typename P3, typename P4>
RefCountImpl(P1 p1, P2 p2, P3 p3, P4 p4) : T(p1, p2, p3, p4), ref_count_(0) {}
template<typename P1, typename P2, typename P3, typename P4, typename P5>
RefCountImpl(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5)
: T(p1, p2, p3, p4, p5), ref_count_(0) {}
virtual int32_t AddRef() {
return ++ref_count_;
}
virtual int32_t Release() {
int32_t ref_count;
ref_count = --ref_count_;
if (ref_count == 0)
delete this;
return ref_count;
}
protected:
Atomic32 ref_count_;
};
} // namespace webrtc
#endif // SYSTEM_WRAPPERS_INTERFACE_REF_COUNT_H_

View File

@@ -0,0 +1,50 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef SYSTEM_WRAPPERS_INTERFACE_RTP_TO_NTP_H_
#define SYSTEM_WRAPPERS_INTERFACE_RTP_TO_NTP_H_
#include <list>
#include "webrtc/typedefs.h"
namespace webrtc {
struct RtcpMeasurement {
RtcpMeasurement();
RtcpMeasurement(uint32_t ntp_secs, uint32_t ntp_frac, uint32_t timestamp);
uint32_t ntp_secs;
uint32_t ntp_frac;
uint32_t rtp_timestamp;
};
typedef std::list<RtcpMeasurement> RtcpList;
// Updates |rtcp_list| with timestamps from the latest RTCP SR.
// |new_rtcp_sr| will be set to true if these are the timestamps which have
// never be added to |rtcp_list|.
bool UpdateRtcpList(uint32_t ntp_secs,
uint32_t ntp_frac,
uint32_t rtp_timestamp,
RtcpList* rtcp_list,
bool* new_rtcp_sr);
// Converts an RTP timestamp to the NTP domain in milliseconds using two
// (RTP timestamp, NTP timestamp) pairs.
bool RtpToNtpMs(int64_t rtp_timestamp, const RtcpList& rtcp,
int64_t* timestamp_in_ms);
// Returns 1 there has been a forward wrap around, 0 if there has been no wrap
// around and -1 if there has been a backwards wrap around (i.e. reordering).
int CheckForWrapArounds(uint32_t rtp_timestamp, uint32_t rtcp_rtp_timestamp);
} // namespace webrtc
#endif // SYSTEM_WRAPPERS_INTERFACE_RTP_TO_NTP_H_

View File

@@ -0,0 +1,68 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_RW_LOCK_WRAPPER_H_
#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_RW_LOCK_WRAPPER_H_
#include "webrtc/system_wrappers/interface/thread_annotations.h"
// Note, Windows pre-Vista version of RW locks are not supported natively. For
// these OSs regular critical sections have been used to approximate RW lock
// functionality and will therefore have worse performance.
namespace webrtc {
class LOCKABLE RWLockWrapper {
public:
static RWLockWrapper* CreateRWLock();
virtual ~RWLockWrapper() {}
virtual void AcquireLockExclusive() EXCLUSIVE_LOCK_FUNCTION() = 0;
virtual void ReleaseLockExclusive() UNLOCK_FUNCTION() = 0;
virtual void AcquireLockShared() SHARED_LOCK_FUNCTION() = 0;
virtual void ReleaseLockShared() UNLOCK_FUNCTION() = 0;
};
// RAII extensions of the RW lock. Prevents Acquire/Release missmatches and
// provides more compact locking syntax.
class SCOPED_LOCKABLE ReadLockScoped {
public:
ReadLockScoped(RWLockWrapper& rw_lock) SHARED_LOCK_FUNCTION(rw_lock)
: rw_lock_(rw_lock) {
rw_lock_.AcquireLockShared();
}
~ReadLockScoped() UNLOCK_FUNCTION() {
rw_lock_.ReleaseLockShared();
}
private:
RWLockWrapper& rw_lock_;
};
class SCOPED_LOCKABLE WriteLockScoped {
public:
WriteLockScoped(RWLockWrapper& rw_lock) EXCLUSIVE_LOCK_FUNCTION(rw_lock)
: rw_lock_(rw_lock) {
rw_lock_.AcquireLockExclusive();
}
~WriteLockScoped() UNLOCK_FUNCTION() {
rw_lock_.ReleaseLockExclusive();
}
private:
RWLockWrapper& rw_lock_;
};
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_RW_LOCK_WRAPPER_H_

View File

@@ -0,0 +1,566 @@
/*
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// Borrowed from Chromium's src/base/memory/scoped_ptr.h.
// Scopers help you manage ownership of a pointer, helping you easily manage the
// 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 the result of an analogous
// scoper's Pass() function or another function that generates a temporary;
// passing by copy will NOT work. Here is an example using scoped_ptr:
//
// void TakesOwnership(scoped_ptr<Foo> arg) {
// // Do something with arg
// }
// scoped_ptr<Foo> CreateFoo() {
// // No need for calling Pass() because we are constructing a temporary
// // for the return value.
// return scoped_ptr<Foo>(new Foo("new"));
// }
// scoped_ptr<Foo> PassThru(scoped_ptr<Foo> arg) {
// return arg.Pass();
// }
//
// {
// scoped_ptr<Foo> ptr(new Foo("yay")); // ptr manages Foo("yay").
// TakesOwnership(ptr.Pass()); // ptr no longer owns Foo("yay").
// scoped_ptr<Foo> ptr2 = CreateFoo(); // ptr2 owns the return Foo.
// scoped_ptr<Foo> ptr3 = // ptr3 now owns what was in ptr2.
// PassThru(ptr2.Pass()); // ptr2 is correspondingly NULL.
// }
//
// Notice that if you do not call Pass() when returning from PassThru(), or
// when invoking TakesOwnership(), the code will not compile because scopers
// are not copyable; they only implement move semantics which require calling
// the Pass() function to signify a destructive transfer of state. CreateFoo()
// is different though because we are constructing a temporary on the return
// line and thus can avoid needing to call Pass().
//
// Pass() properly handles upcast in initialization, i.e. you can use a
// scoped_ptr<Child> to initialize a scoped_ptr<Parent>:
//
// scoped_ptr<Foo> foo(new Foo());
// scoped_ptr<FooParent> parent(foo.Pass());
//
// PassAs<>() should be used to upcast return value in return statement:
//
// scoped_ptr<Foo> CreateFoo() {
// scoped_ptr<FooChild> result(new FooChild());
// return result.PassAs<Foo>();
// }
//
// Note that PassAs<>() is implemented only for scoped_ptr<T>, but not for
// scoped_ptr<T[]>. This is because casting array pointers may not be safe.
#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_SCOPED_PTR_H_
#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_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 <algorithm> // For std::swap().
#include "webrtc/base/constructormagic.h"
#include "webrtc/system_wrappers/interface/compile_assert.h"
#include "webrtc/system_wrappers/interface/template_util.h"
#include "webrtc/system_wrappers/source/move.h"
#include "webrtc/typedefs.h"
namespace webrtc {
// Function object which deletes its parameter, which must be a pointer.
// If C is an array type, invokes 'delete[]' on the parameter; otherwise,
// invokes 'delete'. The default deleter for scoped_ptr<T>.
template <class T>
struct DefaultDeleter {
DefaultDeleter() {}
template <typename U> DefaultDeleter(const DefaultDeleter<U>& other) {
// IMPLEMENTATION NOTE: C++11 20.7.1.1.2p2 only provides this constructor
// if U* is implicitly convertible to T* and U is not an array type.
//
// Correct implementation should use SFINAE to disable this
// constructor. However, since there are no other 1-argument constructors,
// using a COMPILE_ASSERT() based on is_convertible<> and requiring
// complete types is simpler and will cause compile failures for equivalent
// misuses.
//
// Note, the is_convertible<U*, T*> check also ensures that U is not an
// array. T is guaranteed to be a non-array, so any U* where U is an array
// cannot convert to T*.
enum { T_must_be_complete = sizeof(T) };
enum { U_must_be_complete = sizeof(U) };
COMPILE_ASSERT((webrtc::is_convertible<U*, T*>::value),
U_ptr_must_implicitly_convert_to_T_ptr);
}
inline void operator()(T* ptr) const {
enum { type_must_be_complete = sizeof(T) };
delete ptr;
}
};
// Specialization of DefaultDeleter for array types.
template <class T>
struct DefaultDeleter<T[]> {
inline void operator()(T* ptr) const {
enum { type_must_be_complete = sizeof(T) };
delete[] ptr;
}
private:
// Disable this operator for any U != T because it is undefined to execute
// an array delete when the static type of the array mismatches the dynamic
// type.
//
// References:
// C++98 [expr.delete]p3
// http://cplusplus.github.com/LWG/lwg-defects.html#938
template <typename U> void operator()(U* array) const;
};
template <class T, int n>
struct DefaultDeleter<T[n]> {
// Never allow someone to declare something like scoped_ptr<int[10]>.
COMPILE_ASSERT(sizeof(T) == -1, do_not_use_array_with_size_as_type);
};
// Function object which invokes 'free' on its parameter, which must be
// a pointer. Can be used to store malloc-allocated pointers in scoped_ptr:
//
// scoped_ptr<int, webrtc::FreeDeleter> foo_ptr(
// static_cast<int*>(malloc(sizeof(int))));
struct FreeDeleter {
inline void operator()(void* ptr) const {
free(ptr);
}
};
namespace internal {
// 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 webrtc::subtle::move() and webrtc::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() {
if (data_.ptr != NULL) {
// Not using get_deleter() saves one function call in non-optimized
// builds.
static_cast<D&>(data_)(data_.ptr);
}
}
void reset(T* p) {
// This is a self-reset, which is no longer allowed: http://crbug.com/162971
if (p != NULL && p == data_.ptr)
abort();
// Note that running data_.ptr = p can lead to undefined behavior if
// get_deleter()(get()) deletes this. In order to pevent this, reset()
// should update the stored pointer before deleting its old value.
//
// However, changing reset() to use that behavior may cause current code to
// break in unexpected ways. If the destruction of the owned object
// dereferences the scoped_ptr when it is destroyed by a call to reset(),
// then it will incorrectly dispatch calls to |p| rather than the original
// value of |data_.ptr|.
//
// During the transition period, set the stored pointer to NULL while
// deleting the object. Eventually, this safety check will be removed to
// prevent the scenario initially described from occuring and
// http://crbug.com/176091 can be closed.
T* old = data_.ptr;
data_.ptr = NULL;
if (old != NULL)
static_cast<D&>(data_)(old);
data_.ptr = p;
}
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 = NULL;
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
// 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 NULL 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
// DefaultDeleter, 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 = webrtc::DefaultDeleter<T> >
class scoped_ptr {
WEBRTC_MOVE_ONLY_TYPE_FOR_CPP_03(scoped_ptr, RValue)
public:
// The element and deleter types.
typedef T element_type;
typedef D deleter_type;
// Constructor. Defaults to initializing with NULL.
scoped_ptr() : impl_(NULL) { }
// 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 scoped_ptr rvalue for a
// convertible type and deleter.
//
// IMPLEMENTATION NOTE: C++11 unique_ptr<> keeps this constructor distinct
// from the normal move constructor. By C++11 20.7.1.2.1.21, this constructor
// has different post-conditions if D is a reference type. Since this
// implementation does not support deleters with reference type,
// we do not need a separate move constructor allowing us to avoid one
// use of SFINAE. You only need to care about this if you modify the
// implementation of scoped_ptr.
template <typename U, typename V>
scoped_ptr(scoped_ptr<U, V> other) : impl_(&other.impl_) {
COMPILE_ASSERT(!webrtc::is_array<U>::value, U_cannot_be_an_array);
}
// Constructor. Move constructor for C++03 move emulation of this type.
scoped_ptr(RValue rvalue) : impl_(&rvalue.object->impl_) { }
// operator=. Allows assignment from a scoped_ptr rvalue for a convertible
// type and deleter.
//
// IMPLEMENTATION NOTE: C++11 unique_ptr<> keeps this operator= distinct from
// the normal move assignment operator. By C++11 20.7.1.2.3.4, this templated
// form has different requirements on for move-only Deleters. Since this
// implementation does not support move-only Deleters, we do not need a
// separate move assignment operator allowing us to avoid one use of SFINAE.
// You only need to care about this if you modify the implementation of
// scoped_ptr.
template <typename U, typename V>
scoped_ptr& operator=(scoped_ptr<U, V> rhs) {
COMPILE_ASSERT(!webrtc::is_array<U>::value, U_cannot_be_an_array);
impl_.TakeState(&rhs.impl_);
return *this;
}
// Reset. Deletes the currently owned object, if any.
// Then takes ownership of a new object, if given.
void reset(element_type* p = NULL) { 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() != NULL);
return *impl_.get();
}
element_type* operator->() const {
assert(impl_.get() != NULL);
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 webrtc::internal::scoped_ptr_impl<element_type, deleter_type>
scoped_ptr::*Testable;
public:
operator Testable() const { return impl_.get() ? &scoped_ptr::impl_ : NULL; }
// Comparison operators.
// These return whether two scoped_ptr refer to the same object, not just to
// two different but equal objects.
bool operator==(const element_type* p) const { return impl_.get() == p; }
bool operator!=(const element_type* p) const { return impl_.get() != p; }
// Swap two scoped pointers.
void swap(scoped_ptr& p2) {
impl_.swap(p2.impl_);
}
// Release a pointer.
// The return value is the current pointer held by this object.
// If this object holds a NULL pointer, the return value is NULL.
// After this operation, this object will hold a NULL pointer,
// and will not own the object any more.
element_type* release() WARN_UNUSED_RESULT {
return impl_.release();
}
// C++98 doesn't support functions templates with default parameters which
// makes it hard to write a PassAs() that understands converting the deleter
// while preserving simple calling semantics.
//
// Until there is a use case for PassAs() with custom deleters, just ignore
// the custom deleter.
template <typename PassAsType>
scoped_ptr<PassAsType> PassAs() {
return scoped_ptr<PassAsType>(Pass());
}
private:
// Needed to reach into |impl_| in the constructor.
template <typename U, typename V> friend class scoped_ptr;
webrtc::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);
// Forbid comparison of scoped_ptr types. If U != T, it totally
// doesn't make sense, and if U == T, it still doesn't make sense
// because you should never have the same object owned by two different
// scoped_ptrs.
template <class U> bool operator==(scoped_ptr<U> const& p2) const;
template <class U> bool operator!=(scoped_ptr<U> const& p2) const;
};
template <class T, class D>
class scoped_ptr<T[], D> {
WEBRTC_MOVE_ONLY_TYPE_FOR_CPP_03(scoped_ptr, RValue)
public:
// The element and deleter types.
typedef T element_type;
typedef D deleter_type;
// Constructor. Defaults to initializing with NULL.
scoped_ptr() : impl_(NULL) { }
// 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 NULL, because NULL is an integral expression, not a
// pointer to T. Use the no-argument version instead of explicitly
// passing NULL.
// - 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 implicit_cast<const T*>().
// However, because of the first bullet in this comment, users MUST
// NOT use implicit_cast<Base*>() to upcast the static type of the array.
explicit scoped_ptr(element_type* array) : impl_(array) { }
// Constructor. Move constructor for C++03 move emulation of this type.
scoped_ptr(RValue rvalue) : impl_(&rvalue.object->impl_) { }
// operator=. Move operator= for C++03 move emulation of this type.
scoped_ptr& operator=(RValue rhs) {
impl_.TakeState(&rhs.object->impl_);
return *this;
}
// Reset. Deletes the currently owned array, if any.
// Then takes ownership of a new object, if given.
void reset(element_type* array = NULL) { impl_.reset(array); }
// Accessors to get the owned array.
element_type& operator[](size_t i) const {
assert(impl_.get() != NULL);
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 webrtc::internal::scoped_ptr_impl<element_type, deleter_type>
scoped_ptr::*Testable;
public:
operator Testable() const { return impl_.get() ? &scoped_ptr::impl_ : NULL; }
// Comparison operators.
// These return whether two scoped_ptr refer to the same object, not just to
// two different but equal objects.
bool operator==(element_type* array) const { return impl_.get() == array; }
bool operator!=(element_type* array) const { return impl_.get() != array; }
// Swap two scoped pointers.
void swap(scoped_ptr& p2) {
impl_.swap(p2.impl_);
}
// Release a pointer.
// The return value is the current pointer held by this object.
// If this object holds a NULL pointer, the return value is NULL.
// After this operation, this object will hold a NULL pointer,
// and will not own the object any more.
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.
webrtc::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);
// Forbid comparison of scoped_ptr types. If U != T, it totally
// doesn't make sense, and if U == T, it still doesn't make sense
// because you should never have the same object owned by two different
// scoped_ptrs.
template <class U> bool operator==(scoped_ptr<U> const& p2) const;
template <class U> bool operator!=(scoped_ptr<U> const& p2) const;
};
} // namespace webrtc
// Free functions
template <class T, class D>
void swap(webrtc::scoped_ptr<T, D>& p1, webrtc::scoped_ptr<T, D>& p2) {
p1.swap(p2);
}
template <class T, class D>
bool operator==(T* p1, const webrtc::scoped_ptr<T, D>& p2) {
return p1 == p2.get();
}
template <class T, class D>
bool operator!=(T* p1, const webrtc::scoped_ptr<T, D>& p2) {
return p1 != p2.get();
}
#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_SCOPED_PTR_H_

View File

@@ -0,0 +1,144 @@
/*
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef SYSTEM_WRAPPERS_INTERFACE_SCOPED_REFPTR_H_
#define SYSTEM_WRAPPERS_INTERFACE_SCOPED_REFPTR_H_
#include <stddef.h>
namespace webrtc {
// Extracted from Chromium's src/base/memory/ref_counted.h.
//
// A smart pointer class for reference counted objects. Use this class instead
// of calling AddRef and Release manually on a reference counted object to
// avoid common memory leaks caused by forgetting to Release an object
// reference. Sample usage:
//
// class MyFoo : public RefCounted<MyFoo> {
// ...
// };
//
// void some_function() {
// scoped_refptr<MyFoo> foo = new MyFoo();
// foo->Method(param);
// // |foo| is released when this function returns
// }
//
// void some_other_function() {
// scoped_refptr<MyFoo> foo = new MyFoo();
// ...
// foo = NULL; // explicitly releases |foo|
// ...
// if (foo)
// foo->Method(param);
// }
//
// The above examples show how scoped_refptr<T> acts like a pointer to T.
// Given two scoped_refptr<T> classes, it is also possible to exchange
// references between the two objects, like so:
//
// {
// scoped_refptr<MyFoo> a = new MyFoo();
// scoped_refptr<MyFoo> b;
//
// b.swap(a);
// // now, |b| references the MyFoo object, and |a| references NULL.
// }
//
// To make both |a| and |b| in the above example reference the same MyFoo
// object, simply use the assignment operator:
//
// {
// scoped_refptr<MyFoo> a = new MyFoo();
// scoped_refptr<MyFoo> b;
//
// b = a;
// // now, |a| and |b| each own a reference to the same MyFoo object.
// }
//
template <class T>
class scoped_refptr {
public:
scoped_refptr() : ptr_(NULL) {
}
scoped_refptr(T* p) : ptr_(p) {
if (ptr_)
ptr_->AddRef();
}
scoped_refptr(const scoped_refptr<T>& r) : ptr_(r.ptr_) {
if (ptr_)
ptr_->AddRef();
}
template <typename U>
scoped_refptr(const scoped_refptr<U>& r) : ptr_(r.get()) {
if (ptr_)
ptr_->AddRef();
}
~scoped_refptr() {
if (ptr_)
ptr_->Release();
}
T* get() const { return ptr_; }
operator T*() const { return ptr_; }
T* operator->() const { return ptr_; }
// Release a pointer.
// The return value is the current pointer held by this object.
// If this object holds a NULL pointer, the return value is NULL.
// After this operation, this object will hold a NULL pointer,
// and will not own the object any more.
T* release() {
T* retVal = ptr_;
ptr_ = NULL;
return retVal;
}
scoped_refptr<T>& operator=(T* p) {
// AddRef first so that self assignment should work
if (p)
p->AddRef();
if (ptr_ )
ptr_->Release();
ptr_ = p;
return *this;
}
scoped_refptr<T>& operator=(const scoped_refptr<T>& r) {
return *this = r.ptr_;
}
template <typename U>
scoped_refptr<T>& operator=(const scoped_refptr<U>& r) {
return *this = r.get();
}
void swap(T** pp) {
T* p = ptr_;
ptr_ = *pp;
*pp = p;
}
void swap(scoped_refptr<T>& r) {
swap(&r.ptr_);
}
protected:
T* ptr_;
};
} // namespace webrtc
#endif // SYSTEM_WRAPPERS_INTERFACE_SCOPED_REFPTR_H_

View File

@@ -0,0 +1,149 @@
/*
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// Borrowed from Chromium's src/base/memory/scoped_vector.h.
#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_SCOPED_VECTOR_H_
#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_SCOPED_VECTOR_H_
#include <assert.h>
#include <algorithm>
#include <vector>
#include "webrtc/system_wrappers/interface/stl_util.h"
#include "webrtc/system_wrappers/source/move.h"
namespace webrtc {
// ScopedVector wraps a vector deleting the elements from its
// destructor.
template <class T>
class ScopedVector {
WEBRTC_MOVE_ONLY_TYPE_FOR_CPP_03(ScopedVector, RValue)
public:
typedef typename std::vector<T*>::allocator_type allocator_type;
typedef typename std::vector<T*>::size_type size_type;
typedef typename std::vector<T*>::difference_type difference_type;
typedef typename std::vector<T*>::pointer pointer;
typedef typename std::vector<T*>::const_pointer const_pointer;
typedef typename std::vector<T*>::reference reference;
typedef typename std::vector<T*>::const_reference const_reference;
typedef typename std::vector<T*>::value_type value_type;
typedef typename std::vector<T*>::iterator iterator;
typedef typename std::vector<T*>::const_iterator const_iterator;
typedef typename std::vector<T*>::reverse_iterator reverse_iterator;
typedef typename std::vector<T*>::const_reverse_iterator
const_reverse_iterator;
ScopedVector() {}
~ScopedVector() { clear(); }
ScopedVector(RValue other) { swap(*other.object); }
ScopedVector& operator=(RValue rhs) {
swap(*rhs.object);
return *this;
}
reference operator[](size_t index) { return v_[index]; }
const_reference operator[](size_t index) const { return v_[index]; }
bool empty() const { return v_.empty(); }
size_t size() const { return v_.size(); }
reverse_iterator rbegin() { return v_.rbegin(); }
const_reverse_iterator rbegin() const { return v_.rbegin(); }
reverse_iterator rend() { return v_.rend(); }
const_reverse_iterator rend() const { return v_.rend(); }
iterator begin() { return v_.begin(); }
const_iterator begin() const { return v_.begin(); }
iterator end() { return v_.end(); }
const_iterator end() const { return v_.end(); }
const_reference front() const { return v_.front(); }
reference front() { return v_.front(); }
const_reference back() const { return v_.back(); }
reference back() { return v_.back(); }
void push_back(T* elem) { v_.push_back(elem); }
void pop_back() {
assert(!empty());
delete v_.back();
v_.pop_back();
}
std::vector<T*>& get() { return v_; }
const std::vector<T*>& get() const { return v_; }
void swap(std::vector<T*>& other) { v_.swap(other); }
void swap(ScopedVector<T>& other) { v_.swap(other.v_); }
void release(std::vector<T*>* out) {
out->swap(v_);
v_.clear();
}
void reserve(size_t capacity) { v_.reserve(capacity); }
// Resize, deleting elements in the disappearing range if we are shrinking.
void resize(size_t new_size) {
if (v_.size() > new_size)
STLDeleteContainerPointers(v_.begin() + new_size, v_.end());
v_.resize(new_size);
}
template<typename InputIterator>
void assign(InputIterator begin, InputIterator end) {
v_.assign(begin, end);
}
void clear() { STLDeleteElements(&v_); }
// Like |clear()|, but doesn't delete any elements.
void weak_clear() { v_.clear(); }
// Lets the ScopedVector take ownership of |x|.
iterator insert(iterator position, T* x) {
return v_.insert(position, x);
}
// Lets the ScopedVector take ownership of elements in [first,last).
template<typename InputIterator>
void insert(iterator position, InputIterator first, InputIterator last) {
v_.insert(position, first, last);
}
iterator erase(iterator position) {
delete *position;
return v_.erase(position);
}
iterator erase(iterator first, iterator last) {
STLDeleteContainerPointers(first, last);
return v_.erase(first, last);
}
// Like |erase()|, but doesn't delete the element at |position|.
iterator weak_erase(iterator position) {
return v_.erase(position);
}
// Like |erase()|, but doesn't delete the elements in [first, last).
iterator weak_erase(iterator first, iterator last) {
return v_.erase(first, last);
}
private:
std::vector<T*> v_;
};
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_SCOPED_VECTOR_H_

View File

@@ -0,0 +1,24 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// An OS-independent sleep function.
#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_SLEEP_H_
#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_SLEEP_H_
namespace webrtc {
// This function sleeps for the specified number of milliseconds.
// It may return early if the thread is woken by some other event,
// such as the delivery of a signal on Unix.
void SleepMs(int msecs);
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_SLEEP_H_

View File

@@ -0,0 +1,65 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// Generic unstable sorting routines.
#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_SORT_H_
#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_SORT_H_
#include "webrtc/common_types.h"
#include "webrtc/typedefs.h"
namespace webrtc {
enum Type {
TYPE_Word8,
TYPE_UWord8,
TYPE_Word16,
TYPE_UWord16,
TYPE_Word32,
TYPE_UWord32,
TYPE_Word64,
TYPE_UWord64,
TYPE_Float32,
TYPE_Float64
};
// Sorts intrinsic data types.
//
// data [in/out] A pointer to an array of intrinsic type.
// Upon return it will be sorted in ascending order.
// num_of_elements The number of elements in the array.
// data_type Enum corresponding to the type of the array.
//
// returns 0 on success, -1 on failure.
int32_t Sort(void* data, uint32_t num_of_elements, Type data_type);
// Sorts arbitrary data types. This requires an array of intrinsically typed
// key values which will be used to sort the data array. There must be a
// one-to-one correspondence between data elements and key elements, with
// corresponding elements sharing the same position in their respective
// arrays.
//
// data [in/out] A pointer to an array of arbitrary type.
// Upon return it will be sorted in ascending order.
// key [in] A pointer to an array of keys used to sort the
// data array.
// num_of_elements The number of elements in the arrays.
// size_of_element The size, in bytes, of the data array.
// key_type Enum corresponding to the type of the key array.
//
// returns 0 on success, -1 on failure.
//
int32_t KeySort(void* data, void* key, uint32_t num_of_elements,
uint32_t size_of_element, Type key_type);
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_SORT_H_

View File

@@ -0,0 +1,153 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_STATIC_INSTANCE_H_
#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_STATIC_INSTANCE_H_
#include <assert.h>
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#ifdef _WIN32
#include "webrtc/system_wrappers/interface/fix_interlocked_exchange_pointer_win.h"
#endif
namespace webrtc {
enum CountOperation {
kRelease,
kAddRef,
kAddRefNoCreate
};
enum CreateOperation {
kInstanceExists,
kCreate,
kDestroy
};
template <class T>
// Construct On First Use idiom. Avoids
// "static initialization order fiasco".
static T* GetStaticInstance(CountOperation count_operation) {
// TODO (hellner): use atomic wrapper instead.
static volatile long instance_count = 0;
static T* volatile instance = NULL;
CreateOperation state = kInstanceExists;
#ifndef _WIN32
// This memory is staticly allocated once. The application does not try to
// free this memory. This approach is taken to avoid issues with
// destruction order for statically allocated memory. The memory will be
// reclaimed by the OS and memory leak tools will not recognize memory
// reachable from statics leaked so no noise is added by doing this.
static CriticalSectionWrapper* crit_sect(
CriticalSectionWrapper::CreateCriticalSection());
CriticalSectionScoped lock(crit_sect);
if (count_operation ==
kAddRefNoCreate && instance_count == 0) {
return NULL;
}
if (count_operation ==
kAddRef ||
count_operation == kAddRefNoCreate) {
instance_count++;
if (instance_count == 1) {
state = kCreate;
}
} else {
instance_count--;
if (instance_count == 0) {
state = kDestroy;
}
}
if (state == kCreate) {
instance = T::CreateInstance();
} else if (state == kDestroy) {
T* old_instance = instance;
instance = NULL;
// The state will not change past this point. Release the critical
// section while deleting the object in case it would be blocking on
// access back to this object. (This is the case for the tracing class
// since the thread owned by the tracing class also traces).
// TODO(hellner): this is a bit out of place but here goes, de-couple
// thread implementation with trace implementation.
crit_sect->Leave();
if (old_instance) {
delete old_instance;
}
// Re-acquire the lock since the scoped critical section will release
// it.
crit_sect->Enter();
return NULL;
}
#else // _WIN32
if (count_operation ==
kAddRefNoCreate && instance_count == 0) {
return NULL;
}
if (count_operation == kAddRefNoCreate) {
if (1 == InterlockedIncrement(&instance_count)) {
// The instance has been destroyed by some other thread. Rollback.
InterlockedDecrement(&instance_count);
assert(false);
return NULL;
}
// Sanity to catch corrupt state.
if (instance == NULL) {
assert(false);
InterlockedDecrement(&instance_count);
return NULL;
}
} else if (count_operation == kAddRef) {
if (instance_count == 0) {
state = kCreate;
} else {
if (1 == InterlockedIncrement(&instance_count)) {
// InterlockedDecrement because reference count should not be
// updated just yet (that's done when the instance is created).
InterlockedDecrement(&instance_count);
state = kCreate;
}
}
} else {
int new_value = InterlockedDecrement(&instance_count);
if (new_value == 0) {
state = kDestroy;
}
}
if (state == kCreate) {
// Create instance and let whichever thread finishes first assign its
// local copy to the global instance. All other threads reclaim their
// local copy.
T* new_instance = T::CreateInstance();
if (1 == InterlockedIncrement(&instance_count)) {
InterlockedExchangePointer(reinterpret_cast<void * volatile*>(&instance),
new_instance);
} else {
InterlockedDecrement(&instance_count);
if (new_instance) {
delete static_cast<T*>(new_instance);
}
}
} else if (state == kDestroy) {
T* old_value = static_cast<T*>(InterlockedExchangePointer(
reinterpret_cast<void * volatile*>(&instance), NULL));
if (old_value) {
delete static_cast<T*>(old_value);
}
return NULL;
}
#endif // #ifndef _WIN32
return instance;
}
} // namspace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_STATIC_INSTANCE_H_

View File

@@ -0,0 +1,265 @@
/*
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// Borrowed from Chromium's src/base/stl_util.h.
#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_STL_UTIL_H_
#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_STL_UTIL_H_
#include <assert.h>
#include <algorithm>
#include <functional>
#include <iterator>
#include <string>
#include <vector>
namespace webrtc {
// 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.
template<class T>
void STLClearObject(T* obj) {
T tmp;
tmp.swap(*obj);
// Sometimes "T tmp" allocates objects with memory (arena implementation?).
// Hence using additional reserve(0) even if it doesn't always work.
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;
}
}
// To treat a possibly-empty vector as an array, use these functions.
// If you know the array will never be empty, you can use &*v.begin()
// directly, but that is undefined behaviour if |v| is empty.
template<typename T>
inline T* vector_as_array(std::vector<T>* v) {
return v->empty() ? NULL : &*v->begin();
}
template<typename T>
inline const T* vector_as_array(const std::vector<T>* v) {
return v->empty() ? NULL : &*v->begin();
}
// Return a mutable char* pointing to a string's internal buffer,
// which may not be null-terminated. Writing through this pointer will
// modify the string.
//
// string_as_array(&str)[i] is valid for 0 <= i < str.size() until the
// next call to a string method that invalidates iterators.
//
// As of 2006-04, there is no standard-blessed way of getting a
// mutable reference to a string's internal buffer. However, issue 530
// (http://www.open-std.org/JTC1/SC22/WG21/docs/lwg-active.html#530)
// proposes this as the method. According to Matt Austern, this should
// already work on all current implementations.
inline char* string_as_array(std::string* str) {
// DO NOT USE const_cast<char*>(str->data())
return str->empty() ? NULL : &*str->begin();
}
// The following functions are useful for cleaning up STL containers whose
// elements point to allocated memory.
// STLDeleteElements() deletes all the elements in an STL container and clears
// the container. This function is suitable for use with a vector, set,
// hash_set, or any other STL container which defines sensible begin(), end(),
// and clear() methods.
//
// If container is NULL, this function is a no-op.
//
// As an alternative to calling STLDeleteElements() directly, consider
// STLElementDeleter (defined below), which ensures that your container's
// elements are deleted when the STLElementDeleter goes out of scope.
template <class T>
void STLDeleteElements(T* container) {
if (!container)
return;
STLDeleteContainerPointers(container->begin(), container->end());
container->clear();
}
// Given an STL container consisting of (key, value) pairs, STLDeleteValues
// deletes all the "value" components and clears the container. Does nothing
// in the case it's given a NULL pointer.
template <class T>
void STLDeleteValues(T* container) {
if (!container)
return;
for (typename T::iterator i(container->begin()); i != container->end(); ++i)
delete i->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>
bool ContainsKey(const Collection& collection, const Key& key) {
return collection.find(key) != collection.end();
}
// Returns true if the container is sorted.
template <typename Container>
bool STLIsSorted(const Container& cont) {
// Note: Use reverse iterator on container to ensure we only require
// value_type to implement operator<.
return std::adjacent_find(cont.rbegin(), cont.rend(),
std::less<typename Container::value_type>())
== cont.rend();
}
// Returns a new ResultType containing the difference of two sorted containers.
template <typename ResultType, typename Arg1, typename Arg2>
ResultType STLSetDifference(const Arg1& a1, const Arg2& a2) {
assert(STLIsSorted(a1));
assert(STLIsSorted(a2));
ResultType difference;
std::set_difference(a1.begin(), a1.end(),
a2.begin(), a2.end(),
std::inserter(difference, difference.end()));
return difference;
}
// Returns a new ResultType containing the union of two sorted containers.
template <typename ResultType, typename Arg1, typename Arg2>
ResultType STLSetUnion(const Arg1& a1, const Arg2& a2) {
assert(STLIsSorted(a1));
assert(STLIsSorted(a2));
ResultType result;
std::set_union(a1.begin(), a1.end(),
a2.begin(), a2.end(),
std::inserter(result, result.end()));
return result;
}
// Returns a new ResultType containing the intersection of two sorted
// containers.
template <typename ResultType, typename Arg1, typename Arg2>
ResultType STLSetIntersection(const Arg1& a1, const Arg2& a2) {
assert(STLIsSorted(a1));
assert(STLIsSorted(a2));
ResultType result;
std::set_intersection(a1.begin(), a1.end(),
a2.begin(), a2.end(),
std::inserter(result, result.end()));
return result;
}
// Returns true if the sorted container |a1| contains all elements of the sorted
// container |a2|.
template <typename Arg1, typename Arg2>
bool STLIncludes(const Arg1& a1, const Arg2& a2) {
assert(STLIsSorted(a1));
assert(STLIsSorted(a2));
return std::includes(a1.begin(), a1.end(),
a2.begin(), a2.end());
}
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_STL_UTIL_H_

View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// Modified from the Chromium original:
// src/base/strings/stringize_macros.h
// This file defines preprocessor macros for stringizing preprocessor
// symbols (or their output) and manipulating preprocessor symbols
// that define strings.
#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_STRINGIZE_MACROS_H_
#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_STRINGIZE_MACROS_H_
// This is not very useful as it does not expand defined symbols if
// called directly. Use its counterpart without the _NO_EXPANSION
// suffix, below.
#define STRINGIZE_NO_EXPANSION(x) #x
// Use this to quote the provided parameter, first expanding it if it
// is a preprocessor symbol.
//
// For example, if:
// #define A FOO
// #define B(x) myobj->FunctionCall(x)
//
// Then:
// STRINGIZE(A) produces "FOO"
// STRINGIZE(B(y)) produces "myobj->FunctionCall(y)"
#define STRINGIZE(x) STRINGIZE_NO_EXPANSION(x)
#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_STRINGIZE_MACROS_H_

View File

@@ -0,0 +1,114 @@
/*
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// Borrowed from Chromium's src/base/template_util.h.
#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_TEMPLATE_UTIL_H_
#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_TEMPLATE_UTIL_H_
#include <stddef.h> // For size_t.
namespace webrtc {
// Template definitions from tr1.
template<class T, T v>
struct integral_constant {
static const T value = v;
typedef T value_type;
typedef integral_constant<T, v> type;
};
template <class T, T v> const T integral_constant<T, v>::value;
typedef integral_constant<bool, true> true_type;
typedef integral_constant<bool, false> false_type;
template <class T> struct is_pointer : false_type {};
template <class T> struct is_pointer<T*> : true_type {};
template <class T, class U> struct is_same : public false_type {};
template <class T> struct is_same<T, T> : true_type {};
template<class> struct is_array : public false_type {};
template<class T, size_t n> struct is_array<T[n]> : public true_type {};
template<class T> struct is_array<T[]> : public true_type {};
template <class T> struct is_non_const_reference : false_type {};
template <class T> struct is_non_const_reference<T&> : true_type {};
template <class T> struct is_non_const_reference<const T&> : false_type {};
template <class T> struct is_void : false_type {};
template <> struct is_void<void> : true_type {};
namespace internal {
// Types YesType and NoType are guaranteed such that sizeof(YesType) <
// sizeof(NoType).
typedef char YesType;
struct NoType {
YesType dummy[2];
};
// This class is an implementation detail for is_convertible, and you
// don't need to know how it works to use is_convertible. For those
// who care: we declare two different functions, one whose argument is
// of type To and one with a variadic argument list. We give them
// return types of different size, so we can use sizeof to trick the
// compiler into telling us which function it would have chosen if we
// had called it with an argument of type From. See Alexandrescu's
// _Modern C++ Design_ for more details on this sort of trick.
struct ConvertHelper {
template <typename To>
static YesType Test(To);
template <typename To>
static NoType Test(...);
template <typename From>
static From& Create();
};
// Used to determine if a type is a struct/union/class. Inspired by Boost's
// is_class type_trait implementation.
struct IsClassHelper {
template <typename C>
static YesType Test(void(C::*)(void));
template <typename C>
static NoType Test(...);
};
} // namespace internal
// Inherits from true_type if From is convertible to To, false_type otherwise.
//
// Note that if the type is convertible, this will be a true_type REGARDLESS
// of whether or not the conversion would emit a warning.
template <typename From, typename To>
struct is_convertible
: integral_constant<bool,
sizeof(internal::ConvertHelper::Test<To>(
internal::ConvertHelper::Create<From>())) ==
sizeof(internal::YesType)> {
};
template <typename T>
struct is_class
: integral_constant<bool,
sizeof(internal::IsClassHelper::Test<T>(0)) ==
sizeof(internal::YesType)> {
};
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_TEMPLATE_UTIL_H_

View File

@@ -0,0 +1,99 @@
//
// Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
//
// Borrowed from
// https://code.google.com/p/gperftools/source/browse/src/base/thread_annotations.h
// but adapted for clang attributes instead of the gcc.
//
// This header file contains the macro definitions for thread safety
// annotations that allow the developers to document the locking policies
// of their multi-threaded code. The annotations can also help program
// analysis tools to identify potential thread safety issues.
#ifndef BASE_THREAD_ANNOTATIONS_H_
#define BASE_THREAD_ANNOTATIONS_H_
#if defined(__clang__) && (!defined(SWIG))
#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
#else
#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
#endif
// Document if a shared variable/field needs to be protected by a lock.
// GUARDED_BY allows the user to specify a particular lock that should be
// held when accessing the annotated variable, while GUARDED_VAR only
// indicates a shared variable should be guarded (by any lock). GUARDED_VAR
// is primarily used when the client cannot express the name of the lock.
#define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
#define GUARDED_VAR THREAD_ANNOTATION_ATTRIBUTE__(guarded)
// Document if the memory location pointed to by a pointer should be guarded
// by a lock when dereferencing the pointer. Similar to GUARDED_VAR,
// PT_GUARDED_VAR is primarily used when the client cannot express the name
// of the lock. Note that a pointer variable to a shared memory location
// could itself be a shared variable. For example, if a shared global pointer
// q, which is guarded by mu1, points to a shared memory location that is
// guarded by mu2, q should be annotated as follows:
// int *q GUARDED_BY(mu1) PT_GUARDED_BY(mu2);
#define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(point_to_guarded_by(x))
#define PT_GUARDED_VAR THREAD_ANNOTATION_ATTRIBUTE__(point_to_guarded)
// Document the acquisition order between locks that can be held
// simultaneously by a thread. For any two locks that need to be annotated
// to establish an acquisition order, only one of them needs the annotation.
// (i.e. You don't have to annotate both locks with both ACQUIRED_AFTER
// and ACQUIRED_BEFORE.)
#define ACQUIRED_AFTER(x) THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(x))
#define ACQUIRED_BEFORE(x) THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(x))
// The following three annotations document the lock requirements for
// functions/methods.
// Document if a function expects certain locks to be held before it is called
#define EXCLUSIVE_LOCKS_REQUIRED(...) \
THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__))
#define SHARED_LOCKS_REQUIRED(...) \
THREAD_ANNOTATION_ATTRIBUTE__(shared_locks_required(__VA_ARGS__))
// Document the locks acquired in the body of the function. These locks
// cannot be held when calling this function (as google3's Mutex locks are
// non-reentrant).
#define LOCKS_EXCLUDED(x) THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(x))
// Document the lock the annotated function returns without acquiring it.
#define LOCK_RETURNED(x) THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
// Document if a class/type is a lockable type (such as the Mutex class).
#define LOCKABLE THREAD_ANNOTATION_ATTRIBUTE__(lockable)
// Document if a class is a scoped lockable type (such as the MutexLock class).
#define SCOPED_LOCKABLE THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
// The following annotations specify lock and unlock primitives.
#define EXCLUSIVE_LOCK_FUNCTION(...) \
THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__))
#define SHARED_LOCK_FUNCTION(...) \
THREAD_ANNOTATION_ATTRIBUTE__(shared_lock_function(__VA_ARGS__))
#define EXCLUSIVE_TRYLOCK_FUNCTION(...) \
THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__))
#define SHARED_TRYLOCK_FUNCTION(...) \
THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock_function(__VA_ARGS__))
#define UNLOCK_FUNCTION(...) \
THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__))
// An escape hatch for thread safety analysis to ignore the annotated function.
#define NO_THREAD_SAFETY_ANALYSIS \
THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
#endif // BASE_THREAD_ANNOTATIONS_H_

View File

@@ -0,0 +1,92 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// System independant wrapper for spawning threads
// Note: the spawned thread will loop over the callback function until stopped.
// Note: The callback function is expected to return every 2 seconds or more
// often.
#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_THREAD_WRAPPER_H_
#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_THREAD_WRAPPER_H_
#include "webrtc/common_types.h"
#include "webrtc/typedefs.h"
namespace webrtc {
// Object that will be passed by the spawned thread when it enters the callback
// function.
#define ThreadObj void*
// Callback function that the spawned thread will enter once spawned.
// A return value of false is interpreted as that the function has no
// more work to do and that the thread can be released.
typedef bool(*ThreadRunFunction)(ThreadObj);
enum ThreadPriority {
kLowPriority = 1,
kNormalPriority = 2,
kHighPriority = 3,
kHighestPriority = 4,
kRealtimePriority = 5
};
class ThreadWrapper {
public:
enum {kThreadMaxNameLength = 64};
virtual ~ThreadWrapper() {};
// Factory method. Constructor disabled.
//
// func Pointer to a, by user, specified callback function.
// obj Object associated with the thread. Passed in the callback
// function.
// prio Thread priority. May require root/admin rights.
// thread_name NULL terminated thread name, will be visable in the Windows
// debugger.
static ThreadWrapper* CreateThread(ThreadRunFunction func,
ThreadObj obj,
ThreadPriority prio = kNormalPriority,
const char* thread_name = 0);
// Get the current thread's kernel thread ID.
static uint32_t GetThreadId();
// Non blocking termination of the spawned thread. Note that it is not safe
// to delete this class until the spawned thread has been reclaimed.
virtual void SetNotAlive() = 0;
// Tries to spawns a thread and returns true if that was successful.
// Additionally, it tries to set thread priority according to the priority
// from when CreateThread was called. However, failure to set priority will
// not result in a false return value.
// TODO(henrike): add a function for polling whether priority was set or
// not.
virtual bool Start(unsigned int& id) = 0;
// Sets the threads CPU affinity. CPUs are listed 0 - (number of CPUs - 1).
// The numbers in processor_numbers specify which CPUs are allowed to run the
// thread. processor_numbers should not contain any duplicates and elements
// should be lower than (number of CPUs - 1). amount_of_processors should be
// equal to the number of processors listed in processor_numbers.
virtual bool SetAffinity(const int* processor_numbers,
const unsigned int amount_of_processors);
// Stops the spawned thread and waits for it to be reclaimed with a timeout
// of two seconds. Will return false if the thread was not reclaimed.
// Multiple tries to Stop are allowed (e.g. to wait longer than 2 seconds).
// It's ok to call Stop() even if the spawned thread has been reclaimed.
virtual bool Stop() = 0;
};
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_THREAD_WRAPPER_H_

View File

@@ -0,0 +1,298 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// System independant wrapper for polling elapsed time in ms and us.
// The implementation works in the tick domain which can be mapped over to the
// time domain.
#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_TICK_UTIL_H_
#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_TICK_UTIL_H_
#if _WIN32
// Note: The Windows header must always be included before mmsystem.h
#include <windows.h>
#include <mmsystem.h>
#elif WEBRTC_LINUX
#include <time.h>
#elif WEBRTC_MAC
#include <mach/mach_time.h>
#include <string.h>
#else
#include <sys/time.h>
#include <time.h>
#endif
#include "webrtc/typedefs.h"
namespace webrtc {
class TickInterval;
// Class representing the current time.
class TickTime {
public:
TickTime();
explicit TickTime(int64_t ticks);
// Current time in the tick domain.
static TickTime Now();
// Now in the time domain in ms.
static int64_t MillisecondTimestamp();
// Now in the time domain in us.
static int64_t MicrosecondTimestamp();
// Returns the number of ticks in the tick domain.
int64_t Ticks() const;
static int64_t MillisecondsToTicks(const int64_t ms);
static int64_t TicksToMilliseconds(const int64_t ticks);
// Returns a TickTime that is ticks later than the passed TickTime.
friend TickTime operator+(const TickTime lhs, const int64_t ticks);
TickTime& operator+=(const int64_t& ticks);
// Returns a TickInterval that is the difference in ticks beween rhs and lhs.
friend TickInterval operator-(const TickTime& lhs, const TickTime& rhs);
// Call to engage the fake clock. This is useful for tests since relying on
// a real clock often makes the test flaky.
static void UseFakeClock(int64_t start_millisecond);
// Advance the fake clock. Must be called after UseFakeClock.
static void AdvanceFakeClock(int64_t milliseconds);
private:
static int64_t QueryOsForTicks();
static bool use_fake_clock_;
static int64_t fake_ticks_;
int64_t ticks_;
};
// Represents a time delta in ticks.
class TickInterval {
public:
TickInterval();
int64_t Milliseconds() const;
int64_t Microseconds() const;
// Returns the sum of two TickIntervals as a TickInterval.
friend TickInterval operator+(const TickInterval& lhs,
const TickInterval& rhs);
TickInterval& operator+=(const TickInterval& rhs);
// Returns a TickInterval corresponding to rhs - lhs.
friend TickInterval operator-(const TickInterval& lhs,
const TickInterval& rhs);
TickInterval& operator-=(const TickInterval& rhs);
friend bool operator>(const TickInterval& lhs, const TickInterval& rhs);
friend bool operator<=(const TickInterval& lhs, const TickInterval& rhs);
friend bool operator<(const TickInterval& lhs, const TickInterval& rhs);
friend bool operator>=(const TickInterval& lhs, const TickInterval& rhs);
private:
explicit TickInterval(int64_t interval);
friend class TickTime;
friend TickInterval operator-(const TickTime& lhs, const TickTime& rhs);
private:
int64_t interval_;
};
inline TickInterval operator+(const TickInterval& lhs,
const TickInterval& rhs) {
return TickInterval(lhs.interval_ + rhs.interval_);
}
inline TickInterval operator-(const TickInterval& lhs,
const TickInterval& rhs) {
return TickInterval(lhs.interval_ - rhs.interval_);
}
inline TickInterval operator-(const TickTime& lhs, const TickTime& rhs) {
return TickInterval(lhs.ticks_ - rhs.ticks_);
}
inline TickTime operator+(const TickTime lhs, const int64_t ticks) {
TickTime time = lhs;
time.ticks_ += ticks;
return time;
}
inline bool operator>(const TickInterval& lhs, const TickInterval& rhs) {
return lhs.interval_ > rhs.interval_;
}
inline bool operator<=(const TickInterval& lhs, const TickInterval& rhs) {
return lhs.interval_ <= rhs.interval_;
}
inline bool operator<(const TickInterval& lhs, const TickInterval& rhs) {
return lhs.interval_ <= rhs.interval_;
}
inline bool operator>=(const TickInterval& lhs, const TickInterval& rhs) {
return lhs.interval_ >= rhs.interval_;
}
inline TickTime::TickTime()
: ticks_(0) {
}
inline TickTime::TickTime(int64_t ticks)
: ticks_(ticks) {
}
inline TickTime TickTime::Now() {
if (use_fake_clock_)
return TickTime(fake_ticks_);
else
return TickTime(QueryOsForTicks());
}
inline int64_t TickTime::MillisecondTimestamp() {
int64_t ticks = TickTime::Now().Ticks();
#if _WIN32
#ifdef USE_QUERY_PERFORMANCE_COUNTER
LARGE_INTEGER qpfreq;
QueryPerformanceFrequency(&qpfreq);
return (ticks * 1000) / qpfreq.QuadPart;
#else
return ticks;
#endif
#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
return ticks / 1000000LL;
#else
return ticks / 1000LL;
#endif
}
inline int64_t TickTime::MicrosecondTimestamp() {
int64_t ticks = TickTime::Now().Ticks();
#if _WIN32
#ifdef USE_QUERY_PERFORMANCE_COUNTER
LARGE_INTEGER qpfreq;
QueryPerformanceFrequency(&qpfreq);
return (ticks * 1000) / (qpfreq.QuadPart / 1000);
#else
return ticks * 1000LL;
#endif
#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
return ticks / 1000LL;
#else
return ticks;
#endif
}
inline int64_t TickTime::Ticks() const {
return ticks_;
}
inline int64_t TickTime::MillisecondsToTicks(const int64_t ms) {
#if _WIN32
#ifdef USE_QUERY_PERFORMANCE_COUNTER
LARGE_INTEGER qpfreq;
QueryPerformanceFrequency(&qpfreq);
return (qpfreq.QuadPart * ms) / 1000;
#else
return ms;
#endif
#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
return ms * 1000000LL;
#else
return ms * 1000LL;
#endif
}
inline int64_t TickTime::TicksToMilliseconds(const int64_t ticks) {
#if _WIN32
#ifdef USE_QUERY_PERFORMANCE_COUNTER
LARGE_INTEGER qpfreq;
QueryPerformanceFrequency(&qpfreq);
return (ticks * 1000) / qpfreq.QuadPart;
#else
return ticks;
#endif
#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
return ticks / 1000000LL;
#else
return ticks / 1000LL;
#endif
}
inline TickTime& TickTime::operator+=(const int64_t& ticks) {
ticks_ += ticks;
return *this;
}
inline TickInterval::TickInterval() : interval_(0) {
}
inline TickInterval::TickInterval(const int64_t interval)
: interval_(interval) {
}
inline int64_t TickInterval::Milliseconds() const {
#if _WIN32
#ifdef USE_QUERY_PERFORMANCE_COUNTER
LARGE_INTEGER qpfreq;
QueryPerformanceFrequency(&qpfreq);
return (interval_ * 1000) / qpfreq.QuadPart;
#else
// interval_ is in ms
return interval_;
#endif
#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
// interval_ is in ns
return interval_ / 1000000;
#else
// interval_ is usecs
return interval_ / 1000;
#endif
}
inline int64_t TickInterval::Microseconds() const {
#if _WIN32
#ifdef USE_QUERY_PERFORMANCE_COUNTER
LARGE_INTEGER qpfreq;
QueryPerformanceFrequency(&qpfreq);
return (interval_ * 1000000) / qpfreq.QuadPart;
#else
// interval_ is in ms
return interval_ * 1000LL;
#endif
#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
// interval_ is in ns
return interval_ / 1000;
#else
// interval_ is usecs
return interval_;
#endif
}
inline TickInterval& TickInterval::operator+=(const TickInterval& rhs) {
interval_ += rhs.interval_;
return *this;
}
inline TickInterval& TickInterval::operator-=(const TickInterval& rhs) {
interval_ -= rhs.interval_;
return *this;
}
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_TICK_UTIL_H_

View File

@@ -0,0 +1,56 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef SYSTEM_WRAPPERS_INTERFACE_TIMESTAMP_EXTRAPOLATOR_H_
#define SYSTEM_WRAPPERS_INTERFACE_TIMESTAMP_EXTRAPOLATOR_H_
#include "webrtc/system_wrappers/interface/rw_lock_wrapper.h"
#include "webrtc/typedefs.h"
namespace webrtc
{
class TimestampExtrapolator
{
public:
explicit TimestampExtrapolator(int64_t start_ms);
~TimestampExtrapolator();
void Update(int64_t tMs, uint32_t ts90khz);
int64_t ExtrapolateLocalTime(uint32_t timestamp90khz);
void Reset(int64_t start_ms);
private:
void CheckForWrapArounds(uint32_t ts90khz);
bool DelayChangeDetection(double error);
RWLockWrapper* _rwLock;
double _w[2];
double _P[2][2];
int64_t _startMs;
int64_t _prevMs;
uint32_t _firstTimestamp;
int32_t _wrapArounds;
int64_t _prevUnwrappedTimestamp;
int64_t _prevWrapTimestamp;
const double _lambda;
bool _firstAfterReset;
uint32_t _packetCount;
const uint32_t _startUpFilterDelayInPackets;
double _detectorAccumulatorPos;
double _detectorAccumulatorNeg;
const double _alarmThreshold;
const double _accDrift;
const double _accMaxError;
const double _P11;
};
} // namespace webrtc
#endif // SYSTEM_WRAPPERS_INTERFACE_TIMESTAMP_EXTRAPOLATOR_H_

View File

@@ -0,0 +1,92 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*
* System independent wrapper for logging runtime information to file.
* Note: All log messages will be written to the same trace file.
* Note: If too many messages are written to file there will be a build up of
* messages. Apply filtering to avoid that.
*/
#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_TRACE_H_
#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_TRACE_H_
#include "webrtc/common_types.h"
#include "webrtc/typedefs.h"
namespace webrtc {
#if defined(WEBRTC_RESTRICT_LOGGING)
// Disable all TRACE macros. The LOG macro is still functional.
#define WEBRTC_TRACE true ? (void) 0 : Trace::Add
#else
#define WEBRTC_TRACE Trace::Add
#endif
class Trace {
public:
// The length of the trace text preceeding the log message.
static const int kBoilerplateLength;
// The position of the timestamp text within a trace.
static const int kTimestampPosition;
// The length of the timestamp (without "delta" field).
static const int kTimestampLength;
// Increments the reference count to the trace.
static void CreateTrace();
// Decrements the reference count to the trace.
static void ReturnTrace();
// Note: any instance that writes to the trace file should increment and
// decrement the reference count on construction and destruction,
// respectively.
// Specifies what type of messages should be written to the trace file. The
// filter parameter is a bitmask where each message type is enumerated by the
// TraceLevel enumerator. TODO(hellner): why is the TraceLevel enumerator not
// defined in this file?
static void set_level_filter(uint32_t filter) { level_filter_ = filter; }
// Returns what type of messages are written to the trace file.
static uint32_t level_filter() { return level_filter_; }
// Sets the file name. If add_file_counter is false the same file will be
// reused when it fills up. If it's true a new file with incremented name
// will be used.
static int32_t SetTraceFile(const char* file_name,
const bool add_file_counter = false);
// Returns the name of the file that the trace is currently writing to.
static int32_t TraceFile(char file_name[1024]);
// Registers callback to receive trace messages.
// TODO(hellner): Why not use OutStream instead? Why is TraceCallback not
// defined in this file?
static int32_t SetTraceCallback(TraceCallback* callback);
// Adds a trace message for writing to file. The message is put in a queue
// for writing to file whenever possible for performance reasons. I.e. there
// is a crash it is possible that the last, vital logs are not logged yet.
// level is the type of message to log. If that type of messages is
// filtered it will not be written to file. module is an identifier for what
// part of the code the message is coming.
// id is an identifier that should be unique for that set of classes that
// are associated (e.g. all instances owned by an engine).
// msg and the ellipsis are the same as e.g. sprintf.
// TODO(hellner) Why is TraceModule not defined in this file?
static void Add(const TraceLevel level,
const TraceModule module,
const int32_t id,
const char* msg, ...);
private:
static uint32_t level_filter_;
};
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_TRACE_H_

View File

@@ -0,0 +1,912 @@
// 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 under third_party_mods/chromium or at:
// http://src.chromium.org/svn/trunk/src/LICENSE
#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_TRACE_EVENT_H_
#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_TRACE_EVENT_H_
#include <string>
#include "webrtc/system_wrappers/interface/event_tracer.h"
#if defined(TRACE_EVENT0)
#error "Another copy of trace_event.h has already been included."
#endif
// Extracted from Chromium's src/base/debug/trace_event.h.
// This header is designed to give you trace_event macros without specifying
// how the events actually get collected and stored. If you need to expose trace
// event to some other universe, you can copy-and-paste this file,
// implement the TRACE_EVENT_API macros, and do any other necessary fixup for
// the target platform. The end result is that multiple libraries can funnel
// events through to a shared trace event collector.
// Trace events are for tracking application performance and resource usage.
// Macros are provided to track:
// Begin and end of function calls
// Counters
//
// Events are issued against categories. Whereas LOG's
// categories are statically defined, TRACE categories are created
// implicitly with a string. For example:
// TRACE_EVENT_INSTANT0("MY_SUBSYSTEM", "SomeImportantEvent")
//
// Events can be INSTANT, or can be pairs of BEGIN and END in the same scope:
// TRACE_EVENT_BEGIN0("MY_SUBSYSTEM", "SomethingCostly")
// doSomethingCostly()
// TRACE_EVENT_END0("MY_SUBSYSTEM", "SomethingCostly")
// Note: our tools can't always determine the correct BEGIN/END pairs unless
// these are used in the same scope. Use ASYNC_BEGIN/ASYNC_END macros if you
// need them to be in separate scopes.
//
// A common use case is to trace entire function scopes. This
// issues a trace BEGIN and END automatically:
// void doSomethingCostly() {
// TRACE_EVENT0("MY_SUBSYSTEM", "doSomethingCostly");
// ...
// }
//
// Additional parameters can be associated with an event:
// void doSomethingCostly2(int howMuch) {
// TRACE_EVENT1("MY_SUBSYSTEM", "doSomethingCostly",
// "howMuch", howMuch);
// ...
// }
//
// The trace system will automatically add to this information the
// current process id, thread id, and a timestamp in microseconds.
//
// To trace an asynchronous procedure such as an IPC send/receive, use
// ASYNC_BEGIN and ASYNC_END:
// [single threaded sender code]
// static int send_count = 0;
// ++send_count;
// TRACE_EVENT_ASYNC_BEGIN0("ipc", "message", send_count);
// Send(new MyMessage(send_count));
// [receive code]
// void OnMyMessage(send_count) {
// TRACE_EVENT_ASYNC_END0("ipc", "message", send_count);
// }
// The third parameter is a unique ID to match ASYNC_BEGIN/ASYNC_END pairs.
// ASYNC_BEGIN and ASYNC_END can occur on any thread of any traced process.
// Pointers can be used for the ID parameter, and they will be mangled
// internally so that the same pointer on two different processes will not
// match. For example:
// class MyTracedClass {
// public:
// MyTracedClass() {
// TRACE_EVENT_ASYNC_BEGIN0("category", "MyTracedClass", this);
// }
// ~MyTracedClass() {
// TRACE_EVENT_ASYNC_END0("category", "MyTracedClass", this);
// }
// }
//
// Trace event also supports counters, which is a way to track a quantity
// as it varies over time. Counters are created with the following macro:
// TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter", g_myCounterValue);
//
// Counters are process-specific. The macro itself can be issued from any
// thread, however.
//
// Sometimes, you want to track two counters at once. You can do this with two
// counter macros:
// TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter0", g_myCounterValue[0]);
// TRACE_COUNTER1("MY_SUBSYSTEM", "myCounter1", g_myCounterValue[1]);
// Or you can do it with a combined macro:
// TRACE_COUNTER2("MY_SUBSYSTEM", "myCounter",
// "bytesPinned", g_myCounterValue[0],
// "bytesAllocated", g_myCounterValue[1]);
// This indicates to the tracing UI that these counters should be displayed
// in a single graph, as a summed area chart.
//
// Since counters are in a global namespace, you may want to disembiguate with a
// unique ID, by using the TRACE_COUNTER_ID* variations.
//
// By default, trace collection is compiled in, but turned off at runtime.
// Collecting trace data is the responsibility of the embedding
// application. In Chrome's case, navigating to about:tracing will turn on
// tracing and display data collected across all active processes.
//
//
// Memory scoping note:
// Tracing copies the pointers, not the string content, of the strings passed
// in for category, name, and arg_names. Thus, the following code will
// cause problems:
// char* str = strdup("impprtantName");
// TRACE_EVENT_INSTANT0("SUBSYSTEM", str); // BAD!
// free(str); // Trace system now has dangling pointer
//
// To avoid this issue with the |name| and |arg_name| parameters, use the
// TRACE_EVENT_COPY_XXX overloads of the macros at additional runtime overhead.
// Notes: The category must always be in a long-lived char* (i.e. static const).
// The |arg_values|, when used, are always deep copied with the _COPY
// macros.
//
// When are string argument values copied:
// const char* arg_values are only referenced by default:
// TRACE_EVENT1("category", "name",
// "arg1", "literal string is only referenced");
// Use TRACE_STR_COPY to force copying of a const char*:
// TRACE_EVENT1("category", "name",
// "arg1", TRACE_STR_COPY("string will be copied"));
// std::string arg_values are always copied:
// TRACE_EVENT1("category", "name",
// "arg1", std::string("string will be copied"));
//
//
// Thread Safety:
// Thread safety is provided by methods defined in event_tracer.h. See the file
// for details.
// By default, const char* argument values are assumed to have long-lived scope
// and will not be copied. Use this macro to force a const char* to be copied.
#define TRACE_STR_COPY(str) \
webrtc::trace_event_internal::TraceStringWithCopy(str)
// By default, uint64 ID argument values are not mangled with the Process ID in
// TRACE_EVENT_ASYNC macros. Use this macro to force Process ID mangling.
#define TRACE_ID_MANGLE(id) \
webrtc::trace_event_internal::TraceID::ForceMangle(id)
// Records a pair of begin and end events called "name" for the current
// scope, with 0, 1 or 2 associated arguments. If the category is not
// enabled, then this does nothing.
// - category and name strings must have application lifetime (statics or
// literals). They may not include " chars.
#define TRACE_EVENT0(category, name) \
INTERNAL_TRACE_EVENT_ADD_SCOPED(category, name)
#define TRACE_EVENT1(category, name, arg1_name, arg1_val) \
INTERNAL_TRACE_EVENT_ADD_SCOPED(category, name, arg1_name, arg1_val)
#define TRACE_EVENT2(category, name, arg1_name, arg1_val, arg2_name, arg2_val) \
INTERNAL_TRACE_EVENT_ADD_SCOPED(category, name, arg1_name, arg1_val, \
arg2_name, arg2_val)
// Same as TRACE_EVENT except that they are not included in official builds.
#ifdef OFFICIAL_BUILD
#define UNSHIPPED_TRACE_EVENT0(category, name) (void)0
#define UNSHIPPED_TRACE_EVENT1(category, name, arg1_name, arg1_val) (void)0
#define UNSHIPPED_TRACE_EVENT2(category, name, arg1_name, arg1_val, \
arg2_name, arg2_val) (void)0
#define UNSHIPPED_TRACE_EVENT_INSTANT0(category, name) (void)0
#define UNSHIPPED_TRACE_EVENT_INSTANT1(category, name, arg1_name, arg1_val) \
(void)0
#define UNSHIPPED_TRACE_EVENT_INSTANT2(category, name, arg1_name, arg1_val, \
arg2_name, arg2_val) (void)0
#else
#define UNSHIPPED_TRACE_EVENT0(category, name) \
TRACE_EVENT0(category, name)
#define UNSHIPPED_TRACE_EVENT1(category, name, arg1_name, arg1_val) \
TRACE_EVENT1(category, name, arg1_name, arg1_val)
#define UNSHIPPED_TRACE_EVENT2(category, name, arg1_name, arg1_val, \
arg2_name, arg2_val) \
TRACE_EVENT2(category, name, arg1_name, arg1_val, arg2_name, arg2_val)
#define UNSHIPPED_TRACE_EVENT_INSTANT0(category, name) \
TRACE_EVENT_INSTANT0(category, name)
#define UNSHIPPED_TRACE_EVENT_INSTANT1(category, name, arg1_name, arg1_val) \
TRACE_EVENT_INSTANT1(category, name, arg1_name, arg1_val)
#define UNSHIPPED_TRACE_EVENT_INSTANT2(category, name, arg1_name, arg1_val, \
arg2_name, arg2_val) \
TRACE_EVENT_INSTANT2(category, name, arg1_name, arg1_val, \
arg2_name, arg2_val)
#endif
// Records a single event called "name" immediately, with 0, 1 or 2
// associated arguments. If the category is not enabled, then this
// does nothing.
// - category and name strings must have application lifetime (statics or
// literals). They may not include " chars.
#define TRACE_EVENT_INSTANT0(category, name) \
INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \
category, name, TRACE_EVENT_FLAG_NONE)
#define TRACE_EVENT_INSTANT1(category, name, arg1_name, arg1_val) \
INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \
category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
#define TRACE_EVENT_INSTANT2(category, name, arg1_name, arg1_val, \
arg2_name, arg2_val) \
INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \
category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \
arg2_name, arg2_val)
#define TRACE_EVENT_COPY_INSTANT0(category, name) \
INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \
category, name, TRACE_EVENT_FLAG_COPY)
#define TRACE_EVENT_COPY_INSTANT1(category, name, arg1_name, arg1_val) \
INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \
category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val)
#define TRACE_EVENT_COPY_INSTANT2(category, name, arg1_name, arg1_val, \
arg2_name, arg2_val) \
INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_INSTANT, \
category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \
arg2_name, arg2_val)
// Records a single BEGIN event called "name" immediately, with 0, 1 or 2
// associated arguments. If the category is not enabled, then this
// does nothing.
// - category and name strings must have application lifetime (statics or
// literals). They may not include " chars.
#define TRACE_EVENT_BEGIN0(category, name) \
INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \
category, name, TRACE_EVENT_FLAG_NONE)
#define TRACE_EVENT_BEGIN1(category, name, arg1_name, arg1_val) \
INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \
category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
#define TRACE_EVENT_BEGIN2(category, name, arg1_name, arg1_val, \
arg2_name, arg2_val) \
INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \
category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \
arg2_name, arg2_val)
#define TRACE_EVENT_COPY_BEGIN0(category, name) \
INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \
category, name, TRACE_EVENT_FLAG_COPY)
#define TRACE_EVENT_COPY_BEGIN1(category, name, arg1_name, arg1_val) \
INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \
category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val)
#define TRACE_EVENT_COPY_BEGIN2(category, name, arg1_name, arg1_val, \
arg2_name, arg2_val) \
INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_BEGIN, \
category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \
arg2_name, arg2_val)
// Records a single END event for "name" immediately. If the category
// is not enabled, then this does nothing.
// - category and name strings must have application lifetime (statics or
// literals). They may not include " chars.
#define TRACE_EVENT_END0(category, name) \
INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \
category, name, TRACE_EVENT_FLAG_NONE)
#define TRACE_EVENT_END1(category, name, arg1_name, arg1_val) \
INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \
category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
#define TRACE_EVENT_END2(category, name, arg1_name, arg1_val, \
arg2_name, arg2_val) \
INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \
category, name, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val, \
arg2_name, arg2_val)
#define TRACE_EVENT_COPY_END0(category, name) \
INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \
category, name, TRACE_EVENT_FLAG_COPY)
#define TRACE_EVENT_COPY_END1(category, name, arg1_name, arg1_val) \
INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \
category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val)
#define TRACE_EVENT_COPY_END2(category, name, arg1_name, arg1_val, \
arg2_name, arg2_val) \
INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_END, \
category, name, TRACE_EVENT_FLAG_COPY, arg1_name, arg1_val, \
arg2_name, arg2_val)
// Records the value of a counter called "name" immediately. Value
// must be representable as a 32 bit integer.
// - category and name strings must have application lifetime (statics or
// literals). They may not include " chars.
#define TRACE_COUNTER1(category, name, value) \
INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \
category, name, TRACE_EVENT_FLAG_NONE, \
"value", static_cast<int>(value))
#define TRACE_COPY_COUNTER1(category, name, value) \
INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \
category, name, TRACE_EVENT_FLAG_COPY, \
"value", static_cast<int>(value))
// Records the values of a multi-parted counter called "name" immediately.
// The UI will treat value1 and value2 as parts of a whole, displaying their
// values as a stacked-bar chart.
// - category and name strings must have application lifetime (statics or
// literals). They may not include " chars.
#define TRACE_COUNTER2(category, name, value1_name, value1_val, \
value2_name, value2_val) \
INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \
category, name, TRACE_EVENT_FLAG_NONE, \
value1_name, static_cast<int>(value1_val), \
value2_name, static_cast<int>(value2_val))
#define TRACE_COPY_COUNTER2(category, name, value1_name, value1_val, \
value2_name, value2_val) \
INTERNAL_TRACE_EVENT_ADD(TRACE_EVENT_PHASE_COUNTER, \
category, name, TRACE_EVENT_FLAG_COPY, \
value1_name, static_cast<int>(value1_val), \
value2_name, static_cast<int>(value2_val))
// Records the value of a counter called "name" immediately. Value
// must be representable as a 32 bit integer.
// - category and name strings must have application lifetime (statics or
// literals). They may not include " chars.
// - |id| is used to disambiguate counters with the same name. It must either
// be a pointer or an integer value up to 64 bits. If it's a pointer, the bits
// will be xored with a hash of the process ID so that the same pointer on
// two different processes will not collide.
#define TRACE_COUNTER_ID1(category, name, id, value) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \
category, name, id, TRACE_EVENT_FLAG_NONE, \
"value", static_cast<int>(value))
#define TRACE_COPY_COUNTER_ID1(category, name, id, value) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \
category, name, id, TRACE_EVENT_FLAG_COPY, \
"value", static_cast<int>(value))
// Records the values of a multi-parted counter called "name" immediately.
// The UI will treat value1 and value2 as parts of a whole, displaying their
// values as a stacked-bar chart.
// - category and name strings must have application lifetime (statics or
// literals). They may not include " chars.
// - |id| is used to disambiguate counters with the same name. It must either
// be a pointer or an integer value up to 64 bits. If it's a pointer, the bits
// will be xored with a hash of the process ID so that the same pointer on
// two different processes will not collide.
#define TRACE_COUNTER_ID2(category, name, id, value1_name, value1_val, \
value2_name, value2_val) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \
category, name, id, TRACE_EVENT_FLAG_NONE, \
value1_name, static_cast<int>(value1_val), \
value2_name, static_cast<int>(value2_val))
#define TRACE_COPY_COUNTER_ID2(category, name, id, value1_name, value1_val, \
value2_name, value2_val) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_COUNTER, \
category, name, id, TRACE_EVENT_FLAG_COPY, \
value1_name, static_cast<int>(value1_val), \
value2_name, static_cast<int>(value2_val))
// Records a single ASYNC_BEGIN event called "name" immediately, with 0, 1 or 2
// associated arguments. If the category is not enabled, then this
// does nothing.
// - category and name strings must have application lifetime (statics or
// literals). They may not include " chars.
// - |id| is used to match the ASYNC_BEGIN event with the ASYNC_END event. ASYNC
// events are considered to match if their category, name and id values all
// match. |id| must either be a pointer or an integer value up to 64 bits. If
// it's a pointer, the bits will be xored with a hash of the process ID so
// that the same pointer on two different processes will not collide.
// An asynchronous operation can consist of multiple phases. The first phase is
// defined by the ASYNC_BEGIN calls. Additional phases can be defined using the
// ASYNC_STEP macros. When the operation completes, call ASYNC_END.
// An ASYNC trace typically occur on a single thread (if not, they will only be
// drawn on the thread defined in the ASYNC_BEGIN event), but all events in that
// operation must use the same |name| and |id|. Each event can have its own
// args.
#define TRACE_EVENT_ASYNC_BEGIN0(category, name, id) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \
category, name, id, TRACE_EVENT_FLAG_NONE)
#define TRACE_EVENT_ASYNC_BEGIN1(category, name, id, arg1_name, arg1_val) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \
category, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
#define TRACE_EVENT_ASYNC_BEGIN2(category, name, id, arg1_name, arg1_val, \
arg2_name, arg2_val) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \
category, name, id, TRACE_EVENT_FLAG_NONE, \
arg1_name, arg1_val, arg2_name, arg2_val)
#define TRACE_EVENT_COPY_ASYNC_BEGIN0(category, name, id) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \
category, name, id, TRACE_EVENT_FLAG_COPY)
#define TRACE_EVENT_COPY_ASYNC_BEGIN1(category, name, id, arg1_name, arg1_val) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \
category, name, id, TRACE_EVENT_FLAG_COPY, \
arg1_name, arg1_val)
#define TRACE_EVENT_COPY_ASYNC_BEGIN2(category, name, id, arg1_name, arg1_val, \
arg2_name, arg2_val) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_BEGIN, \
category, name, id, TRACE_EVENT_FLAG_COPY, \
arg1_name, arg1_val, arg2_name, arg2_val)
// Records a single ASYNC_STEP event for |step| immediately. If the category
// is not enabled, then this does nothing. The |name| and |id| must match the
// ASYNC_BEGIN event above. The |step| param identifies this step within the
// async event. This should be called at the beginning of the next phase of an
// asynchronous operation.
#define TRACE_EVENT_ASYNC_STEP0(category, name, id, step) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, \
category, name, id, TRACE_EVENT_FLAG_NONE, "step", step)
#define TRACE_EVENT_ASYNC_STEP1(category, name, id, step, \
arg1_name, arg1_val) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, \
category, name, id, TRACE_EVENT_FLAG_NONE, "step", step, \
arg1_name, arg1_val)
#define TRACE_EVENT_COPY_ASYNC_STEP0(category, name, id, step) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, \
category, name, id, TRACE_EVENT_FLAG_COPY, "step", step)
#define TRACE_EVENT_COPY_ASYNC_STEP1(category, name, id, step, \
arg1_name, arg1_val) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_STEP, \
category, name, id, TRACE_EVENT_FLAG_COPY, "step", step, \
arg1_name, arg1_val)
// Records a single ASYNC_END event for "name" immediately. If the category
// is not enabled, then this does nothing.
#define TRACE_EVENT_ASYNC_END0(category, name, id) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \
category, name, id, TRACE_EVENT_FLAG_NONE)
#define TRACE_EVENT_ASYNC_END1(category, name, id, arg1_name, arg1_val) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \
category, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
#define TRACE_EVENT_ASYNC_END2(category, name, id, arg1_name, arg1_val, \
arg2_name, arg2_val) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \
category, name, id, TRACE_EVENT_FLAG_NONE, \
arg1_name, arg1_val, arg2_name, arg2_val)
#define TRACE_EVENT_COPY_ASYNC_END0(category, name, id) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \
category, name, id, TRACE_EVENT_FLAG_COPY)
#define TRACE_EVENT_COPY_ASYNC_END1(category, name, id, arg1_name, arg1_val) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \
category, name, id, TRACE_EVENT_FLAG_COPY, \
arg1_name, arg1_val)
#define TRACE_EVENT_COPY_ASYNC_END2(category, name, id, arg1_name, arg1_val, \
arg2_name, arg2_val) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_ASYNC_END, \
category, name, id, TRACE_EVENT_FLAG_COPY, \
arg1_name, arg1_val, arg2_name, arg2_val)
// Records a single FLOW_BEGIN event called "name" immediately, with 0, 1 or 2
// associated arguments. If the category is not enabled, then this
// does nothing.
// - category and name strings must have application lifetime (statics or
// literals). They may not include " chars.
// - |id| is used to match the FLOW_BEGIN event with the FLOW_END event. FLOW
// events are considered to match if their category, name and id values all
// match. |id| must either be a pointer or an integer value up to 64 bits. If
// it's a pointer, the bits will be xored with a hash of the process ID so
// that the same pointer on two different processes will not collide.
// FLOW events are different from ASYNC events in how they are drawn by the
// tracing UI. A FLOW defines asynchronous data flow, such as posting a task
// (FLOW_BEGIN) and later executing that task (FLOW_END). Expect FLOWs to be
// drawn as lines or arrows from FLOW_BEGIN scopes to FLOW_END scopes. Similar
// to ASYNC, a FLOW can consist of multiple phases. The first phase is defined
// by the FLOW_BEGIN calls. Additional phases can be defined using the FLOW_STEP
// macros. When the operation completes, call FLOW_END. An async operation can
// span threads and processes, but all events in that operation must use the
// same |name| and |id|. Each event can have its own args.
#define TRACE_EVENT_FLOW_BEGIN0(category, name, id) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \
category, name, id, TRACE_EVENT_FLAG_NONE)
#define TRACE_EVENT_FLOW_BEGIN1(category, name, id, arg1_name, arg1_val) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \
category, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
#define TRACE_EVENT_FLOW_BEGIN2(category, name, id, arg1_name, arg1_val, \
arg2_name, arg2_val) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \
category, name, id, TRACE_EVENT_FLAG_NONE, \
arg1_name, arg1_val, arg2_name, arg2_val)
#define TRACE_EVENT_COPY_FLOW_BEGIN0(category, name, id) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \
category, name, id, TRACE_EVENT_FLAG_COPY)
#define TRACE_EVENT_COPY_FLOW_BEGIN1(category, name, id, arg1_name, arg1_val) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \
category, name, id, TRACE_EVENT_FLAG_COPY, \
arg1_name, arg1_val)
#define TRACE_EVENT_COPY_FLOW_BEGIN2(category, name, id, arg1_name, arg1_val, \
arg2_name, arg2_val) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_BEGIN, \
category, name, id, TRACE_EVENT_FLAG_COPY, \
arg1_name, arg1_val, arg2_name, arg2_val)
// Records a single FLOW_STEP event for |step| immediately. If the category
// is not enabled, then this does nothing. The |name| and |id| must match the
// FLOW_BEGIN event above. The |step| param identifies this step within the
// async event. This should be called at the beginning of the next phase of an
// asynchronous operation.
#define TRACE_EVENT_FLOW_STEP0(category, name, id, step) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, \
category, name, id, TRACE_EVENT_FLAG_NONE, "step", step)
#define TRACE_EVENT_FLOW_STEP1(category, name, id, step, \
arg1_name, arg1_val) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, \
category, name, id, TRACE_EVENT_FLAG_NONE, "step", step, \
arg1_name, arg1_val)
#define TRACE_EVENT_COPY_FLOW_STEP0(category, name, id, step) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, \
category, name, id, TRACE_EVENT_FLAG_COPY, "step", step)
#define TRACE_EVENT_COPY_FLOW_STEP1(category, name, id, step, \
arg1_name, arg1_val) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_STEP, \
category, name, id, TRACE_EVENT_FLAG_COPY, "step", step, \
arg1_name, arg1_val)
// Records a single FLOW_END event for "name" immediately. If the category
// is not enabled, then this does nothing.
#define TRACE_EVENT_FLOW_END0(category, name, id) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \
category, name, id, TRACE_EVENT_FLAG_NONE)
#define TRACE_EVENT_FLOW_END1(category, name, id, arg1_name, arg1_val) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \
category, name, id, TRACE_EVENT_FLAG_NONE, arg1_name, arg1_val)
#define TRACE_EVENT_FLOW_END2(category, name, id, arg1_name, arg1_val, \
arg2_name, arg2_val) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \
category, name, id, TRACE_EVENT_FLAG_NONE, \
arg1_name, arg1_val, arg2_name, arg2_val)
#define TRACE_EVENT_COPY_FLOW_END0(category, name, id) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \
category, name, id, TRACE_EVENT_FLAG_COPY)
#define TRACE_EVENT_COPY_FLOW_END1(category, name, id, arg1_name, arg1_val) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \
category, name, id, TRACE_EVENT_FLAG_COPY, \
arg1_name, arg1_val)
#define TRACE_EVENT_COPY_FLOW_END2(category, name, id, arg1_name, arg1_val, \
arg2_name, arg2_val) \
INTERNAL_TRACE_EVENT_ADD_WITH_ID(TRACE_EVENT_PHASE_FLOW_END, \
category, name, id, TRACE_EVENT_FLAG_COPY, \
arg1_name, arg1_val, arg2_name, arg2_val)
////////////////////////////////////////////////////////////////////////////////
// Implementation specific tracing API definitions.
// Get a pointer to the enabled state of the given trace category. Only
// long-lived literal strings should be given as the category name. The returned
// pointer can be held permanently in a local static for example. If the
// unsigned char is non-zero, tracing is enabled. If tracing is enabled,
// TRACE_EVENT_API_ADD_TRACE_EVENT can be called. It's OK if tracing is disabled
// between the load of the tracing state and the call to
// TRACE_EVENT_API_ADD_TRACE_EVENT, because this flag only provides an early out
// for best performance when tracing is disabled.
// const unsigned char*
// TRACE_EVENT_API_GET_CATEGORY_ENABLED(const char* category_name)
#define TRACE_EVENT_API_GET_CATEGORY_ENABLED \
webrtc::EventTracer::GetCategoryEnabled
// Add a trace event to the platform tracing system.
// void TRACE_EVENT_API_ADD_TRACE_EVENT(
// char phase,
// const unsigned char* category_enabled,
// const char* name,
// unsigned long long id,
// int num_args,
// const char** arg_names,
// const unsigned char* arg_types,
// const unsigned long long* arg_values,
// unsigned char flags)
#define TRACE_EVENT_API_ADD_TRACE_EVENT webrtc::EventTracer::AddTraceEvent
////////////////////////////////////////////////////////////////////////////////
// Implementation detail: trace event macros create temporary variables
// to keep instrumentation overhead low. These macros give each temporary
// variable a unique name based on the line number to prevent name collissions.
#define INTERNAL_TRACE_EVENT_UID3(a,b) \
trace_event_unique_##a##b
#define INTERNAL_TRACE_EVENT_UID2(a,b) \
INTERNAL_TRACE_EVENT_UID3(a,b)
#define INTERNAL_TRACE_EVENT_UID(name_prefix) \
INTERNAL_TRACE_EVENT_UID2(name_prefix, __LINE__)
// Implementation detail: internal macro to create static category.
#define INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category) \
static const unsigned char* INTERNAL_TRACE_EVENT_UID(catstatic) = 0; \
if (!INTERNAL_TRACE_EVENT_UID(catstatic)) { \
INTERNAL_TRACE_EVENT_UID(catstatic) = \
TRACE_EVENT_API_GET_CATEGORY_ENABLED(category); \
}
// Implementation detail: internal macro to create static category and add
// event if the category is enabled.
#define INTERNAL_TRACE_EVENT_ADD(phase, category, name, flags, ...) \
do { \
INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category); \
if (*INTERNAL_TRACE_EVENT_UID(catstatic)) { \
webrtc::trace_event_internal::AddTraceEvent( \
phase, INTERNAL_TRACE_EVENT_UID(catstatic), name, \
webrtc::trace_event_internal::kNoEventId, flags, ##__VA_ARGS__); \
} \
} while (0)
// Implementation detail: internal macro to create static category and add begin
// event if the category is enabled. Also adds the end event when the scope
// ends.
#define INTERNAL_TRACE_EVENT_ADD_SCOPED(category, name, ...) \
INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category); \
webrtc::trace_event_internal::TraceEndOnScopeClose \
INTERNAL_TRACE_EVENT_UID(profileScope); \
if (*INTERNAL_TRACE_EVENT_UID(catstatic)) { \
webrtc::trace_event_internal::AddTraceEvent( \
TRACE_EVENT_PHASE_BEGIN, \
INTERNAL_TRACE_EVENT_UID(catstatic), \
name, webrtc::trace_event_internal::kNoEventId, \
TRACE_EVENT_FLAG_NONE, ##__VA_ARGS__); \
INTERNAL_TRACE_EVENT_UID(profileScope).Initialize( \
INTERNAL_TRACE_EVENT_UID(catstatic), name); \
}
// Implementation detail: internal macro to create static category and add
// event if the category is enabled.
#define INTERNAL_TRACE_EVENT_ADD_WITH_ID(phase, category, name, id, flags, \
...) \
do { \
INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category); \
if (*INTERNAL_TRACE_EVENT_UID(catstatic)) { \
unsigned char trace_event_flags = flags | TRACE_EVENT_FLAG_HAS_ID; \
webrtc::trace_event_internal::TraceID trace_event_trace_id( \
id, &trace_event_flags); \
webrtc::trace_event_internal::AddTraceEvent( \
phase, INTERNAL_TRACE_EVENT_UID(catstatic), \
name, trace_event_trace_id.data(), trace_event_flags, \
##__VA_ARGS__); \
} \
} while (0)
// Notes regarding the following definitions:
// New values can be added and propagated to third party libraries, but existing
// definitions must never be changed, because third party libraries may use old
// definitions.
// Phase indicates the nature of an event entry. E.g. part of a begin/end pair.
#define TRACE_EVENT_PHASE_BEGIN ('B')
#define TRACE_EVENT_PHASE_END ('E')
#define TRACE_EVENT_PHASE_INSTANT ('I')
#define TRACE_EVENT_PHASE_ASYNC_BEGIN ('S')
#define TRACE_EVENT_PHASE_ASYNC_STEP ('T')
#define TRACE_EVENT_PHASE_ASYNC_END ('F')
#define TRACE_EVENT_PHASE_FLOW_BEGIN ('s')
#define TRACE_EVENT_PHASE_FLOW_STEP ('t')
#define TRACE_EVENT_PHASE_FLOW_END ('f')
#define TRACE_EVENT_PHASE_METADATA ('M')
#define TRACE_EVENT_PHASE_COUNTER ('C')
// Flags for changing the behavior of TRACE_EVENT_API_ADD_TRACE_EVENT.
#define TRACE_EVENT_FLAG_NONE (static_cast<unsigned char>(0))
#define TRACE_EVENT_FLAG_COPY (static_cast<unsigned char>(1 << 0))
#define TRACE_EVENT_FLAG_HAS_ID (static_cast<unsigned char>(1 << 1))
#define TRACE_EVENT_FLAG_MANGLE_ID (static_cast<unsigned char>(1 << 2))
// Type values for identifying types in the TraceValue union.
#define TRACE_VALUE_TYPE_BOOL (static_cast<unsigned char>(1))
#define TRACE_VALUE_TYPE_UINT (static_cast<unsigned char>(2))
#define TRACE_VALUE_TYPE_INT (static_cast<unsigned char>(3))
#define TRACE_VALUE_TYPE_DOUBLE (static_cast<unsigned char>(4))
#define TRACE_VALUE_TYPE_POINTER (static_cast<unsigned char>(5))
#define TRACE_VALUE_TYPE_STRING (static_cast<unsigned char>(6))
#define TRACE_VALUE_TYPE_COPY_STRING (static_cast<unsigned char>(7))
namespace webrtc {
namespace trace_event_internal {
// Specify these values when the corresponding argument of AddTraceEvent is not
// used.
const int kZeroNumArgs = 0;
const unsigned long long kNoEventId = 0;
// TraceID encapsulates an ID that can either be an integer or pointer. Pointers
// are mangled with the Process ID so that they are unlikely to collide when the
// same pointer is used on different processes.
class TraceID {
public:
class ForceMangle {
public:
explicit ForceMangle(unsigned long long id) : data_(id) {}
explicit ForceMangle(unsigned long id) : data_(id) {}
explicit ForceMangle(unsigned int id) : data_(id) {}
explicit ForceMangle(unsigned short id) : data_(id) {}
explicit ForceMangle(unsigned char id) : data_(id) {}
explicit ForceMangle(long long id)
: data_(static_cast<unsigned long long>(id)) {}
explicit ForceMangle(long id)
: data_(static_cast<unsigned long long>(id)) {}
explicit ForceMangle(int id)
: data_(static_cast<unsigned long long>(id)) {}
explicit ForceMangle(short id)
: data_(static_cast<unsigned long long>(id)) {}
explicit ForceMangle(signed char id)
: data_(static_cast<unsigned long long>(id)) {}
unsigned long long data() const { return data_; }
private:
unsigned long long data_;
};
explicit TraceID(const void* id, unsigned char* flags)
: data_(static_cast<unsigned long long>(
reinterpret_cast<unsigned long>(id))) {
*flags |= TRACE_EVENT_FLAG_MANGLE_ID;
}
explicit TraceID(ForceMangle id, unsigned char* flags) : data_(id.data()) {
*flags |= TRACE_EVENT_FLAG_MANGLE_ID;
}
explicit TraceID(unsigned long long id, unsigned char* flags)
: data_(id) { (void)flags; }
explicit TraceID(unsigned long id, unsigned char* flags)
: data_(id) { (void)flags; }
explicit TraceID(unsigned int id, unsigned char* flags)
: data_(id) { (void)flags; }
explicit TraceID(unsigned short id, unsigned char* flags)
: data_(id) { (void)flags; }
explicit TraceID(unsigned char id, unsigned char* flags)
: data_(id) { (void)flags; }
explicit TraceID(long long id, unsigned char* flags)
: data_(static_cast<unsigned long long>(id)) { (void)flags; }
explicit TraceID(long id, unsigned char* flags)
: data_(static_cast<unsigned long long>(id)) { (void)flags; }
explicit TraceID(int id, unsigned char* flags)
: data_(static_cast<unsigned long long>(id)) { (void)flags; }
explicit TraceID(short id, unsigned char* flags)
: data_(static_cast<unsigned long long>(id)) { (void)flags; }
explicit TraceID(signed char id, unsigned char* flags)
: data_(static_cast<unsigned long long>(id)) { (void)flags; }
unsigned long long data() const { return data_; }
private:
unsigned long long data_;
};
// Simple union to store various types as unsigned long long.
union TraceValueUnion {
bool as_bool;
unsigned long long as_uint;
long long as_int;
double as_double;
const void* as_pointer;
const char* as_string;
};
// Simple container for const char* that should be copied instead of retained.
class TraceStringWithCopy {
public:
explicit TraceStringWithCopy(const char* str) : str_(str) {}
operator const char* () const { return str_; }
private:
const char* str_;
};
// Define SetTraceValue for each allowed type. It stores the type and
// value in the return arguments. This allows this API to avoid declaring any
// structures so that it is portable to third_party libraries.
#define INTERNAL_DECLARE_SET_TRACE_VALUE(actual_type, \
union_member, \
value_type_id) \
static inline void SetTraceValue(actual_type arg, \
unsigned char* type, \
unsigned long long* value) { \
TraceValueUnion type_value; \
type_value.union_member = arg; \
*type = value_type_id; \
*value = type_value.as_uint; \
}
// Simpler form for int types that can be safely casted.
#define INTERNAL_DECLARE_SET_TRACE_VALUE_INT(actual_type, \
value_type_id) \
static inline void SetTraceValue(actual_type arg, \
unsigned char* type, \
unsigned long long* value) { \
*type = value_type_id; \
*value = static_cast<unsigned long long>(arg); \
}
INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned long long, TRACE_VALUE_TYPE_UINT)
INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned long, TRACE_VALUE_TYPE_UINT)
INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned int, TRACE_VALUE_TYPE_UINT)
INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned short, TRACE_VALUE_TYPE_UINT)
INTERNAL_DECLARE_SET_TRACE_VALUE_INT(unsigned char, TRACE_VALUE_TYPE_UINT)
INTERNAL_DECLARE_SET_TRACE_VALUE_INT(long long, TRACE_VALUE_TYPE_INT)
INTERNAL_DECLARE_SET_TRACE_VALUE_INT(long, TRACE_VALUE_TYPE_INT)
INTERNAL_DECLARE_SET_TRACE_VALUE_INT(int, TRACE_VALUE_TYPE_INT)
INTERNAL_DECLARE_SET_TRACE_VALUE_INT(short, TRACE_VALUE_TYPE_INT)
INTERNAL_DECLARE_SET_TRACE_VALUE_INT(signed char, TRACE_VALUE_TYPE_INT)
INTERNAL_DECLARE_SET_TRACE_VALUE(bool, as_bool, TRACE_VALUE_TYPE_BOOL)
INTERNAL_DECLARE_SET_TRACE_VALUE(double, as_double, TRACE_VALUE_TYPE_DOUBLE)
INTERNAL_DECLARE_SET_TRACE_VALUE(const void*, as_pointer,
TRACE_VALUE_TYPE_POINTER)
INTERNAL_DECLARE_SET_TRACE_VALUE(const char*, as_string,
TRACE_VALUE_TYPE_STRING)
INTERNAL_DECLARE_SET_TRACE_VALUE(const TraceStringWithCopy&, as_string,
TRACE_VALUE_TYPE_COPY_STRING)
#undef INTERNAL_DECLARE_SET_TRACE_VALUE
#undef INTERNAL_DECLARE_SET_TRACE_VALUE_INT
// std::string version of SetTraceValue so that trace arguments can be strings.
static inline void SetTraceValue(const std::string& arg,
unsigned char* type,
unsigned long long* value) {
TraceValueUnion type_value;
type_value.as_string = arg.c_str();
*type = TRACE_VALUE_TYPE_COPY_STRING;
*value = type_value.as_uint;
}
// These AddTraceEvent template functions are defined here instead of in the
// macro, because the arg_values could be temporary objects, such as
// std::string. In order to store pointers to the internal c_str and pass
// through to the tracing API, the arg_values must live throughout
// these procedures.
static inline void AddTraceEvent(char phase,
const unsigned char* category_enabled,
const char* name,
unsigned long long id,
unsigned char flags) {
TRACE_EVENT_API_ADD_TRACE_EVENT(
phase, category_enabled, name, id,
kZeroNumArgs, NULL, NULL, NULL,
flags);
}
template<class ARG1_TYPE>
static inline void AddTraceEvent(char phase,
const unsigned char* category_enabled,
const char* name,
unsigned long long id,
unsigned char flags,
const char* arg1_name,
const ARG1_TYPE& arg1_val) {
const int num_args = 1;
unsigned char arg_types[1];
unsigned long long arg_values[1];
SetTraceValue(arg1_val, &arg_types[0], &arg_values[0]);
TRACE_EVENT_API_ADD_TRACE_EVENT(
phase, category_enabled, name, id,
num_args, &arg1_name, arg_types, arg_values,
flags);
}
template<class ARG1_TYPE, class ARG2_TYPE>
static inline void AddTraceEvent(char phase,
const unsigned char* category_enabled,
const char* name,
unsigned long long id,
unsigned char flags,
const char* arg1_name,
const ARG1_TYPE& arg1_val,
const char* arg2_name,
const ARG2_TYPE& arg2_val) {
const int num_args = 2;
const char* arg_names[2] = { arg1_name, arg2_name };
unsigned char arg_types[2];
unsigned long long arg_values[2];
SetTraceValue(arg1_val, &arg_types[0], &arg_values[0]);
SetTraceValue(arg2_val, &arg_types[1], &arg_values[1]);
TRACE_EVENT_API_ADD_TRACE_EVENT(
phase, category_enabled, name, id,
num_args, arg_names, arg_types, arg_values,
flags);
}
// Used by TRACE_EVENTx macro. Do not use directly.
class TraceEndOnScopeClose {
public:
// Note: members of data_ intentionally left uninitialized. See Initialize.
TraceEndOnScopeClose() : p_data_(NULL) {}
~TraceEndOnScopeClose() {
if (p_data_)
AddEventIfEnabled();
}
void Initialize(const unsigned char* category_enabled,
const char* name) {
data_.category_enabled = category_enabled;
data_.name = name;
p_data_ = &data_;
}
private:
// Add the end event if the category is still enabled.
void AddEventIfEnabled() {
// Only called when p_data_ is non-null.
if (*p_data_->category_enabled) {
TRACE_EVENT_API_ADD_TRACE_EVENT(
TRACE_EVENT_PHASE_END,
p_data_->category_enabled,
p_data_->name, kNoEventId,
kZeroNumArgs, NULL, NULL, NULL,
TRACE_EVENT_FLAG_NONE);
}
}
// This Data struct workaround is to avoid initializing all the members
// in Data during construction of this object, since this object is always
// constructed, even when tracing is disabled. If the members of Data were
// members of this class instead, compiler warnings occur about potential
// uninitialized accesses.
struct Data {
const unsigned char* category_enabled;
const char* name;
};
Data* p_data_;
Data data_;
};
} // namespace trace_event_internal
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_TRACE_EVENT_H_

View File

@@ -0,0 +1,57 @@
/*
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// Conversion functions for UTF-8 and UTF-16 strings on Windows.
// Duplicated from talk/base/win32.h.
#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_UTF_UTIL_H_
#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_UTF_UTIL_H_
#ifdef WIN32
#include <windows.h>
#include <string>
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
namespace webrtc {
inline std::wstring ToUtf16(const char* utf8, size_t len) {
int len16 = ::MultiByteToWideChar(CP_UTF8, 0, utf8, static_cast<int>(len),
NULL, 0);
scoped_ptr<wchar_t[]> ws(new wchar_t[len16]);
::MultiByteToWideChar(CP_UTF8, 0, utf8, static_cast<int>(len), ws.get(),
len16);
return std::wstring(ws.get(), len16);
}
inline std::wstring ToUtf16(const std::string& str) {
return ToUtf16(str.data(), str.length());
}
inline std::string ToUtf8(const wchar_t* wide, size_t len) {
int len8 = ::WideCharToMultiByte(CP_UTF8, 0, wide, static_cast<int>(len),
NULL, 0, NULL, NULL);
scoped_ptr<char[]> ns(new char[len8]);
::WideCharToMultiByte(CP_UTF8, 0, wide, static_cast<int>(len), ns.get(), len8,
NULL, NULL);
return std::string(ns.get(), len8);
}
inline std::string ToUtf8(const wchar_t* wide) {
return ToUtf8(wide, wcslen(wide));
}
inline std::string ToUtf8(const std::wstring& wstr) {
return ToUtf8(wstr.data(), wstr.length());
}
} // namespace webrtc
#endif // WIN32
#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_UTF_UTIL_H_

View File

@@ -0,0 +1,68 @@
# Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
#
# Use of this source code is governed by a BSD-style license
# that can be found in the LICENSE file in the root of the source
# tree. An additional intellectual property rights grant can be found
# in the file PATENTS. All contributing project authors may
# be found in the AUTHORS file in the root of the source tree.
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
include $(LOCAL_PATH)/../../../android-webrtc.mk
LOCAL_ARM_MODE := arm
LOCAL_MODULE := libwebrtc_system_wrappers
LOCAL_MODULE_TAGS := optional
LOCAL_CPP_EXTENSION := .cc
LOCAL_SRC_FILES := \
cpu_features_android.c \
sort.cc \
aligned_malloc.cc \
atomic32_posix.cc \
condition_variable.cc \
cpu_features.cc \
cpu_info.cc \
critical_section.cc \
event.cc \
event_tracer.cc \
file_impl.cc \
rw_lock.cc \
thread.cc \
trace_impl.cc \
condition_variable_posix.cc \
critical_section_posix.cc \
event_posix.cc \
rtp_to_ntp.cc \
sleep.cc \
thread_posix.cc \
tick_util.cc \
timestamp_extrapolator.cc \
trace_posix.cc \
rw_lock_generic.cc \
rw_lock_posix.cc \
logging.cc
LOCAL_CFLAGS := \
$(MY_WEBRTC_COMMON_DEFS)
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/../.. \
$(LOCAL_PATH)/../interface \
$(LOCAL_PATH)/spreadsortlib \
$(LOCAL_PATH)/../../..
LOCAL_SHARED_LIBRARIES := \
libcutils \
libdl \
libstlport
LOCAL_STATIC_LIBRARIES := cpufeatures
ifndef NDK_ROOT
include external/stlport/libstlport.mk
endif
include $(BUILD_STATIC_LIBRARY)
$(call import-module,android/cpufeatures)

View File

@@ -0,0 +1,6 @@
per-file *.isolate=kjellander@webrtc.org
# These are for the common case of adding or renaming files. If you're doing
# structural changes, please get a review from a reviewer in this file.
per-file *.gyp=*
per-file *.gypi=*

View File

@@ -0,0 +1,100 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/system_wrappers/interface/aligned_malloc.h"
#include <memory.h>
#include <stdlib.h>
#if _WIN32
#include <windows.h>
#else
#include <stdint.h>
#endif
#include "webrtc/typedefs.h"
// Reference on memory alignment:
// http://stackoverflow.com/questions/227897/solve-the-memory-alignment-in-c-interview-question-that-stumped-me
namespace webrtc {
uintptr_t GetRightAlign(uintptr_t start_pos, size_t alignment) {
// The pointer should be aligned with |alignment| bytes. The - 1 guarantees
// that it is aligned towards the closest higher (right) address.
return (start_pos + alignment - 1) & ~(alignment - 1);
}
// Alignment must be an integer power of two.
bool ValidAlignment(size_t alignment) {
if (!alignment) {
return false;
}
return (alignment & (alignment - 1)) == 0;
}
void* GetRightAlign(const void* pointer, size_t alignment) {
if (!pointer) {
return NULL;
}
if (!ValidAlignment(alignment)) {
return NULL;
}
uintptr_t start_pos = reinterpret_cast<uintptr_t>(pointer);
return reinterpret_cast<void*>(GetRightAlign(start_pos, alignment));
}
void* AlignedMalloc(size_t size, size_t alignment) {
if (size == 0) {
return NULL;
}
if (!ValidAlignment(alignment)) {
return NULL;
}
// The memory is aligned towards the lowest address that so only
// alignment - 1 bytes needs to be allocated.
// A pointer to the start of the memory must be stored so that it can be
// retreived for deletion, ergo the sizeof(uintptr_t).
void* memory_pointer = malloc(size + sizeof(uintptr_t) + alignment - 1);
if (memory_pointer == NULL) {
return NULL;
}
// Aligning after the sizeof(uintptr_t) bytes will leave room for the header
// in the same memory block.
uintptr_t align_start_pos = reinterpret_cast<uintptr_t>(memory_pointer);
align_start_pos += sizeof(uintptr_t);
uintptr_t aligned_pos = GetRightAlign(align_start_pos, alignment);
void* aligned_pointer = reinterpret_cast<void*>(aligned_pos);
// Store the address to the beginning of the memory just before the aligned
// memory.
uintptr_t header_pos = aligned_pos - sizeof(uintptr_t);
void* header_pointer = reinterpret_cast<void*>(header_pos);
uintptr_t memory_start = reinterpret_cast<uintptr_t>(memory_pointer);
memcpy(header_pointer, &memory_start, sizeof(uintptr_t));
return aligned_pointer;
}
void AlignedFree(void* mem_block) {
if (mem_block == NULL) {
return;
}
uintptr_t aligned_pos = reinterpret_cast<uintptr_t>(mem_block);
uintptr_t header_pos = aligned_pos - sizeof(uintptr_t);
// Read out the address of the AlignedMemory struct from the header.
uintptr_t memory_start_pos = *reinterpret_cast<uintptr_t*>(header_pos);
void* memory_start = reinterpret_cast<void*>(memory_start_pos);
free(memory_start);
}
} // namespace webrtc

View File

@@ -0,0 +1,82 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/system_wrappers/interface/aligned_malloc.h"
#if _WIN32
#include <windows.h>
#else
#include <stdint.h>
#endif
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
#include "webrtc/typedefs.h"
namespace webrtc {
// Returns true if |size| and |alignment| are valid combinations.
bool CorrectUsage(size_t size, size_t alignment) {
scoped_ptr<char, AlignedFreeDeleter> scoped(
static_cast<char*>(AlignedMalloc(size, alignment)));
if (scoped.get() == NULL) {
return false;
}
const uintptr_t scoped_address = reinterpret_cast<uintptr_t> (scoped.get());
return 0u == scoped_address % alignment;
}
TEST(AlignedMalloc, GetRightAlign) {
const size_t size = 100;
const size_t alignment = 32;
const size_t left_misalignment = 1;
scoped_ptr<char, AlignedFreeDeleter> scoped(
static_cast<char*>(AlignedMalloc(size, alignment)));
EXPECT_TRUE(scoped.get() != NULL);
const uintptr_t aligned_address = reinterpret_cast<uintptr_t> (scoped.get());
const uintptr_t misaligned_address = aligned_address - left_misalignment;
const char* misaligned_ptr = reinterpret_cast<const char*>(
misaligned_address);
const char* realigned_ptr = GetRightAlign(misaligned_ptr, alignment);
EXPECT_EQ(scoped.get(), realigned_ptr);
}
TEST(AlignedMalloc, IncorrectSize) {
const size_t incorrect_size = 0;
const size_t alignment = 64;
EXPECT_FALSE(CorrectUsage(incorrect_size, alignment));
}
TEST(AlignedMalloc, IncorrectAlignment) {
const size_t size = 100;
const size_t incorrect_alignment = 63;
EXPECT_FALSE(CorrectUsage(size, incorrect_alignment));
}
TEST(AlignedMalloc, AlignTo2Bytes) {
size_t size = 100;
size_t alignment = 2;
EXPECT_TRUE(CorrectUsage(size, alignment));
}
TEST(AlignedMalloc, AlignTo32Bytes) {
size_t size = 100;
size_t alignment = 32;
EXPECT_TRUE(CorrectUsage(size, alignment));
}
TEST(AlignedMalloc, AlignTo128Bytes) {
size_t size = 100;
size_t alignment = 128;
EXPECT_TRUE(CorrectUsage(size, alignment));
}
} // namespace webrtc

View File

@@ -0,0 +1,49 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/system_wrappers/interface/atomic32.h"
#include <assert.h>
#include <libkern/OSAtomic.h>
#include <stdlib.h>
#include "webrtc/common_types.h"
namespace webrtc {
Atomic32::Atomic32(int32_t initial_value)
: value_(initial_value) {
assert(Is32bitAligned());
}
Atomic32::~Atomic32() {
}
int32_t Atomic32::operator++() {
return OSAtomicIncrement32Barrier(&value_);
}
int32_t Atomic32::operator--() {
return OSAtomicDecrement32Barrier(&value_);
}
int32_t Atomic32::operator+=(int32_t value) {
return OSAtomicAdd32Barrier(value, &value_);
}
int32_t Atomic32::operator-=(int32_t value) {
return OSAtomicAdd32Barrier(-value, &value_);
}
bool Atomic32::CompareExchange(int32_t new_value, int32_t compare_value) {
return OSAtomicCompareAndSwap32Barrier(compare_value, new_value, &value_);
}
} // namespace webrtc

View File

@@ -0,0 +1,53 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/system_wrappers/interface/atomic32.h"
#include <assert.h>
#include <inttypes.h>
#include <malloc.h>
#include "webrtc/common_types.h"
namespace webrtc {
Atomic32::Atomic32(int32_t initial_value)
: value_(initial_value) {
assert(Is32bitAligned());
}
Atomic32::~Atomic32() {
}
int32_t Atomic32::operator++() {
return __sync_fetch_and_add(&value_, 1) + 1;
}
int32_t Atomic32::operator--() {
return __sync_fetch_and_sub(&value_, 1) - 1;
}
int32_t Atomic32::operator+=(int32_t value) {
int32_t return_value = __sync_fetch_and_add(&value_, value);
return_value += value;
return return_value;
}
int32_t Atomic32::operator-=(int32_t value) {
int32_t return_value = __sync_fetch_and_sub(&value_, value);
return_value -= value;
return return_value;
}
bool Atomic32::CompareExchange(int32_t new_value, int32_t compare_value) {
return __sync_bool_compare_and_swap(&value_, compare_value, new_value);
}
} // namespace webrtc

View File

@@ -0,0 +1,61 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/system_wrappers/interface/atomic32.h"
#include <assert.h>
#include <windows.h>
#include "webrtc/common_types.h"
#include "webrtc/system_wrappers/interface/compile_assert.h"
namespace webrtc {
Atomic32::Atomic32(int32_t initial_value)
: value_(initial_value) {
COMPILE_ASSERT(sizeof(value_) == sizeof(LONG),
counter_variable_is_the_expected_size);
assert(Is32bitAligned());
}
Atomic32::~Atomic32() {
}
int32_t Atomic32::operator++() {
return static_cast<int32_t>(InterlockedIncrement(
reinterpret_cast<volatile LONG*>(&value_)));
}
int32_t Atomic32::operator--() {
return static_cast<int32_t>(InterlockedDecrement(
reinterpret_cast<volatile LONG*>(&value_)));
}
int32_t Atomic32::operator+=(int32_t value) {
return InterlockedExchangeAdd(reinterpret_cast<volatile LONG*>(&value_),
value);
}
int32_t Atomic32::operator-=(int32_t value) {
return InterlockedExchangeAdd(reinterpret_cast<volatile LONG*>(&value_),
-value);
}
bool Atomic32::CompareExchange(int32_t new_value, int32_t compare_value) {
const LONG old_value = InterlockedCompareExchange(
reinterpret_cast<volatile LONG*>(&value_),
new_value,
compare_value);
// If the old value and the compare value is the same an exchange happened.
return (old_value == compare_value);
}
} // namespace webrtc

View File

@@ -0,0 +1,304 @@
/*
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/system_wrappers/interface/clock.h"
#if defined(_WIN32)
// Windows needs to be included before mmsystem.h
#include <Windows.h>
#include <WinSock.h>
#include <MMSystem.h>
#elif ((defined WEBRTC_LINUX) || (defined WEBRTC_MAC))
#include <sys/time.h>
#include <time.h>
#endif
#include "webrtc/system_wrappers/interface/rw_lock_wrapper.h"
#include "webrtc/system_wrappers/interface/tick_util.h"
namespace webrtc {
const double kNtpFracPerMs = 4.294967296E6;
int64_t Clock::NtpToMs(uint32_t ntp_secs, uint32_t ntp_frac) {
const double ntp_frac_ms = static_cast<double>(ntp_frac) / kNtpFracPerMs;
return 1000 * static_cast<int64_t>(ntp_secs) +
static_cast<int64_t>(ntp_frac_ms + 0.5);
}
#if defined(_WIN32)
struct reference_point {
FILETIME file_time;
LARGE_INTEGER counterMS;
};
struct WindowsHelpTimer {
volatile LONG _timeInMs;
volatile LONG _numWrapTimeInMs;
reference_point _ref_point;
volatile LONG _sync_flag;
};
void Synchronize(WindowsHelpTimer* help_timer) {
const LONG start_value = 0;
const LONG new_value = 1;
const LONG synchronized_value = 2;
LONG compare_flag = new_value;
while (help_timer->_sync_flag == start_value) {
const LONG new_value = 1;
compare_flag = InterlockedCompareExchange(
&help_timer->_sync_flag, new_value, start_value);
}
if (compare_flag != start_value) {
// This thread was not the one that incremented the sync flag.
// Block until synchronization finishes.
while (compare_flag != synchronized_value) {
::Sleep(0);
}
return;
}
// Only the synchronizing thread gets here so this part can be
// considered single threaded.
// set timer accuracy to 1 ms
timeBeginPeriod(1);
FILETIME ft0 = { 0, 0 },
ft1 = { 0, 0 };
//
// Spin waiting for a change in system time. Get the matching
// performance counter value for that time.
//
::GetSystemTimeAsFileTime(&ft0);
do {
::GetSystemTimeAsFileTime(&ft1);
help_timer->_ref_point.counterMS.QuadPart = ::timeGetTime();
::Sleep(0);
} while ((ft0.dwHighDateTime == ft1.dwHighDateTime) &&
(ft0.dwLowDateTime == ft1.dwLowDateTime));
help_timer->_ref_point.file_time = ft1;
timeEndPeriod(1);
}
void get_time(WindowsHelpTimer* help_timer, FILETIME& current_time) {
// we can't use query performance counter due to speed stepping
DWORD t = timeGetTime();
// NOTE: we have a missmatch in sign between _timeInMs(LONG) and
// (DWORD) however we only use it here without +- etc
volatile LONG* timeInMsPtr = &help_timer->_timeInMs;
// Make sure that we only inc wrapper once.
DWORD old = InterlockedExchange(timeInMsPtr, t);
if(old > t) {
// wrap
help_timer->_numWrapTimeInMs++;
}
LARGE_INTEGER elapsedMS;
elapsedMS.HighPart = help_timer->_numWrapTimeInMs;
elapsedMS.LowPart = t;
elapsedMS.QuadPart = elapsedMS.QuadPart -
help_timer->_ref_point.counterMS.QuadPart;
// Translate to 100-nanoseconds intervals (FILETIME resolution)
// and add to reference FILETIME to get current FILETIME.
ULARGE_INTEGER filetime_ref_as_ul;
filetime_ref_as_ul.HighPart =
help_timer->_ref_point.file_time.dwHighDateTime;
filetime_ref_as_ul.LowPart =
help_timer->_ref_point.file_time.dwLowDateTime;
filetime_ref_as_ul.QuadPart +=
(ULONGLONG)((elapsedMS.QuadPart)*1000*10);
// Copy to result
current_time.dwHighDateTime = filetime_ref_as_ul.HighPart;
current_time.dwLowDateTime = filetime_ref_as_ul.LowPart;
}
#endif
class RealTimeClock : public Clock {
// Return a timestamp in milliseconds relative to some arbitrary source; the
// source is fixed for this clock.
virtual int64_t TimeInMilliseconds() const OVERRIDE {
return TickTime::MillisecondTimestamp();
}
// Return a timestamp in microseconds relative to some arbitrary source; the
// source is fixed for this clock.
virtual int64_t TimeInMicroseconds() const OVERRIDE {
return TickTime::MicrosecondTimestamp();
}
// Retrieve an NTP absolute timestamp in seconds and fractions of a second.
virtual void CurrentNtp(uint32_t& seconds,
uint32_t& fractions) const OVERRIDE {
timeval tv = CurrentTimeVal();
double microseconds_in_seconds;
Adjust(tv, &seconds, &microseconds_in_seconds);
fractions = static_cast<uint32_t>(
microseconds_in_seconds * kMagicNtpFractionalUnit + 0.5);
}
// Retrieve an NTP absolute timestamp in milliseconds.
virtual int64_t CurrentNtpInMilliseconds() const OVERRIDE {
timeval tv = CurrentTimeVal();
uint32_t seconds;
double microseconds_in_seconds;
Adjust(tv, &seconds, &microseconds_in_seconds);
return 1000 * static_cast<int64_t>(seconds) +
static_cast<int64_t>(1000.0 * microseconds_in_seconds + 0.5);
}
protected:
virtual timeval CurrentTimeVal() const = 0;
static void Adjust(const timeval& tv, uint32_t* adjusted_s,
double* adjusted_us_in_s) {
*adjusted_s = tv.tv_sec + kNtpJan1970;
*adjusted_us_in_s = tv.tv_usec / 1e6;
if (*adjusted_us_in_s >= 1) {
*adjusted_us_in_s -= 1;
++*adjusted_s;
} else if (*adjusted_us_in_s < -1) {
*adjusted_us_in_s += 1;
--*adjusted_s;
}
}
};
#if defined(_WIN32)
class WindowsRealTimeClock : public RealTimeClock {
public:
WindowsRealTimeClock(WindowsHelpTimer* helpTimer)
: _helpTimer(helpTimer) {}
virtual ~WindowsRealTimeClock() {}
protected:
virtual timeval CurrentTimeVal() const OVERRIDE {
const uint64_t FILETIME_1970 = 0x019db1ded53e8000;
FILETIME StartTime;
uint64_t Time;
struct timeval tv;
// We can't use query performance counter since they can change depending on
// speed stepping.
get_time(_helpTimer, StartTime);
Time = (((uint64_t) StartTime.dwHighDateTime) << 32) +
(uint64_t) StartTime.dwLowDateTime;
// Convert the hecto-nano second time to tv format.
Time -= FILETIME_1970;
tv.tv_sec = (uint32_t)(Time / (uint64_t)10000000);
tv.tv_usec = (uint32_t)((Time % (uint64_t)10000000) / 10);
return tv;
}
WindowsHelpTimer* _helpTimer;
};
#elif ((defined WEBRTC_LINUX) || (defined WEBRTC_MAC))
class UnixRealTimeClock : public RealTimeClock {
public:
UnixRealTimeClock() {}
virtual ~UnixRealTimeClock() {}
protected:
virtual timeval CurrentTimeVal() const OVERRIDE {
struct timeval tv;
struct timezone tz;
tz.tz_minuteswest = 0;
tz.tz_dsttime = 0;
gettimeofday(&tv, &tz);
return tv;
}
};
#endif
#if defined(_WIN32)
// Keeps the global state for the Windows implementation of RtpRtcpClock.
// Note that this is a POD. Only PODs are allowed to have static storage
// duration according to the Google Style guide.
//
// Note that on Windows, GetSystemTimeAsFileTime has poorer (up to 15 ms)
// resolution than the media timers, hence the WindowsHelpTimer context
// object and Synchronize API to sync the two.
//
// We only sync up once, which means that on Windows, our realtime clock
// wont respond to system time/date changes without a program restart.
// TODO(henrike): We should probably call sync more often to catch
// drift and time changes for parity with other platforms.
static WindowsHelpTimer *SyncGlobalHelpTimer() {
static WindowsHelpTimer global_help_timer = {0, 0, {{ 0, 0}, 0}, 0};
Synchronize(&global_help_timer);
return &global_help_timer;
}
#endif
Clock* Clock::GetRealTimeClock() {
#if defined(_WIN32)
static WindowsRealTimeClock clock(SyncGlobalHelpTimer());
return &clock;
#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
static UnixRealTimeClock clock;
return &clock;
#else
return NULL;
#endif
}
SimulatedClock::SimulatedClock(int64_t initial_time_us)
: time_us_(initial_time_us), lock_(RWLockWrapper::CreateRWLock()) {
}
SimulatedClock::~SimulatedClock() {
}
int64_t SimulatedClock::TimeInMilliseconds() const {
ReadLockScoped synchronize(*lock_);
return (time_us_ + 500) / 1000;
}
int64_t SimulatedClock::TimeInMicroseconds() const {
ReadLockScoped synchronize(*lock_);
return time_us_;
}
void SimulatedClock::CurrentNtp(uint32_t& seconds, uint32_t& fractions) const {
int64_t now_ms = TimeInMilliseconds();
seconds = (now_ms / 1000) + kNtpJan1970;
fractions =
static_cast<uint32_t>((now_ms % 1000) * kMagicNtpFractionalUnit / 1000);
}
int64_t SimulatedClock::CurrentNtpInMilliseconds() const {
return TimeInMilliseconds() + 1000 * static_cast<int64_t>(kNtpJan1970);
}
void SimulatedClock::AdvanceTimeMilliseconds(int64_t milliseconds) {
AdvanceTimeMicroseconds(1000 * milliseconds);
}
void SimulatedClock::AdvanceTimeMicroseconds(int64_t microseconds) {
WriteLockScoped synchronize(*lock_);
time_us_ += microseconds;
}
}; // namespace webrtc

View File

@@ -0,0 +1,27 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/system_wrappers/interface/clock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace webrtc {
TEST(ClockTest, NtpTime) {
Clock* clock = Clock::GetRealTimeClock();
uint32_t seconds;
uint32_t fractions;
clock->CurrentNtp(seconds, fractions);
int64_t milliseconds = clock->CurrentNtpInMilliseconds();
EXPECT_GT(milliseconds / 1000, kNtpJan1970);
EXPECT_GE(milliseconds, Clock::NtpToMs(seconds, fractions));
EXPECT_NEAR(milliseconds, Clock::NtpToMs(seconds, fractions), 5);
}
} // namespace webrtc

View File

@@ -0,0 +1,41 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/system_wrappers/interface/condition_variable_wrapper.h"
#if defined(_WIN32)
#include <windows.h>
#include "webrtc/system_wrappers/source/condition_variable_event_win.h"
#include "webrtc/system_wrappers/source/condition_variable_native_win.h"
#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
#include <pthread.h>
#include "webrtc/system_wrappers/source/condition_variable_posix.h"
#endif
namespace webrtc {
ConditionVariableWrapper* ConditionVariableWrapper::CreateConditionVariable() {
#if defined(_WIN32)
// Try to create native condition variable implementation.
ConditionVariableWrapper* ret_val = ConditionVariableNativeWin::Create();
if (!ret_val) {
// Native condition variable implementation does not exist. Create generic
// condition variable based on events.
ret_val = new ConditionVariableEventWin();
}
return ret_val;
#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC)
return ConditionVariablePosix::Create();
#else
return NULL;
#endif
}
} // namespace webrtc

View File

@@ -0,0 +1,195 @@
/*
Source:
http://www1.cse.wustl.edu/~schmidt/ACE-copying.html
License:
Copyright and Licensing Information for ACE(TM), TAO(TM), CIAO(TM), DAnCE(TM),
and CoSMIC(TM)
ACE(TM), TAO(TM), CIAO(TM), DAnCE>(TM), and CoSMIC(TM) (henceforth referred to
as "DOC software") are copyrighted by Douglas C. Schmidt and his research
group at Washington University, University of California, Irvine, and
Vanderbilt University, Copyright (c) 1993-2009, all rights reserved. Since DOC
software is open-source, freely available software, you are free to use,
modify, copy, and distribute--perpetually and irrevocably--the DOC software
source code and object code produced from the source, as well as copy and
distribute modified versions of this software. You must, however, include this
copyright statement along with any code built using DOC software that you
release. No copyright statement needs to be provided if you just ship binary
executables of your software products.
You can use DOC software in commercial and/or binary software releases and are
under no obligation to redistribute any of your source code that is built
using DOC software. Note, however, that you may not misappropriate the DOC
software code, such as copyrighting it yourself or claiming authorship of the
DOC software code, in a way that will prevent DOC software from being
distributed freely using an open-source development model. You needn't inform
anyone that you're using DOC software in your software, though we encourage
you to let us know so we can promote your project in the DOC software success
stories.
The ACE, TAO, CIAO, DAnCE, and CoSMIC web sites are maintained by the DOC
Group at the Institute for Software Integrated Systems (ISIS) and the Center
for Distributed Object Computing of Washington University, St. Louis for the
development of open-source software as part of the open-source software
community. Submissions are provided by the submitter ``as is'' with no
warranties whatsoever, including any warranty of merchantability,
noninfringement of third party intellectual property, or fitness for any
particular purpose. In no event shall the submitter be liable for any direct,
indirect, special, exemplary, punitive, or consequential damages, including
without limitation, lost profits, even if advised of the possibility of such
damages. Likewise, DOC software is provided as is with no warranties of any
kind, including the warranties of design, merchantability, and fitness for a
particular purpose, noninfringement, or arising from a course of dealing,
usage or trade practice. Washington University, UC Irvine, Vanderbilt
University, their employees, and students shall have no liability with respect
to the infringement of copyrights, trade secrets or any patents by DOC
software or any part thereof. Moreover, in no event will Washington
University, UC Irvine, or Vanderbilt University, their employees, or students
be liable for any lost revenue or profits or other special, indirect and
consequential damages.
DOC software is provided with no support and without any obligation on the
part of Washington University, UC Irvine, Vanderbilt University, their
employees, or students to assist in its use, correction, modification, or
enhancement. A number of companies around the world provide commercial support
for DOC software, however. DOC software is Y2K-compliant, as long as the
underlying OS platform is Y2K-compliant. Likewise, DOC software is compliant
with the new US daylight savings rule passed by Congress as "The Energy Policy
Act of 2005," which established new daylight savings times (DST) rules for the
United States that expand DST as of March 2007. Since DOC software obtains
time/date and calendaring information from operating systems users will not be
affected by the new DST rules as long as they upgrade their operating systems
accordingly.
The names ACE(TM), TAO(TM), CIAO(TM), DAnCE(TM), CoSMIC(TM), Washington
University, UC Irvine, and Vanderbilt University, may not be used to endorse
or promote products or services derived from this source without express
written permission from Washington University, UC Irvine, or Vanderbilt
University. This license grants no permission to call products or services
derived from this source ACE(TM), TAO(TM), CIAO(TM), DAnCE(TM), or CoSMIC(TM),
nor does it grant permission for the name Washington University, UC Irvine, or
Vanderbilt University to appear in their names.
*/
/*
* This source code contain modifications to the original source code
* which can be found here:
* http://www.cs.wustl.edu/~schmidt/win32-cv-1.html (section 3.2).
* Modifications:
* 1) Dynamic detection of native support for condition variables.
* 2) Use of WebRTC defined types and classes. Renaming of some functions.
* 3) Introduction of a second event for wake all functionality. This prevents
* a thread from spinning on the same condition variable, preventing other
* threads from waking up.
*/
#include "webrtc/system_wrappers/source/condition_variable_event_win.h"
#include "webrtc/system_wrappers/source/critical_section_win.h"
namespace webrtc {
ConditionVariableEventWin::ConditionVariableEventWin() : eventID_(WAKEALL_0) {
memset(&num_waiters_[0], 0, sizeof(num_waiters_));
InitializeCriticalSection(&num_waiters_crit_sect_);
events_[WAKEALL_0] = CreateEvent(NULL, // no security attributes
TRUE, // manual-reset, sticky event
FALSE, // initial state non-signaled
NULL); // no name for event
events_[WAKEALL_1] = CreateEvent(NULL, // no security attributes
TRUE, // manual-reset, sticky event
FALSE, // initial state non-signaled
NULL); // no name for event
events_[WAKE] = CreateEvent(NULL, // no security attributes
FALSE, // auto-reset, sticky event
FALSE, // initial state non-signaled
NULL); // no name for event
}
ConditionVariableEventWin::~ConditionVariableEventWin() {
CloseHandle(events_[WAKE]);
CloseHandle(events_[WAKEALL_1]);
CloseHandle(events_[WAKEALL_0]);
DeleteCriticalSection(&num_waiters_crit_sect_);
}
void ConditionVariableEventWin::SleepCS(CriticalSectionWrapper& crit_sect) {
SleepCS(crit_sect, INFINITE);
}
bool ConditionVariableEventWin::SleepCS(CriticalSectionWrapper& crit_sect,
unsigned long max_time_in_ms) {
EnterCriticalSection(&num_waiters_crit_sect_);
// Get the eventID for the event that will be triggered by next
// WakeAll() call and start waiting for it.
const EventWakeUpType eventID =
(WAKEALL_0 == eventID_) ? WAKEALL_1 : WAKEALL_0;
++(num_waiters_[eventID]);
LeaveCriticalSection(&num_waiters_crit_sect_);
CriticalSectionWindows* cs =
static_cast<CriticalSectionWindows*>(&crit_sect);
LeaveCriticalSection(&cs->crit);
HANDLE events[2];
events[0] = events_[WAKE];
events[1] = events_[eventID];
const DWORD result = WaitForMultipleObjects(2, // Wait on 2 events.
events,
FALSE, // Wait for either.
max_time_in_ms);
const bool ret_val = (result != WAIT_TIMEOUT);
EnterCriticalSection(&num_waiters_crit_sect_);
--(num_waiters_[eventID]);
// Last waiter should only be true for WakeAll(). WakeAll() correspond
// to position 1 in events[] -> (result == WAIT_OBJECT_0 + 1)
const bool last_waiter = (result == WAIT_OBJECT_0 + 1) &&
(num_waiters_[eventID] == 0);
LeaveCriticalSection(&num_waiters_crit_sect_);
if (last_waiter) {
// Reset/unset the WakeAll() event since all threads have been
// released.
ResetEvent(events_[eventID]);
}
EnterCriticalSection(&cs->crit);
return ret_val;
}
void ConditionVariableEventWin::Wake() {
EnterCriticalSection(&num_waiters_crit_sect_);
const bool have_waiters = (num_waiters_[WAKEALL_0] > 0) ||
(num_waiters_[WAKEALL_1] > 0);
LeaveCriticalSection(&num_waiters_crit_sect_);
if (have_waiters) {
SetEvent(events_[WAKE]);
}
}
void ConditionVariableEventWin::WakeAll() {
EnterCriticalSection(&num_waiters_crit_sect_);
// Update current WakeAll() event
eventID_ = (WAKEALL_0 == eventID_) ? WAKEALL_1 : WAKEALL_0;
// Trigger current event
const EventWakeUpType eventID = eventID_;
const bool have_waiters = num_waiters_[eventID] > 0;
LeaveCriticalSection(&num_waiters_crit_sect_);
if (have_waiters) {
SetEvent(events_[eventID]);
}
}
} // namespace webrtc

View File

@@ -0,0 +1,46 @@
/*
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_EVENT_WIN_H_
#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_EVENT_WIN_H_
#include <windows.h>
#include "webrtc/system_wrappers/interface/condition_variable_wrapper.h"
namespace webrtc {
class ConditionVariableEventWin : public ConditionVariableWrapper {
public:
ConditionVariableEventWin();
virtual ~ConditionVariableEventWin();
void SleepCS(CriticalSectionWrapper& crit_sect);
bool SleepCS(CriticalSectionWrapper& crit_sect, unsigned long max_time_inMS);
void Wake();
void WakeAll();
private:
enum EventWakeUpType {
WAKEALL_0 = 0,
WAKEALL_1 = 1,
WAKE = 2,
EVENT_COUNT = 3
};
unsigned int num_waiters_[2];
EventWakeUpType eventID_;
CRITICAL_SECTION num_waiters_crit_sect_;
HANDLE events_[EVENT_COUNT];
};
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_EVENT_WIN_H_

View File

@@ -0,0 +1,104 @@
/*
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/system_wrappers/interface/trace.h"
#include "webrtc/system_wrappers/source/condition_variable_native_win.h"
#include "webrtc/system_wrappers/source/critical_section_win.h"
namespace webrtc {
static HMODULE library = NULL;
static bool win_support_condition_variables_primitive = false;
PInitializeConditionVariable PInitializeConditionVariable_;
PSleepConditionVariableCS PSleepConditionVariableCS_;
PWakeConditionVariable PWakeConditionVariable_;
PWakeAllConditionVariable PWakeAllConditionVariable_;
typedef void (WINAPI *PInitializeConditionVariable)(PCONDITION_VARIABLE);
typedef BOOL (WINAPI *PSleepConditionVariableCS)(PCONDITION_VARIABLE,
PCRITICAL_SECTION, DWORD);
typedef void (WINAPI *PWakeConditionVariable)(PCONDITION_VARIABLE);
typedef void (WINAPI *PWakeAllConditionVariable)(PCONDITION_VARIABLE);
ConditionVariableNativeWin::ConditionVariableNativeWin() {
}
ConditionVariableNativeWin::~ConditionVariableNativeWin() {
}
ConditionVariableWrapper* ConditionVariableNativeWin::Create() {
ConditionVariableNativeWin* ret_val = new ConditionVariableNativeWin();
if (!ret_val->Init()) {
delete ret_val;
return NULL;
}
return ret_val;
}
bool ConditionVariableNativeWin::Init() {
if (!library) {
// Native implementation is supported on Vista+.
library = LoadLibrary(TEXT("Kernel32.dll"));
// TODO(henrike): this code results in an attempt to load the above dll
// every time the previous attempt failed. Only try to load once.
if (library) {
// TODO(henrike): not thread safe as reading and writing to library is not
// serialized. Fix.
WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, "Loaded Kernel.dll");
PInitializeConditionVariable_ =
(PInitializeConditionVariable) GetProcAddress(
library, "InitializeConditionVariable");
PSleepConditionVariableCS_ = (PSleepConditionVariableCS) GetProcAddress(
library, "SleepConditionVariableCS");
PWakeConditionVariable_ = (PWakeConditionVariable) GetProcAddress(
library, "WakeConditionVariable");
PWakeAllConditionVariable_ = (PWakeAllConditionVariable) GetProcAddress(
library, "WakeAllConditionVariable");
if (PInitializeConditionVariable_ && PSleepConditionVariableCS_
&& PWakeConditionVariable_ && PWakeAllConditionVariable_) {
WEBRTC_TRACE(
kTraceStateInfo, kTraceUtility, -1,
"Loaded native condition variables");
win_support_condition_variables_primitive = true;
}
}
}
if (!win_support_condition_variables_primitive) {
return false;
}
PInitializeConditionVariable_(&condition_variable_);
return true;
}
void ConditionVariableNativeWin::SleepCS(CriticalSectionWrapper& crit_sect) {
SleepCS(crit_sect, INFINITE);
}
bool ConditionVariableNativeWin::SleepCS(CriticalSectionWrapper& crit_sect,
unsigned long max_time_in_ms) {
CriticalSectionWindows* cs =
static_cast<CriticalSectionWindows*>(&crit_sect);
BOOL ret_val = PSleepConditionVariableCS_(&condition_variable_,
&(cs->crit), max_time_in_ms);
return ret_val != 0;
}
void ConditionVariableNativeWin::Wake() {
PWakeConditionVariable_(&condition_variable_);
}
void ConditionVariableNativeWin::WakeAll() {
PWakeAllConditionVariable_(&condition_variable_);
}
} // namespace webrtc

View File

@@ -0,0 +1,54 @@
/*
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_NATIVE_WIN_H_
#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_NATIVE_WIN_H_
#include <windows.h>
#include "webrtc/system_wrappers/interface/condition_variable_wrapper.h"
namespace webrtc {
#if !defined CONDITION_VARIABLE_INIT
typedef struct RTL_CONDITION_VARIABLE_ {
void* Ptr;
} RTL_CONDITION_VARIABLE, *PRTL_CONDITION_VARIABLE;
typedef RTL_CONDITION_VARIABLE CONDITION_VARIABLE, *PCONDITION_VARIABLE;
#endif
typedef void (WINAPI* PInitializeConditionVariable)(PCONDITION_VARIABLE);
typedef BOOL (WINAPI* PSleepConditionVariableCS)(PCONDITION_VARIABLE,
PCRITICAL_SECTION, DWORD);
typedef void (WINAPI* PWakeConditionVariable)(PCONDITION_VARIABLE);
typedef void (WINAPI* PWakeAllConditionVariable)(PCONDITION_VARIABLE);
class ConditionVariableNativeWin : public ConditionVariableWrapper {
public:
static ConditionVariableWrapper* Create();
virtual ~ConditionVariableNativeWin();
void SleepCS(CriticalSectionWrapper& crit_sect);
bool SleepCS(CriticalSectionWrapper& crit_sect, unsigned long max_time_inMS);
void Wake();
void WakeAll();
private:
ConditionVariableNativeWin();
bool Init();
CONDITION_VARIABLE condition_variable_;
};
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_NATIVE_WIN_H_

View File

@@ -0,0 +1,132 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/system_wrappers/source/condition_variable_posix.h"
#include <errno.h>
#if defined(WEBRTC_LINUX)
#include <time.h>
#else
#include <sys/time.h>
#endif
#include "webrtc/system_wrappers/source/critical_section_posix.h"
namespace webrtc {
ConditionVariableWrapper* ConditionVariablePosix::Create() {
ConditionVariablePosix* ptr = new ConditionVariablePosix;
if (!ptr) {
return NULL;
}
const int error = ptr->Construct();
if (error) {
delete ptr;
return NULL;
}
return ptr;
}
ConditionVariablePosix::ConditionVariablePosix() {
}
int ConditionVariablePosix::Construct() {
#ifdef WEBRTC_CLOCK_TYPE_REALTIME
pthread_cond_init(&cond_, NULL);
#else
int result = 0;
pthread_condattr_t cond_attr;
result = pthread_condattr_init(&cond_attr);
if (result != 0) {
return -1;
}
result = pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC);
if (result != 0) {
return -1;
}
result = pthread_cond_init(&cond_, &cond_attr);
if (result != 0) {
return -1;
}
result = pthread_condattr_destroy(&cond_attr);
if (result != 0) {
return -1;
}
#endif
return 0;
}
ConditionVariablePosix::~ConditionVariablePosix() {
pthread_cond_destroy(&cond_);
}
void ConditionVariablePosix::SleepCS(CriticalSectionWrapper& crit_sect) {
CriticalSectionPosix* cs = reinterpret_cast<CriticalSectionPosix*>(
&crit_sect);
pthread_cond_wait(&cond_, &cs->mutex_);
}
bool ConditionVariablePosix::SleepCS(CriticalSectionWrapper& crit_sect,
unsigned long max_time_inMS) {
const unsigned long INFINITE = 0xFFFFFFFF;
const int MILLISECONDS_PER_SECOND = 1000;
#ifndef WEBRTC_LINUX
const int MICROSECONDS_PER_MILLISECOND = 1000;
#endif
const int NANOSECONDS_PER_SECOND = 1000000000;
const int NANOSECONDS_PER_MILLISECOND = 1000000;
CriticalSectionPosix* cs = reinterpret_cast<CriticalSectionPosix*>(
&crit_sect);
if (max_time_inMS != INFINITE) {
timespec ts;
#ifndef WEBRTC_MAC
#ifdef WEBRTC_CLOCK_TYPE_REALTIME
clock_gettime(CLOCK_REALTIME, &ts);
#else
clock_gettime(CLOCK_MONOTONIC, &ts);
#endif
#else // WEBRTC_MAC
struct timeval tv;
gettimeofday(&tv, 0);
ts.tv_sec = tv.tv_sec;
ts.tv_nsec = tv.tv_usec * MICROSECONDS_PER_MILLISECOND;
#endif
ts.tv_sec += max_time_inMS / MILLISECONDS_PER_SECOND;
ts.tv_nsec +=
(max_time_inMS
- ((max_time_inMS / MILLISECONDS_PER_SECOND) * MILLISECONDS_PER_SECOND))
* NANOSECONDS_PER_MILLISECOND;
if (ts.tv_nsec >= NANOSECONDS_PER_SECOND) {
ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND;
ts.tv_nsec %= NANOSECONDS_PER_SECOND;
}
const int res = pthread_cond_timedwait(&cond_, &cs->mutex_, &ts);
return (res == ETIMEDOUT) ? false : true;
} else {
pthread_cond_wait(&cond_, &cs->mutex_);
return true;
}
}
void ConditionVariablePosix::Wake() {
pthread_cond_signal(&cond_);
}
void ConditionVariablePosix::WakeAll() {
pthread_cond_broadcast(&cond_);
}
} // namespace webrtc

View File

@@ -0,0 +1,42 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_POSIX_H_
#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_POSIX_H_
#include <pthread.h>
#include "webrtc/system_wrappers/interface/condition_variable_wrapper.h"
#include "webrtc/typedefs.h"
namespace webrtc {
class ConditionVariablePosix : public ConditionVariableWrapper {
public:
static ConditionVariableWrapper* Create();
virtual ~ConditionVariablePosix();
virtual void SleepCS(CriticalSectionWrapper& crit_sect) OVERRIDE;
virtual bool SleepCS(CriticalSectionWrapper& crit_sect,
unsigned long max_time_in_ms) OVERRIDE;
virtual void Wake() OVERRIDE;
virtual void WakeAll() OVERRIDE;
private:
ConditionVariablePosix();
int Construct();
private:
pthread_cond_t cond_;
};
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_POSIX_H_

View File

@@ -0,0 +1,191 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/system_wrappers/interface/condition_variable_wrapper.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include "webrtc/system_wrappers/interface/thread_wrapper.h"
#include "webrtc/system_wrappers/interface/trace.h"
namespace webrtc {
namespace {
const int kLongWaitMs = 100 * 1000; // A long time in testing terms
const int kShortWaitMs = 2 * 1000; // Long enough for process switches to happen
// A Baton is one possible control structure one can build using
// conditional variables.
// A Baton is always held by one and only one active thread - unlike
// a lock, it can never be free.
// One can pass it or grab it - both calls have timeouts.
// Note - a production tool would guard against passing it without
// grabbing it first. This one is for testing, so it doesn't.
class Baton {
public:
Baton()
: giver_sect_(CriticalSectionWrapper::CreateCriticalSection()),
crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
cond_var_(ConditionVariableWrapper::CreateConditionVariable()),
being_passed_(false),
pass_count_(0) {
}
~Baton() {
delete giver_sect_;
delete crit_sect_;
delete cond_var_;
}
// Pass the baton. Returns false if baton is not picked up in |max_msecs|.
// Only one process can pass at the same time; this property is
// ensured by the |giver_sect_| lock.
bool Pass(uint32_t max_msecs) {
CriticalSectionScoped cs_giver(giver_sect_);
CriticalSectionScoped cs(crit_sect_);
SignalBatonAvailable();
const bool result = TakeBatonIfStillFree(max_msecs);
if (result) {
++pass_count_;
}
return result;
}
// Grab the baton. Returns false if baton is not passed.
bool Grab(uint32_t max_msecs) {
CriticalSectionScoped cs(crit_sect_);
return WaitUntilBatonOffered(max_msecs);
}
int PassCount() {
// We don't allow polling PassCount() during a Pass()-call since there is
// no guarantee that |pass_count_| is incremented until the Pass()-call
// finishes. I.e. the Grab()-call may finish before |pass_count_| has been
// incremented.
// Thus, this function waits on giver_sect_.
CriticalSectionScoped cs(giver_sect_);
return pass_count_;
}
private:
// Wait/Signal forms a classical semaphore on |being_passed_|.
// These functions must be called with crit_sect_ held.
bool WaitUntilBatonOffered(int timeout_ms) {
while (!being_passed_) {
if (!cond_var_->SleepCS(*crit_sect_, timeout_ms)) {
return false;
}
}
being_passed_ = false;
cond_var_->Wake();
return true;
}
void SignalBatonAvailable() {
assert(!being_passed_);
being_passed_ = true;
cond_var_->Wake();
}
// Timeout extension: Wait for a limited time for someone else to
// take it, and take it if it's not taken.
// Returns true if resource is taken by someone else, false
// if it is taken back by the caller.
// This function must be called with both |giver_sect_| and
// |crit_sect_| held.
bool TakeBatonIfStillFree(int timeout_ms) {
bool not_timeout = true;
while (being_passed_ && not_timeout) {
not_timeout = cond_var_->SleepCS(*crit_sect_, timeout_ms);
// If we're woken up while variable is still held, we may have
// gotten a wakeup destined for a grabber thread.
// This situation is not treated specially here.
}
if (!being_passed_) {
return true;
} else {
assert(!not_timeout);
being_passed_ = false;
return false;
}
}
// Lock that ensures that there is only one thread in the active
// part of Pass() at a time.
// |giver_sect_| must always be acquired before |cond_var_|.
CriticalSectionWrapper* giver_sect_;
// Lock that protects |being_passed_|.
CriticalSectionWrapper* crit_sect_;
ConditionVariableWrapper* cond_var_;
bool being_passed_;
// Statistics information: Number of successfull passes.
int pass_count_;
};
// Function that waits on a Baton, and passes it right back.
// We expect these calls never to time out.
bool WaitingRunFunction(void* obj) {
Baton* the_baton = static_cast<Baton*> (obj);
EXPECT_TRUE(the_baton->Grab(kLongWaitMs));
EXPECT_TRUE(the_baton->Pass(kLongWaitMs));
return true;
}
class CondVarTest : public ::testing::Test {
public:
CondVarTest() {}
virtual void SetUp() {
thread_ = ThreadWrapper::CreateThread(&WaitingRunFunction,
&baton_);
unsigned int id = 42;
ASSERT_TRUE(thread_->Start(id));
}
virtual void TearDown() {
// We have to wake the thread in order to make it obey the stop order.
// But we don't know if the thread has completed the run function, so
// we don't know if it will exit before or after the Pass.
// Thus, we need to pin it down inside its Run function (between Grab
// and Pass).
ASSERT_TRUE(baton_.Pass(kShortWaitMs));
thread_->SetNotAlive();
ASSERT_TRUE(baton_.Grab(kShortWaitMs));
ASSERT_TRUE(thread_->Stop());
delete thread_;
}
protected:
Baton baton_;
private:
ThreadWrapper* thread_;
};
// The SetUp and TearDown functions use condition variables.
// This test verifies those pieces in isolation.
TEST_F(CondVarTest, InitFunctionsWork) {
// All relevant asserts are in the SetUp and TearDown functions.
}
// This test verifies that one can use the baton multiple times.
TEST_F(CondVarTest, PassBatonMultipleTimes) {
const int kNumberOfRounds = 2;
for (int i = 0; i < kNumberOfRounds; ++i) {
ASSERT_TRUE(baton_.Pass(kShortWaitMs));
ASSERT_TRUE(baton_.Grab(kShortWaitMs));
}
EXPECT_EQ(2 * kNumberOfRounds, baton_.PassCount());
}
} // anonymous namespace
} // namespace webrtc

View File

@@ -0,0 +1,72 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// Parts of this file derived from Chromium's base/cpu.cc.
#include "webrtc/system_wrappers/interface/cpu_features_wrapper.h"
#if defined(WEBRTC_ARCH_X86_FAMILY) && defined(_MSC_VER)
#include <intrin.h>
#endif
#include "webrtc/typedefs.h"
// No CPU feature is available => straight C path.
int GetCPUInfoNoASM(CPUFeature feature) {
(void)feature;
return 0;
}
#if defined(WEBRTC_ARCH_X86_FAMILY)
#ifndef _MSC_VER
// Intrinsic for "cpuid".
#if defined(__pic__) && defined(__i386__)
static inline void __cpuid(int cpu_info[4], int info_type) {
__asm__ volatile(
"mov %%ebx, %%edi\n"
"cpuid\n"
"xchg %%edi, %%ebx\n"
: "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
: "a"(info_type));
}
#else
static inline void __cpuid(int cpu_info[4], int info_type) {
__asm__ volatile(
"cpuid\n"
: "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
: "a"(info_type));
}
#endif
#endif // _MSC_VER
#endif // WEBRTC_ARCH_X86_FAMILY
#if defined(WEBRTC_ARCH_X86_FAMILY)
// Actual feature detection for x86.
static int GetCPUInfo(CPUFeature feature) {
int cpu_info[4];
__cpuid(cpu_info, 1);
if (feature == kSSE2) {
return 0 != (cpu_info[3] & 0x04000000);
}
if (feature == kSSE3) {
return 0 != (cpu_info[2] & 0x00000001);
}
return 0;
}
#else
// Default to straight C for other platforms.
static int GetCPUInfo(CPUFeature feature) {
(void)feature;
return 0;
}
#endif
WebRtc_CPUInfo WebRtc_GetCPUInfo = GetCPUInfo;
WebRtc_CPUInfo WebRtc_GetCPUInfoNoASM = GetCPUInfoNoASM;

View File

@@ -0,0 +1,15 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <cpu-features.h>
uint64_t WebRtc_GetCPUFeaturesARM(void) {
return android_getCpuFeatures();
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/system_wrappers/interface/cpu_info.h"
#if defined(_WIN32)
#include <Windows.h>
#elif defined(WEBRTC_MAC)
#include <sys/sysctl.h>
#include <sys/types.h>
#else // defined(WEBRTC_LINUX) or defined(WEBRTC_ANDROID)
#include <unistd.h>
#endif
#include "webrtc/system_wrappers/interface/trace.h"
namespace webrtc {
uint32_t CpuInfo::number_of_cores_ = 0;
uint32_t CpuInfo::DetectNumberOfCores() {
if (!number_of_cores_) {
#if defined(_WIN32)
SYSTEM_INFO si;
GetSystemInfo(&si);
number_of_cores_ = static_cast<uint32_t>(si.dwNumberOfProcessors);
WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1,
"Available number of cores:%d", number_of_cores_);
#elif defined(WEBRTC_LINUX) || defined(WEBRTC_ANDROID)
number_of_cores_ = static_cast<uint32_t>(sysconf(_SC_NPROCESSORS_ONLN));
WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1,
"Available number of cores:%d", number_of_cores_);
#elif defined(WEBRTC_MAC)
int name[] = {CTL_HW, HW_AVAILCPU};
int ncpu;
size_t size = sizeof(ncpu);
if (0 == sysctl(name, 2, &ncpu, &size, NULL, 0)) {
number_of_cores_ = static_cast<uint32_t>(ncpu);
WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1,
"Available number of cores:%d", number_of_cores_);
} else {
WEBRTC_TRACE(kTraceError, kTraceUtility, -1,
"Failed to get number of cores");
number_of_cores_ = 1;
}
#else
WEBRTC_TRACE(kTraceWarning, kTraceUtility, -1,
"No function to get number of cores");
number_of_cores_ = 1;
#endif
}
return number_of_cores_;
}
} // namespace webrtc

View File

@@ -0,0 +1,28 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#if defined(_WIN32)
#include <windows.h>
#include "webrtc/system_wrappers/source/critical_section_win.h"
#else
#include "webrtc/system_wrappers/source/critical_section_posix.h"
#endif
namespace webrtc {
CriticalSectionWrapper* CriticalSectionWrapper::CreateCriticalSection() {
#ifdef _WIN32
return new CriticalSectionWindows();
#else
return new CriticalSectionPosix();
#endif
}
} // namespace webrtc

View File

@@ -0,0 +1,42 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// General note: return values for the various pthread synchronization APIs
// are explicitly ignored here. In Chromium, the same thing is done for release.
// However, in debugging, failure in these APIs are logged. There is currently
// no equivalent to DCHECK_EQ in WebRTC code so this is the best we can do here.
// TODO(henrike): add logging when pthread synchronization APIs are failing.
#include "webrtc/system_wrappers/source/critical_section_posix.h"
namespace webrtc {
CriticalSectionPosix::CriticalSectionPosix() {
pthread_mutexattr_t attr;
(void) pthread_mutexattr_init(&attr);
(void) pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
(void) pthread_mutex_init(&mutex_, &attr);
}
CriticalSectionPosix::~CriticalSectionPosix() {
(void) pthread_mutex_destroy(&mutex_);
}
void
CriticalSectionPosix::Enter() {
(void) pthread_mutex_lock(&mutex_);
}
void
CriticalSectionPosix::Leave() {
(void) pthread_mutex_unlock(&mutex_);
}
} // namespace webrtc

View File

@@ -0,0 +1,36 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_POSIX_H_
#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_POSIX_H_
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include <pthread.h>
namespace webrtc {
class CriticalSectionPosix : public CriticalSectionWrapper {
public:
CriticalSectionPosix();
virtual ~CriticalSectionPosix();
virtual void Enter() OVERRIDE;
virtual void Leave() OVERRIDE;
private:
pthread_mutex_t mutex_;
friend class ConditionVariablePosix;
};
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_POSIX_H_

View File

@@ -0,0 +1,142 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/system_wrappers/interface/sleep.h"
#include "webrtc/system_wrappers/interface/thread_wrapper.h"
#include "webrtc/system_wrappers/interface/trace.h"
namespace webrtc {
namespace {
// Cause a process switch. Needed to avoid depending on
// busy-wait in tests.
static void SwitchProcess() {
// Note - sched_yield has been tried as process switch. This does
// not cause a process switch enough of the time for reliability.
SleepMs(1);
}
class ProtectedCount {
public:
explicit ProtectedCount(CriticalSectionWrapper* crit_sect)
: crit_sect_(crit_sect),
count_(0) {
}
void Increment() {
CriticalSectionScoped cs(crit_sect_);
++count_;
}
int Count() const {
CriticalSectionScoped cs(crit_sect_);
return count_;
}
private:
CriticalSectionWrapper* crit_sect_;
int count_;
};
class CritSectTest : public ::testing::Test {
public:
CritSectTest() {}
// Waits a number of cycles for the count to reach a given value.
// Returns true if the target is reached or passed.
bool WaitForCount(int target, ProtectedCount* count) {
int loop_counter = 0;
// On Posix, this SwitchProcess() needs to be in a loop to make the
// test both fast and non-flaky.
// With 1 us wait as the switch, up to 7 rounds have been observed.
while (count->Count() < target && loop_counter < 100 * target) {
++loop_counter;
SwitchProcess();
}
return (count->Count() >= target);
}
};
bool LockUnlockThenStopRunFunction(void* obj) {
ProtectedCount* the_count = static_cast<ProtectedCount*>(obj);
the_count->Increment();
return false;
}
TEST_F(CritSectTest, ThreadWakesOnce) NO_THREAD_SAFETY_ANALYSIS {
CriticalSectionWrapper* crit_sect =
CriticalSectionWrapper::CreateCriticalSection();
ProtectedCount count(crit_sect);
ThreadWrapper* thread = ThreadWrapper::CreateThread(
&LockUnlockThenStopRunFunction, &count);
unsigned int id = 42;
crit_sect->Enter();
ASSERT_TRUE(thread->Start(id));
SwitchProcess();
// The critical section is of reentrant mode, so this should not release
// the lock, even though count.Count() locks and unlocks the critical section
// again.
// Thus, the thread should not be able to increment the count
ASSERT_EQ(0, count.Count());
crit_sect->Leave(); // This frees the thread to act.
EXPECT_TRUE(WaitForCount(1, &count));
EXPECT_TRUE(thread->Stop());
delete thread;
delete crit_sect;
}
bool LockUnlockRunFunction(void* obj) {
ProtectedCount* the_count = static_cast<ProtectedCount*>(obj);
the_count->Increment();
SwitchProcess();
return true;
}
TEST_F(CritSectTest, ThreadWakesTwice) NO_THREAD_SAFETY_ANALYSIS {
CriticalSectionWrapper* crit_sect =
CriticalSectionWrapper::CreateCriticalSection();
ProtectedCount count(crit_sect);
ThreadWrapper* thread = ThreadWrapper::CreateThread(&LockUnlockRunFunction,
&count);
unsigned int id = 42;
crit_sect->Enter(); // Make sure counter stays 0 until we wait for it.
ASSERT_TRUE(thread->Start(id));
crit_sect->Leave();
// The thread is capable of grabbing the lock multiple times,
// incrementing counter once each time.
// It's possible for the count to be incremented by more than 2.
EXPECT_TRUE(WaitForCount(2, &count));
EXPECT_LE(2, count.Count());
// The thread does not increment while lock is held.
crit_sect->Enter();
int count_before = count.Count();
for (int i = 0; i < 10; i++) {
SwitchProcess();
}
EXPECT_EQ(count_before, count.Count());
crit_sect->Leave();
thread->SetNotAlive(); // Tell thread to exit once run function finishes.
SwitchProcess();
EXPECT_TRUE(WaitForCount(count_before + 1, &count));
EXPECT_TRUE(thread->Stop());
delete thread;
delete crit_sect;
}
} // anonymous namespace
} // namespace webrtc

View File

@@ -0,0 +1,33 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/system_wrappers/source/critical_section_win.h"
namespace webrtc {
CriticalSectionWindows::CriticalSectionWindows() {
InitializeCriticalSection(&crit);
}
CriticalSectionWindows::~CriticalSectionWindows() {
DeleteCriticalSection(&crit);
}
void
CriticalSectionWindows::Enter() {
EnterCriticalSection(&crit);
}
void
CriticalSectionWindows::Leave() {
LeaveCriticalSection(&crit);
}
} // namespace webrtc

View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_WIN_H_
#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_WIN_H_
#include <windows.h>
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include "webrtc/typedefs.h"
namespace webrtc {
class CriticalSectionWindows : public CriticalSectionWrapper {
public:
CriticalSectionWindows();
virtual ~CriticalSectionWindows();
virtual void Enter();
virtual void Leave();
private:
CRITICAL_SECTION crit;
friend class ConditionVariableEventWin;
friend class ConditionVariableNativeWin;
};
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_WIN_H_

View File

@@ -0,0 +1,455 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/system_wrappers/interface/data_log.h"
#include <assert.h>
#include <algorithm>
#include <list>
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include "webrtc/system_wrappers/interface/event_wrapper.h"
#include "webrtc/system_wrappers/interface/file_wrapper.h"
#include "webrtc/system_wrappers/interface/rw_lock_wrapper.h"
#include "webrtc/system_wrappers/interface/thread_wrapper.h"
namespace webrtc {
DataLogImpl::CritSectScopedPtr DataLogImpl::crit_sect_(
CriticalSectionWrapper::CreateCriticalSection());
DataLogImpl* DataLogImpl::instance_ = NULL;
// A Row contains cells, which are indexed by the column names as std::string.
// The string index is treated in a case sensitive way.
class Row {
public:
Row();
~Row();
// Inserts a Container into the cell of the column specified with
// column_name.
// column_name is treated in a case sensitive way.
int InsertCell(const std::string& column_name,
const Container* value_container);
// Converts the value at the column specified by column_name to a string
// stored in value_string.
// column_name is treated in a case sensitive way.
void ToString(const std::string& column_name, std::string* value_string);
private:
// Collection of containers indexed by column name as std::string
typedef std::map<std::string, const Container*> CellMap;
CellMap cells_;
CriticalSectionWrapper* cells_lock_;
};
// A LogTable contains multiple rows, where only the latest row is active for
// editing. The rows are defined by the ColumnMap, which contains the name of
// each column and the length of the column (1 for one-value-columns and greater
// than 1 for multi-value-columns).
class LogTable {
public:
LogTable();
~LogTable();
// Adds the column with name column_name to the table. The column will be a
// multi-value-column if multi_value_length is greater than 1.
// column_name is treated in a case sensitive way.
int AddColumn(const std::string& column_name, int multi_value_length);
// Buffers the current row while it is waiting to be written to file,
// which is done by a call to Flush(). A new row is available when the
// function returns
void NextRow();
// Inserts a Container into the cell of the column specified with
// column_name.
// column_name is treated in a case sensitive way.
int InsertCell(const std::string& column_name,
const Container* value_container);
// Creates a log file, named as specified in the string file_name, to
// where the table will be written when calling Flush().
int CreateLogFile(const std::string& file_name);
// Write all complete rows to file.
// May not be called by two threads simultaneously (doing so may result in
// a race condition). Will be called by the file_writer_thread_ when that
// thread is running.
void Flush();
private:
// Collection of multi_value_lengths indexed by column name as std::string
typedef std::map<std::string, int> ColumnMap;
typedef std::list<Row*> RowList;
ColumnMap columns_;
RowList rows_[2];
RowList* rows_history_;
RowList* rows_flush_;
Row* current_row_;
FileWrapper* file_;
bool write_header_;
CriticalSectionWrapper* table_lock_;
};
Row::Row()
: cells_(),
cells_lock_(CriticalSectionWrapper::CreateCriticalSection()) {
}
Row::~Row() {
for (CellMap::iterator it = cells_.begin(); it != cells_.end();) {
delete it->second;
// For maps all iterators (except the erased) are valid after an erase
cells_.erase(it++);
}
delete cells_lock_;
}
int Row::InsertCell(const std::string& column_name,
const Container* value_container) {
CriticalSectionScoped synchronize(cells_lock_);
assert(cells_.count(column_name) == 0);
if (cells_.count(column_name) > 0)
return -1;
cells_[column_name] = value_container;
return 0;
}
void Row::ToString(const std::string& column_name,
std::string* value_string) {
CriticalSectionScoped synchronize(cells_lock_);
const Container* container = cells_[column_name];
if (container == NULL) {
*value_string = "NaN,";
return;
}
container->ToString(value_string);
}
LogTable::LogTable()
: columns_(),
rows_(),
rows_history_(&rows_[0]),
rows_flush_(&rows_[1]),
current_row_(new Row),
file_(FileWrapper::Create()),
write_header_(true),
table_lock_(CriticalSectionWrapper::CreateCriticalSection()) {
}
LogTable::~LogTable() {
for (RowList::iterator row_it = rows_history_->begin();
row_it != rows_history_->end();) {
delete *row_it;
row_it = rows_history_->erase(row_it);
}
for (ColumnMap::iterator col_it = columns_.begin();
col_it != columns_.end();) {
// For maps all iterators (except the erased) are valid after an erase
columns_.erase(col_it++);
}
if (file_ != NULL) {
file_->Flush();
file_->CloseFile();
delete file_;
}
delete current_row_;
delete table_lock_;
}
int LogTable::AddColumn(const std::string& column_name,
int multi_value_length) {
assert(multi_value_length > 0);
if (!write_header_) {
// It's not allowed to add new columns after the header
// has been written.
assert(false);
return -1;
} else {
CriticalSectionScoped synchronize(table_lock_);
if (write_header_)
columns_[column_name] = multi_value_length;
else
return -1;
}
return 0;
}
void LogTable::NextRow() {
CriticalSectionScoped sync_rows(table_lock_);
rows_history_->push_back(current_row_);
current_row_ = new Row;
}
int LogTable::InsertCell(const std::string& column_name,
const Container* value_container) {
CriticalSectionScoped synchronize(table_lock_);
assert(columns_.count(column_name) > 0);
if (columns_.count(column_name) == 0)
return -1;
return current_row_->InsertCell(column_name, value_container);
}
int LogTable::CreateLogFile(const std::string& file_name) {
if (file_name.length() == 0)
return -1;
if (file_->Open())
return -1;
file_->OpenFile(file_name.c_str(),
false, // Open with read/write permissions
false, // Don't wraparound and write at the beginning when
// the file is full
true); // Open as a text file
if (file_ == NULL)
return -1;
return 0;
}
void LogTable::Flush() {
ColumnMap::iterator column_it;
bool commit_header = false;
if (write_header_) {
CriticalSectionScoped synchronize(table_lock_);
if (write_header_) {
commit_header = true;
write_header_ = false;
}
}
if (commit_header) {
for (column_it = columns_.begin();
column_it != columns_.end(); ++column_it) {
if (column_it->second > 1) {
file_->WriteText("%s[%u],", column_it->first.c_str(),
column_it->second);
for (int i = 1; i < column_it->second; ++i)
file_->WriteText(",");
} else {
file_->WriteText("%s,", column_it->first.c_str());
}
}
if (columns_.size() > 0)
file_->WriteText("\n");
}
// Swap the list used for flushing with the list containing the row history
// and clear the history. We also create a local pointer to the new
// list used for flushing to avoid race conditions if another thread
// calls this function while we are writing.
// We don't want to block the list while we're writing to file.
{
CriticalSectionScoped synchronize(table_lock_);
RowList* tmp = rows_flush_;
rows_flush_ = rows_history_;
rows_history_ = tmp;
rows_history_->clear();
}
// Write all complete rows to file and delete them
for (RowList::iterator row_it = rows_flush_->begin();
row_it != rows_flush_->end();) {
for (column_it = columns_.begin();
column_it != columns_.end(); ++column_it) {
std::string row_string;
(*row_it)->ToString(column_it->first, &row_string);
file_->WriteText("%s", row_string.c_str());
}
if (columns_.size() > 0)
file_->WriteText("\n");
delete *row_it;
row_it = rows_flush_->erase(row_it);
}
}
int DataLog::CreateLog() {
return DataLogImpl::CreateLog();
}
void DataLog::ReturnLog() {
return DataLogImpl::ReturnLog();
}
std::string DataLog::Combine(const std::string& table_name, int table_id) {
std::stringstream ss;
std::string combined_id = table_name;
std::string number_suffix;
ss << "_" << table_id;
ss >> number_suffix;
combined_id += number_suffix;
std::transform(combined_id.begin(), combined_id.end(), combined_id.begin(),
::tolower);
return combined_id;
}
int DataLog::AddTable(const std::string& table_name) {
DataLogImpl* data_log = DataLogImpl::StaticInstance();
if (data_log == NULL)
return -1;
return data_log->AddTable(table_name);
}
int DataLog::AddColumn(const std::string& table_name,
const std::string& column_name,
int multi_value_length) {
DataLogImpl* data_log = DataLogImpl::StaticInstance();
if (data_log == NULL)
return -1;
return data_log->DataLogImpl::StaticInstance()->AddColumn(table_name,
column_name,
multi_value_length);
}
int DataLog::NextRow(const std::string& table_name) {
DataLogImpl* data_log = DataLogImpl::StaticInstance();
if (data_log == NULL)
return -1;
return data_log->DataLogImpl::StaticInstance()->NextRow(table_name);
}
DataLogImpl::DataLogImpl()
: counter_(1),
tables_(),
flush_event_(EventWrapper::Create()),
file_writer_thread_(NULL),
tables_lock_(RWLockWrapper::CreateRWLock()) {
}
DataLogImpl::~DataLogImpl() {
StopThread();
Flush(); // Write any remaining rows
delete file_writer_thread_;
delete flush_event_;
for (TableMap::iterator it = tables_.begin(); it != tables_.end();) {
delete static_cast<LogTable*>(it->second);
// For maps all iterators (except the erased) are valid after an erase
tables_.erase(it++);
}
delete tables_lock_;
}
int DataLogImpl::CreateLog() {
CriticalSectionScoped synchronize(crit_sect_.get());
if (instance_ == NULL) {
instance_ = new DataLogImpl();
return instance_->Init();
} else {
++instance_->counter_;
}
return 0;
}
int DataLogImpl::Init() {
file_writer_thread_ = ThreadWrapper::CreateThread(
DataLogImpl::Run,
instance_,
kHighestPriority,
"DataLog");
if (file_writer_thread_ == NULL)
return -1;
unsigned int thread_id = 0;
bool success = file_writer_thread_->Start(thread_id);
if (!success)
return -1;
return 0;
}
DataLogImpl* DataLogImpl::StaticInstance() {
return instance_;
}
void DataLogImpl::ReturnLog() {
CriticalSectionScoped synchronize(crit_sect_.get());
if (instance_ && instance_->counter_ > 1) {
--instance_->counter_;
return;
}
delete instance_;
instance_ = NULL;
}
int DataLogImpl::AddTable(const std::string& table_name) {
WriteLockScoped synchronize(*tables_lock_);
// Make sure we don't add a table which already exists
if (tables_.count(table_name) > 0)
return -1;
tables_[table_name] = new LogTable();
if (tables_[table_name]->CreateLogFile(table_name + ".txt") == -1)
return -1;
return 0;
}
int DataLogImpl::AddColumn(const std::string& table_name,
const std::string& column_name,
int multi_value_length) {
ReadLockScoped synchronize(*tables_lock_);
if (tables_.count(table_name) == 0)
return -1;
return tables_[table_name]->AddColumn(column_name, multi_value_length);
}
int DataLogImpl::InsertCell(const std::string& table_name,
const std::string& column_name,
const Container* value_container) {
ReadLockScoped synchronize(*tables_lock_);
assert(tables_.count(table_name) > 0);
if (tables_.count(table_name) == 0)
return -1;
return tables_[table_name]->InsertCell(column_name, value_container);
}
int DataLogImpl::NextRow(const std::string& table_name) {
ReadLockScoped synchronize(*tables_lock_);
if (tables_.count(table_name) == 0)
return -1;
tables_[table_name]->NextRow();
if (file_writer_thread_ == NULL) {
// Write every row to file as they get complete.
tables_[table_name]->Flush();
} else {
// Signal a complete row
flush_event_->Set();
}
return 0;
}
void DataLogImpl::Flush() {
ReadLockScoped synchronize(*tables_lock_);
for (TableMap::iterator it = tables_.begin(); it != tables_.end(); ++it) {
it->second->Flush();
}
}
bool DataLogImpl::Run(void* obj) {
static_cast<DataLogImpl*>(obj)->Process();
return true;
}
void DataLogImpl::Process() {
// Wait for a row to be complete
flush_event_->Wait(WEBRTC_EVENT_INFINITE);
Flush();
}
void DataLogImpl::StopThread() {
if (file_writer_thread_ != NULL) {
file_writer_thread_->SetNotAlive();
flush_event_->Set();
// Call Stop() repeatedly, waiting for the Flush() call in Process() to
// finish.
while (!file_writer_thread_->Stop()) continue;
}
}
} // namespace webrtc

View File

@@ -0,0 +1,143 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// This is the pure C wrapper of the DataLog class.
#include "webrtc/system_wrappers/interface/data_log_c.h"
#include <string>
#include "webrtc/system_wrappers/interface/data_log.h"
extern "C" int WebRtcDataLog_CreateLog() {
return webrtc::DataLog::CreateLog();
}
extern "C" void WebRtcDataLog_ReturnLog() {
return webrtc::DataLog::ReturnLog();
}
extern "C" char* WebRtcDataLog_Combine(char* combined_name, size_t combined_len,
const char* table_name, int table_id) {
if (!table_name) return NULL;
std::string combined = webrtc::DataLog::Combine(table_name, table_id);
if (combined.size() >= combined_len) return NULL;
std::copy(combined.begin(), combined.end(), combined_name);
combined_name[combined.size()] = '\0';
return combined_name;
}
extern "C" int WebRtcDataLog_AddTable(const char* table_name) {
if (!table_name) return -1;
return webrtc::DataLog::AddTable(table_name);
}
extern "C" int WebRtcDataLog_AddColumn(const char* table_name,
const char* column_name,
int multi_value_length) {
if (!table_name || !column_name) return -1;
return webrtc::DataLog::AddColumn(table_name, column_name,
multi_value_length);
}
extern "C" int WebRtcDataLog_InsertCell_int(const char* table_name,
const char* column_name,
int value) {
if (!table_name || !column_name) return -1;
return webrtc::DataLog::InsertCell(table_name, column_name, value);
}
extern "C" int WebRtcDataLog_InsertArray_int(const char* table_name,
const char* column_name,
const int* values,
int length) {
if (!table_name || !column_name) return -1;
return webrtc::DataLog::InsertCell(table_name, column_name, values, length);
}
extern "C" int WebRtcDataLog_InsertCell_float(const char* table_name,
const char* column_name,
float value) {
if (!table_name || !column_name) return -1;
return webrtc::DataLog::InsertCell(table_name, column_name, value);
}
extern "C" int WebRtcDataLog_InsertArray_float(const char* table_name,
const char* column_name,
const float* values,
int length) {
if (!table_name || !column_name) return -1;
return webrtc::DataLog::InsertCell(table_name, column_name, values, length);
}
extern "C" int WebRtcDataLog_InsertCell_double(const char* table_name,
const char* column_name,
double value) {
if (!table_name || !column_name) return -1;
return webrtc::DataLog::InsertCell(table_name, column_name, value);
}
extern "C" int WebRtcDataLog_InsertArray_double(const char* table_name,
const char* column_name,
const double* values,
int length) {
if (!table_name || !column_name) return -1;
return webrtc::DataLog::InsertCell(table_name, column_name, values, length);
}
extern "C" int WebRtcDataLog_InsertCell_int32(const char* table_name,
const char* column_name,
int32_t value) {
if (!table_name || !column_name) return -1;
return webrtc::DataLog::InsertCell(table_name, column_name, value);
}
extern "C" int WebRtcDataLog_InsertArray_int32(const char* table_name,
const char* column_name,
const int32_t* values,
int length) {
if (!table_name || !column_name) return -1;
return webrtc::DataLog::InsertCell(table_name, column_name, values, length);
}
extern "C" int WebRtcDataLog_InsertCell_uint32(const char* table_name,
const char* column_name,
uint32_t value) {
if (!table_name || !column_name) return -1;
return webrtc::DataLog::InsertCell(table_name, column_name, value);
}
extern "C" int WebRtcDataLog_InsertArray_uint32(const char* table_name,
const char* column_name,
const uint32_t* values,
int length) {
if (!table_name || !column_name) return -1;
return webrtc::DataLog::InsertCell(table_name, column_name, values, length);
}
extern "C" int WebRtcDataLog_InsertCell_int64(const char* table_name,
const char* column_name,
int64_t value) {
if (!table_name || !column_name) return -1;
return webrtc::DataLog::InsertCell(table_name, column_name, value);
}
extern "C" int WebRtcDataLog_InsertArray_int64(const char* table_name,
const char* column_name,
const int64_t* values,
int length) {
if (!table_name || !column_name) return -1;
return webrtc::DataLog::InsertCell(table_name, column_name, values, length);
}
extern "C" int WebRtcDataLog_NextRow(const char* table_name) {
if (!table_name) return -1;
return webrtc::DataLog::NextRow(table_name);
}

View File

@@ -0,0 +1,124 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/system_wrappers/source/data_log_c_helpers_unittest.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "webrtc/system_wrappers/interface/data_log_c.h"
enum { kTestArrayLen = 4 };
static const char kTableName[] = "c_wrapper_table";
static const char kColumnName1[] = "Scalar";
static const char kColumnName2[] = "Vector";
int WebRtcDataLogCHelper_TestCreateLog() {
return WebRtcDataLog_CreateLog();
}
int WebRtcDataLogCHelper_TestReturnLog() {
WebRtcDataLog_ReturnLog();
return 0;
}
int WebRtcDataLogCHelper_TestCombine() {
const int kOutLen = strlen(kTableName) + 4; // Room for "_17" + '\0'
char* combined_name = malloc(kOutLen * sizeof(char));
char* out_ptr = WebRtcDataLog_Combine(combined_name, kOutLen, kTableName, 17);
int return_code = 0;
if (!out_ptr) {
return_code = -1;
}
if (strcmp(combined_name, "c_wrapper_table_17") != 0) {
return_code = -2;
}
free(combined_name);
return return_code;
}
int WebRtcDataLogCHelper_TestAddTable() {
return WebRtcDataLog_AddTable(kTableName);
}
int WebRtcDataLogCHelper_TestAddColumn() {
if (WebRtcDataLog_AddColumn(kTableName, kColumnName1, 1) != 0) {
return -1;
}
if (WebRtcDataLog_AddColumn(kTableName, kColumnName2, kTestArrayLen) != 0) {
return -2;
}
return 0;
}
int WebRtcDataLogCHelper_TestNextRow() {
return WebRtcDataLog_NextRow(kTableName);
}
int WebRtcDataLogCHelper_TestInsertCell_int() {
return WebRtcDataLog_InsertCell_int(kTableName, kColumnName1, 17);
}
int WebRtcDataLogCHelper_TestInsertArray_int() {
int values[kTestArrayLen] = {1, 2, 3, 4};
return WebRtcDataLog_InsertArray_int(kTableName, kColumnName2, values,
kTestArrayLen);
}
int WebRtcDataLogCHelper_TestInsertCell_float() {
return WebRtcDataLog_InsertCell_float(kTableName, kColumnName1, 17.0f);
}
int WebRtcDataLogCHelper_TestInsertArray_float() {
float values[kTestArrayLen] = {1.0f, 2.0f, 3.0f, 4.0f};
return WebRtcDataLog_InsertArray_float(kTableName, kColumnName2, values,
kTestArrayLen);
}
int WebRtcDataLogCHelper_TestInsertCell_double() {
return WebRtcDataLog_InsertCell_int(kTableName, kColumnName1, 17.0);
}
int WebRtcDataLogCHelper_TestInsertArray_double() {
double values[kTestArrayLen] = {1.0, 2.0, 3.0, 4.0};
return WebRtcDataLog_InsertArray_double(kTableName, kColumnName2, values,
kTestArrayLen);
}
int WebRtcDataLogCHelper_TestInsertCell_int32() {
return WebRtcDataLog_InsertCell_int32(kTableName, kColumnName1, 17);
}
int WebRtcDataLogCHelper_TestInsertArray_int32() {
int32_t values[kTestArrayLen] = {1, 2, 3, 4};
return WebRtcDataLog_InsertArray_int32(kTableName, kColumnName2, values,
kTestArrayLen);
}
int WebRtcDataLogCHelper_TestInsertCell_uint32() {
return WebRtcDataLog_InsertCell_uint32(kTableName, kColumnName1, 17);
}
int WebRtcDataLogCHelper_TestInsertArray_uint32() {
uint32_t values[kTestArrayLen] = {1, 2, 3, 4};
return WebRtcDataLog_InsertArray_uint32(kTableName, kColumnName2, values,
kTestArrayLen);
}
int WebRtcDataLogCHelper_TestInsertCell_int64() {
return WebRtcDataLog_InsertCell_int64(kTableName, kColumnName1, 17);
}
int WebRtcDataLogCHelper_TestInsertArray_int64() {
int64_t values[kTestArrayLen] = {1, 2, 3, 4};
return WebRtcDataLog_InsertArray_int64(kTableName, kColumnName2, values,
kTestArrayLen);
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef SRC_SYSTEM_WRAPPERS_SOURCE_DATA_LOG_C_HELPERS_UNITTEST_H_
#define SRC_SYSTEM_WRAPPERS_SOURCE_DATA_LOG_C_HELPERS_UNITTEST_H_
#ifdef __cplusplus
extern "C" {
#endif
int WebRtcDataLogCHelper_TestCreateLog();
int WebRtcDataLogCHelper_TestReturnLog();
int WebRtcDataLogCHelper_TestCombine();
int WebRtcDataLogCHelper_TestAddTable();
int WebRtcDataLogCHelper_TestAddColumn();
int WebRtcDataLogCHelper_TestNextRow();
int WebRtcDataLogCHelper_TestInsertCell_int();
int WebRtcDataLogCHelper_TestInsertArray_int();
int WebRtcDataLogCHelper_TestInsertCell_float();
int WebRtcDataLogCHelper_TestInsertArray_float();
int WebRtcDataLogCHelper_TestInsertCell_double();
int WebRtcDataLogCHelper_TestInsertArray_double();
int WebRtcDataLogCHelper_TestInsertCell_int32();
int WebRtcDataLogCHelper_TestInsertArray_int32();
int WebRtcDataLogCHelper_TestInsertCell_uint32();
int WebRtcDataLogCHelper_TestInsertArray_uint32();
int WebRtcDataLogCHelper_TestInsertCell_int64();
int WebRtcDataLogCHelper_TestInsertArray_int64();
#ifdef __cplusplus
} // end of extern "C"
#endif
#endif // SRC_SYSTEM_WRAPPERS_SOURCE_DATA_LOG_C_HELPERS_UNITTEST_H_

View File

@@ -0,0 +1,65 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/system_wrappers/interface/data_log.h"
#include <string>
#include "testing/gtest/include/gtest/gtest.h"
using ::webrtc::DataLog;
TEST(TestDataLog, IntContainers) {
int c = 5;
webrtc::ValueContainer<int> v1(c);
c = 10;
webrtc::ValueContainer<int> v2(c);
std::string s1, s2;
v1.ToString(&s1);
v2.ToString(&s2);
ASSERT_EQ(s1, "5,");
ASSERT_EQ(s2, "10,");
v1 = v2;
v1.ToString(&s1);
ASSERT_EQ(s1, s2);
}
TEST(TestDataLog, DoubleContainers) {
double c = 3.5;
webrtc::ValueContainer<double> v1(c);
c = 10.3;
webrtc::ValueContainer<double> v2(c);
std::string s1, s2;
v1.ToString(&s1);
v2.ToString(&s2);
ASSERT_EQ(s1, "3.5,");
ASSERT_EQ(s2, "10.3,");
v1 = v2;
v1.ToString(&s1);
ASSERT_EQ(s1, s2);
}
TEST(TestDataLog, MultiValueContainers) {
int a[3] = {1, 2, 3};
int b[3] = {4, 5, 6};
webrtc::MultiValueContainer<int> m1(a, 3);
webrtc::MultiValueContainer<int> m2(b, 3);
webrtc::MultiValueContainer<int> m3(a, 3);
std::string s1, s2, s3;
m1.ToString(&s1);
m2.ToString(&s2);
ASSERT_EQ(s1, "1,2,3,");
ASSERT_EQ(s2, "4,5,6,");
m1 = m2;
m1.ToString(&s1);
ASSERT_EQ(s1, s2);
m3.ToString(&s3);
ASSERT_EQ(s3, "1,2,3,");
}

View File

@@ -0,0 +1,88 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/system_wrappers/interface/data_log.h"
#include <string>
namespace webrtc {
int DataLog::CreateLog() {
return 0;
}
void DataLog::ReturnLog() {
}
std::string DataLog::Combine(const std::string& table_name, int table_id) {
return std::string();
}
int DataLog::AddTable(const std::string& /*table_name*/) {
return 0;
}
int DataLog::AddColumn(const std::string& /*table_name*/,
const std::string& /*column_name*/,
int /*multi_value_length*/) {
return 0;
}
int DataLog::NextRow(const std::string& /*table_name*/) {
return 0;
}
DataLogImpl::DataLogImpl() {
}
DataLogImpl::~DataLogImpl() {
}
DataLogImpl* DataLogImpl::StaticInstance() {
return NULL;
}
void DataLogImpl::ReturnLog() {
}
int DataLogImpl::AddTable(const std::string& /*table_name*/) {
return 0;
}
int DataLogImpl::AddColumn(const std::string& /*table_name*/,
const std::string& /*column_name*/,
int /*multi_value_length*/) {
return 0;
}
int DataLogImpl::InsertCell(const std::string& /*table_name*/,
const std::string& /*column_name*/,
const Container* /*value_container*/) {
return 0;
}
int DataLogImpl::NextRow(const std::string& /*table_name*/) {
return 0;
}
void DataLogImpl::Flush() {
}
bool DataLogImpl::Run(void* /*obj*/) {
return true;
}
void DataLogImpl::Process() {
}
void DataLogImpl::StopThread() {
}
} // namespace webrtc

View File

@@ -0,0 +1,311 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/system_wrappers/interface/data_log.h"
#include <map>
#include <string>
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/system_wrappers/interface/data_log_c.h"
#include "webrtc/system_wrappers/source/data_log_c_helpers_unittest.h"
using ::webrtc::DataLog;
// A class for storing the values expected from a log table column when
// verifying a log table file.
struct ExpectedValues {
public:
ExpectedValues()
: values(),
multi_value_length(1) {
}
ExpectedValues(std::vector<std::string> expected_values,
int expected_multi_value_length)
: values(expected_values),
multi_value_length(expected_multi_value_length) {
}
std::vector<std::string> values;
int multi_value_length;
};
typedef std::map<std::string, ExpectedValues> ExpectedValuesMap;
// A static class used for parsing and verifying data log files.
class DataLogParser {
public:
// Verifies that the log table stored in the file "log_file" corresponds to
// the cells and columns specified in "columns".
static int VerifyTable(FILE* log_file, const ExpectedValuesMap& columns) {
int row = 0;
char line_buffer[kMaxLineLength];
char* ret = fgets(line_buffer, kMaxLineLength, log_file);
EXPECT_FALSE(ret == NULL);
if (ret == NULL)
return -1;
std::string line(line_buffer, kMaxLineLength);
VerifyHeader(line, columns);
while (fgets(line_buffer, kMaxLineLength, log_file) != NULL) {
line = std::string(line_buffer, kMaxLineLength);
size_t line_position = 0;
for (ExpectedValuesMap::const_iterator it = columns.begin();
it != columns.end(); ++it) {
std::string str = ParseElement(line, &line_position,
it->second.multi_value_length);
EXPECT_EQ(str, it->second.values[row]);
if (str != it->second.values[row])
return -1;
}
++row;
}
return 0;
}
// Verifies the table header stored in "line" to correspond with the header
// specified in "columns".
static int VerifyHeader(const std::string& line,
const ExpectedValuesMap& columns) {
size_t line_position = 0;
for (ExpectedValuesMap::const_iterator it = columns.begin();
it != columns.end(); ++it) {
std::string str = ParseElement(line, &line_position,
it->second.multi_value_length);
EXPECT_EQ(str, it->first);
if (str != it->first)
return -1;
}
return 0;
}
// Parses out and returns one element from the string "line", which contains
// one line read from a log table file. An element can either be a column
// header or a cell of a row.
static std::string ParseElement(const std::string& line,
size_t* line_position,
int multi_value_length) {
std::string parsed_cell;
parsed_cell = "";
for (int i = 0; i < multi_value_length; ++i) {
size_t next_separator = line.find(',', *line_position);
EXPECT_NE(next_separator, std::string::npos);
if (next_separator == std::string::npos)
break;
parsed_cell += line.substr(*line_position,
next_separator - *line_position + 1);
*line_position = next_separator + 1;
}
return parsed_cell;
}
// This constant defines the maximum line length the DataLogParser can
// parse.
enum { kMaxLineLength = 100 };
};
TEST(TestDataLog, CreateReturnTest) {
for (int i = 0; i < 10; ++i)
ASSERT_EQ(DataLog::CreateLog(), 0);
ASSERT_EQ(DataLog::AddTable(DataLog::Combine("a proper table", 1)), 0);
for (int i = 0; i < 10; ++i)
DataLog::ReturnLog();
ASSERT_LT(DataLog::AddTable(DataLog::Combine("table failure", 1)), 0);
}
TEST(TestDataLog, VerifyCombineMethod) {
EXPECT_EQ(std::string("a proper table_1"),
DataLog::Combine("a proper table", 1));
}
TEST(TestDataLog, VerifySingleTable) {
DataLog::CreateLog();
DataLog::AddTable(DataLog::Combine("table", 1));
DataLog::AddColumn(DataLog::Combine("table", 1), "arrival", 1);
DataLog::AddColumn(DataLog::Combine("table", 1), "timestamp", 1);
DataLog::AddColumn(DataLog::Combine("table", 1), "size", 5);
uint32_t sizes[5] = {1400, 1500, 1600, 1700, 1800};
for (int i = 0; i < 10; ++i) {
DataLog::InsertCell(DataLog::Combine("table", 1), "arrival",
static_cast<double>(i));
DataLog::InsertCell(DataLog::Combine("table", 1), "timestamp",
static_cast<int64_t>(4354 + i));
DataLog::InsertCell(DataLog::Combine("table", 1), "size", sizes, 5);
DataLog::NextRow(DataLog::Combine("table", 1));
}
DataLog::ReturnLog();
// Verify file
FILE* table = fopen("table_1.txt", "r");
ASSERT_FALSE(table == NULL);
// Read the column names and verify with the expected columns.
// Note that the columns are written to file in alphabetical order.
// Data expected from parsing the file
const int kNumberOfRows = 10;
std::string string_arrival[kNumberOfRows] = {
"0,", "1,", "2,", "3,", "4,",
"5,", "6,", "7,", "8,", "9,"
};
std::string string_timestamp[kNumberOfRows] = {
"4354,", "4355,", "4356,", "4357,",
"4358,", "4359,", "4360,", "4361,",
"4362,", "4363,"
};
std::string string_sizes = "1400,1500,1600,1700,1800,";
ExpectedValuesMap expected;
expected["arrival,"] = ExpectedValues(
std::vector<std::string>(string_arrival,
string_arrival +
kNumberOfRows),
1);
expected["size[5],,,,,"] = ExpectedValues(
std::vector<std::string>(10, string_sizes), 5);
expected["timestamp,"] = ExpectedValues(
std::vector<std::string>(string_timestamp,
string_timestamp +
kNumberOfRows),
1);
ASSERT_EQ(DataLogParser::VerifyTable(table, expected), 0);
fclose(table);
}
TEST(TestDataLog, VerifyMultipleTables) {
DataLog::CreateLog();
DataLog::AddTable(DataLog::Combine("table", 2));
DataLog::AddTable(DataLog::Combine("table", 3));
DataLog::AddColumn(DataLog::Combine("table", 2), "arrival", 1);
DataLog::AddColumn(DataLog::Combine("table", 2), "timestamp", 1);
DataLog::AddColumn(DataLog::Combine("table", 2), "size", 1);
DataLog::AddTable(DataLog::Combine("table", 4));
DataLog::AddColumn(DataLog::Combine("table", 3), "timestamp", 1);
DataLog::AddColumn(DataLog::Combine("table", 3), "arrival", 1);
DataLog::AddColumn(DataLog::Combine("table", 4), "size", 1);
for (int32_t i = 0; i < 10; ++i) {
DataLog::InsertCell(DataLog::Combine("table", 2), "arrival",
static_cast<int32_t>(i));
DataLog::InsertCell(DataLog::Combine("table", 2), "timestamp",
static_cast<int32_t>(4354 + i));
DataLog::InsertCell(DataLog::Combine("table", 2), "size",
static_cast<int32_t>(1200 + 10 * i));
DataLog::InsertCell(DataLog::Combine("table", 3), "timestamp",
static_cast<int32_t>(4354 + i));
DataLog::InsertCell(DataLog::Combine("table", 3), "arrival",
static_cast<int32_t>(i));
DataLog::InsertCell(DataLog::Combine("table", 4), "size",
static_cast<int32_t>(1200 + 10 * i));
DataLog::NextRow(DataLog::Combine("table", 4));
DataLog::NextRow(DataLog::Combine("table", 2));
DataLog::NextRow(DataLog::Combine("table", 3));
}
DataLog::ReturnLog();
// Data expected from parsing the file
const int kNumberOfRows = 10;
std::string string_arrival[kNumberOfRows] = {
"0,", "1,", "2,", "3,", "4,",
"5,", "6,", "7,", "8,", "9,"
};
std::string string_timestamp[kNumberOfRows] = {
"4354,", "4355,", "4356,", "4357,",
"4358,", "4359,", "4360,", "4361,",
"4362,", "4363,"
};
std::string string_size[kNumberOfRows] = {
"1200,", "1210,", "1220,", "1230,",
"1240,", "1250,", "1260,", "1270,",
"1280,", "1290,"
};
// Verify table 2
{
FILE* table = fopen("table_2.txt", "r");
ASSERT_FALSE(table == NULL);
ExpectedValuesMap expected;
expected["arrival,"] = ExpectedValues(
std::vector<std::string>(string_arrival,
string_arrival +
kNumberOfRows),
1);
expected["size,"] = ExpectedValues(
std::vector<std::string>(string_size,
string_size + kNumberOfRows),
1);
expected["timestamp,"] = ExpectedValues(
std::vector<std::string>(string_timestamp,
string_timestamp +
kNumberOfRows),
1);
ASSERT_EQ(DataLogParser::VerifyTable(table, expected), 0);
fclose(table);
}
// Verify table 3
{
FILE* table = fopen("table_3.txt", "r");
ASSERT_FALSE(table == NULL);
ExpectedValuesMap expected;
expected["arrival,"] = ExpectedValues(
std::vector<std::string>(string_arrival,
string_arrival +
kNumberOfRows),
1);
expected["timestamp,"] = ExpectedValues(
std::vector<std::string>(string_timestamp,
string_timestamp +
kNumberOfRows),
1);
ASSERT_EQ(DataLogParser::VerifyTable(table, expected), 0);
fclose(table);
}
// Verify table 4
{
FILE* table = fopen("table_4.txt", "r");
ASSERT_FALSE(table == NULL);
ExpectedValuesMap expected;
expected["size,"] = ExpectedValues(
std::vector<std::string>(string_size,
string_size +
kNumberOfRows),
1);
ASSERT_EQ(DataLogParser::VerifyTable(table, expected), 0);
fclose(table);
}
}
TEST(TestDataLogCWrapper, VerifyCWrapper) {
// Simply call all C wrapper log functions through the C helper unittests.
// Main purpose is to make sure that the linkage is correct.
EXPECT_EQ(0, WebRtcDataLogCHelper_TestCreateLog());
EXPECT_EQ(0, WebRtcDataLogCHelper_TestCombine());
EXPECT_EQ(0, WebRtcDataLogCHelper_TestAddTable());
EXPECT_EQ(0, WebRtcDataLogCHelper_TestAddColumn());
EXPECT_EQ(0, WebRtcDataLogCHelper_TestInsertCell_int());
EXPECT_EQ(0, WebRtcDataLogCHelper_TestInsertArray_int());
EXPECT_EQ(0, WebRtcDataLogCHelper_TestNextRow());
EXPECT_EQ(0, WebRtcDataLogCHelper_TestInsertCell_float());
EXPECT_EQ(0, WebRtcDataLogCHelper_TestInsertArray_float());
EXPECT_EQ(0, WebRtcDataLogCHelper_TestNextRow());
EXPECT_EQ(0, WebRtcDataLogCHelper_TestInsertCell_double());
EXPECT_EQ(0, WebRtcDataLogCHelper_TestInsertArray_double());
EXPECT_EQ(0, WebRtcDataLogCHelper_TestNextRow());
EXPECT_EQ(0, WebRtcDataLogCHelper_TestInsertCell_int32());
EXPECT_EQ(0, WebRtcDataLogCHelper_TestInsertArray_int32());
EXPECT_EQ(0, WebRtcDataLogCHelper_TestNextRow());
EXPECT_EQ(0, WebRtcDataLogCHelper_TestInsertCell_uint32());
EXPECT_EQ(0, WebRtcDataLogCHelper_TestInsertArray_uint32());
EXPECT_EQ(0, WebRtcDataLogCHelper_TestNextRow());
EXPECT_EQ(0, WebRtcDataLogCHelper_TestInsertCell_int64());
EXPECT_EQ(0, WebRtcDataLogCHelper_TestInsertArray_int64());
EXPECT_EQ(0, WebRtcDataLogCHelper_TestNextRow());
EXPECT_EQ(0, WebRtcDataLogCHelper_TestReturnLog());
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/system_wrappers/interface/data_log.h"
#include <stdio.h>
#include "testing/gtest/include/gtest/gtest.h"
using ::webrtc::DataLog;
const char* kDataLogFileName = "table_1.txt";
void PerformLogging(const std::string& table_name) {
// Simulate normal DataTable logging behavior using this table name.
ASSERT_EQ(0, DataLog::AddTable(table_name));
ASSERT_EQ(0, DataLog::AddColumn(table_name, "test", 1));
for (int i = 0; i < 10; ++i) {
// TODO(kjellander): Check InsertCell result when the DataLog dummy is
// fixed.
DataLog::InsertCell(table_name, "test", static_cast<double>(i));
ASSERT_EQ(0, DataLog::NextRow(table_name));
}
}
// Simple test to verify DataLog is still working when the GYP variable
// enable_data_logging==0 (the default case).
TEST(TestDataLogDisabled, VerifyLoggingWorks) {
ASSERT_EQ(0, DataLog::CreateLog());
// Generate a table_name name and assure it's an empty string
// (dummy behavior).
std::string table_name = DataLog::Combine("table", 1);
ASSERT_EQ("", table_name);
PerformLogging(table_name);
DataLog::ReturnLog();
}
TEST(TestDataLogDisabled, EnsureNoFileIsWritten) {
// Remove any previous data files on disk:
remove(kDataLogFileName);
ASSERT_EQ(0, DataLog::CreateLog());
// Don't use the table name we would get from Combine on a disabled DataLog.
// Use "table_1" instead (which is what an enabled DataLog would give us).
PerformLogging("table_1");
DataLog::ReturnLog();
// Verify no data log file have been written:
ASSERT_EQ(NULL, fopen(kDataLogFileName, "r"));
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/system_wrappers/interface/event_wrapper.h"
#if defined(_WIN32)
#include <windows.h>
#include "webrtc/system_wrappers/source/event_win.h"
#elif defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
#include <ApplicationServices/ApplicationServices.h>
#include <pthread.h>
#include "webrtc/system_wrappers/source/event_posix.h"
#else
#include <pthread.h>
#include "webrtc/system_wrappers/source/event_posix.h"
#endif
namespace webrtc {
EventWrapper* EventWrapper::Create() {
#if defined(_WIN32)
return new EventWindows();
#else
return EventPosix::Create();
#endif
}
} // namespace webrtc

View File

@@ -0,0 +1,294 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/system_wrappers/source/event_posix.h"
#include <errno.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <unistd.h>
namespace webrtc {
const long int E6 = 1000000;
const long int E9 = 1000 * E6;
EventWrapper* EventPosix::Create() {
EventPosix* ptr = new EventPosix;
if (!ptr) {
return NULL;
}
const int error = ptr->Construct();
if (error) {
delete ptr;
return NULL;
}
return ptr;
}
EventPosix::EventPosix()
: timer_thread_(0),
timer_event_(0),
periodic_(false),
time_(0),
count_(0),
state_(kDown) {
}
int EventPosix::Construct() {
// Set start time to zero
memset(&created_at_, 0, sizeof(created_at_));
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
int result = pthread_mutex_init(&mutex_, &attr);
if (result != 0) {
return -1;
}
#ifdef WEBRTC_CLOCK_TYPE_REALTIME
result = pthread_cond_init(&cond_, 0);
if (result != 0) {
return -1;
}
#else
pthread_condattr_t cond_attr;
result = pthread_condattr_init(&cond_attr);
if (result != 0) {
return -1;
}
result = pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC);
if (result != 0) {
return -1;
}
result = pthread_cond_init(&cond_, &cond_attr);
if (result != 0) {
return -1;
}
result = pthread_condattr_destroy(&cond_attr);
if (result != 0) {
return -1;
}
#endif
return 0;
}
EventPosix::~EventPosix() {
StopTimer();
pthread_cond_destroy(&cond_);
pthread_mutex_destroy(&mutex_);
}
bool EventPosix::Reset() {
if (0 != pthread_mutex_lock(&mutex_)) {
return false;
}
state_ = kDown;
pthread_mutex_unlock(&mutex_);
return true;
}
bool EventPosix::Set() {
if (0 != pthread_mutex_lock(&mutex_)) {
return false;
}
state_ = kUp;
// Release all waiting threads
pthread_cond_broadcast(&cond_);
pthread_mutex_unlock(&mutex_);
return true;
}
EventTypeWrapper EventPosix::Wait(unsigned long timeout) {
int ret_val = 0;
if (0 != pthread_mutex_lock(&mutex_)) {
return kEventError;
}
if (kDown == state_) {
if (WEBRTC_EVENT_INFINITE != timeout) {
timespec end_at;
#ifndef WEBRTC_MAC
#ifdef WEBRTC_CLOCK_TYPE_REALTIME
clock_gettime(CLOCK_REALTIME, &end_at);
#else
clock_gettime(CLOCK_MONOTONIC, &end_at);
#endif
#else
timeval value;
struct timezone time_zone;
time_zone.tz_minuteswest = 0;
time_zone.tz_dsttime = 0;
gettimeofday(&value, &time_zone);
TIMEVAL_TO_TIMESPEC(&value, &end_at);
#endif
end_at.tv_sec += timeout / 1000;
end_at.tv_nsec += (timeout - (timeout / 1000) * 1000) * E6;
if (end_at.tv_nsec >= E9) {
end_at.tv_sec++;
end_at.tv_nsec -= E9;
}
ret_val = pthread_cond_timedwait(&cond_, &mutex_, &end_at);
} else {
ret_val = pthread_cond_wait(&cond_, &mutex_);
}
}
state_ = kDown;
pthread_mutex_unlock(&mutex_);
switch (ret_val) {
case 0:
return kEventSignaled;
case ETIMEDOUT:
return kEventTimeout;
default:
return kEventError;
}
}
EventTypeWrapper EventPosix::Wait(timespec& wake_at) {
int ret_val = 0;
if (0 != pthread_mutex_lock(&mutex_)) {
return kEventError;
}
if (kUp != state_) {
ret_val = pthread_cond_timedwait(&cond_, &mutex_, &wake_at);
}
state_ = kDown;
pthread_mutex_unlock(&mutex_);
switch (ret_val) {
case 0:
return kEventSignaled;
case ETIMEDOUT:
return kEventTimeout;
default:
return kEventError;
}
}
bool EventPosix::StartTimer(bool periodic, unsigned long time) {
pthread_mutex_lock(&mutex_);
if (timer_thread_) {
if (periodic_) {
// Timer already started.
pthread_mutex_unlock(&mutex_);
return false;
} else {
// New one shot timer
time_ = time;
created_at_.tv_sec = 0;
timer_event_->Set();
pthread_mutex_unlock(&mutex_);
return true;
}
}
// Start the timer thread
timer_event_ = static_cast<EventPosix*>(EventWrapper::Create());
const char* thread_name = "WebRtc_event_timer_thread";
timer_thread_ = ThreadWrapper::CreateThread(Run, this, kRealtimePriority,
thread_name);
periodic_ = periodic;
time_ = time;
unsigned int id = 0;
bool started = timer_thread_->Start(id);
pthread_mutex_unlock(&mutex_);
return started;
}
bool EventPosix::Run(ThreadObj obj) {
return static_cast<EventPosix*>(obj)->Process();
}
bool EventPosix::Process() {
pthread_mutex_lock(&mutex_);
if (created_at_.tv_sec == 0) {
#ifndef WEBRTC_MAC
#ifdef WEBRTC_CLOCK_TYPE_REALTIME
clock_gettime(CLOCK_REALTIME, &created_at_);
#else
clock_gettime(CLOCK_MONOTONIC, &created_at_);
#endif
#else
timeval value;
struct timezone time_zone;
time_zone.tz_minuteswest = 0;
time_zone.tz_dsttime = 0;
gettimeofday(&value, &time_zone);
TIMEVAL_TO_TIMESPEC(&value, &created_at_);
#endif
count_ = 0;
}
timespec end_at;
unsigned long long time = time_ * ++count_;
end_at.tv_sec = created_at_.tv_sec + time / 1000;
end_at.tv_nsec = created_at_.tv_nsec + (time - (time / 1000) * 1000) * E6;
if (end_at.tv_nsec >= E9) {
end_at.tv_sec++;
end_at.tv_nsec -= E9;
}
pthread_mutex_unlock(&mutex_);
switch (timer_event_->Wait(end_at)) {
case kEventSignaled:
return true;
case kEventError:
return false;
case kEventTimeout:
break;
}
pthread_mutex_lock(&mutex_);
if (periodic_ || count_ == 1)
Set();
pthread_mutex_unlock(&mutex_);
return true;
}
bool EventPosix::StopTimer() {
if (timer_thread_) {
timer_thread_->SetNotAlive();
}
if (timer_event_) {
timer_event_->Set();
}
if (timer_thread_) {
if (!timer_thread_->Stop()) {
return false;
}
delete timer_thread_;
timer_thread_ = 0;
}
if (timer_event_) {
delete timer_event_;
timer_event_ = 0;
}
// Set time to zero to force new reference time for the timer.
memset(&created_at_, 0, sizeof(created_at_));
count_ = 0;
return true;
}
} // namespace webrtc

View File

@@ -0,0 +1,65 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_EVENT_POSIX_H_
#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_EVENT_POSIX_H_
#include "webrtc/system_wrappers/interface/event_wrapper.h"
#include <pthread.h>
#include <time.h>
#include "webrtc/system_wrappers/interface/thread_wrapper.h"
namespace webrtc {
enum State {
kUp = 1,
kDown = 2
};
class EventPosix : public EventWrapper {
public:
static EventWrapper* Create();
virtual ~EventPosix();
virtual EventTypeWrapper Wait(unsigned long max_time) OVERRIDE;
virtual bool Set() OVERRIDE;
virtual bool Reset() OVERRIDE;
virtual bool StartTimer(bool periodic, unsigned long time) OVERRIDE;
virtual bool StopTimer() OVERRIDE;
private:
EventPosix();
int Construct();
static bool Run(ThreadObj obj);
bool Process();
EventTypeWrapper Wait(timespec& wake_at);
private:
pthread_cond_t cond_;
pthread_mutex_t mutex_;
ThreadWrapper* timer_thread_;
EventPosix* timer_event_;
timespec created_at_;
bool periodic_;
unsigned long time_; // In ms
unsigned long count_;
State state_;
};
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_EVENT_POSIX_H_

View File

@@ -0,0 +1,60 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/system_wrappers/interface/event_tracer.h"
namespace webrtc {
namespace {
GetCategoryEnabledPtr g_get_category_enabled_ptr = 0;
AddTraceEventPtr g_add_trace_event_ptr = 0;
} // namespace
void SetupEventTracer(GetCategoryEnabledPtr get_category_enabled_ptr,
AddTraceEventPtr add_trace_event_ptr) {
g_get_category_enabled_ptr = get_category_enabled_ptr;
g_add_trace_event_ptr = add_trace_event_ptr;
}
// static
const unsigned char* EventTracer::GetCategoryEnabled(const char* name) {
if (g_get_category_enabled_ptr)
return g_get_category_enabled_ptr(name);
// A string with null terminator means category is disabled.
return reinterpret_cast<const unsigned char*>("\0");
}
// static
void EventTracer::AddTraceEvent(char phase,
const unsigned char* category_enabled,
const char* name,
unsigned long long id,
int num_args,
const char** arg_names,
const unsigned char* arg_types,
const unsigned long long* arg_values,
unsigned char flags) {
if (g_add_trace_event_ptr) {
g_add_trace_event_ptr(phase,
category_enabled,
name,
id,
num_args,
arg_names,
arg_types,
arg_values,
flags);
}
}
} // namespace webrtc

View File

@@ -0,0 +1,82 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/system_wrappers/interface/event_tracer.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/system_wrappers/interface/static_instance.h"
#include "webrtc/system_wrappers/interface/trace_event.h"
namespace {
class TestStatistics {
public:
TestStatistics() : events_logged_(0) {
}
void Reset() {
events_logged_ = 0;
}
void Increment() {
++events_logged_;
}
int Count() const { return events_logged_; }
static TestStatistics* Get() {
static TestStatistics* test_stats = NULL;
if (!test_stats)
test_stats = new TestStatistics();
return test_stats;
}
private:
int events_logged_;
};
static const unsigned char* GetCategoryEnabledHandler(const char* name) {
return reinterpret_cast<const unsigned char*>("test");
}
static void AddTraceEventHandler(char phase,
const unsigned char* category_enabled,
const char* name,
unsigned long long id,
int num_args,
const char** arg_names,
const unsigned char* arg_types,
const unsigned long long* arg_values,
unsigned char flags) {
TestStatistics::Get()->Increment();
}
} // namespace
namespace webrtc {
TEST(EventTracerTest, EventTracerDisabled) {
{
TRACE_EVENT0("test", "EventTracerDisabled");
}
EXPECT_FALSE(TestStatistics::Get()->Count());
TestStatistics::Get()->Reset();
}
TEST(EventTracerTest, ScopedTraceEvent) {
SetupEventTracer(&GetCategoryEnabledHandler, &AddTraceEventHandler);
{
TRACE_EVENT0("test", "ScopedTraceEvent");
}
EXPECT_EQ(2, TestStatistics::Get()->Count());
TestStatistics::Get()->Reset();
}
} // namespace webrtc

View File

@@ -0,0 +1,77 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/system_wrappers/source/event_win.h"
#include "Mmsystem.h"
namespace webrtc {
EventWindows::EventWindows()
: event_(::CreateEvent(NULL, // security attributes
FALSE, // manual reset
FALSE, // initial state
NULL)), // name of event
timerID_(NULL) {
}
EventWindows::~EventWindows() {
StopTimer();
CloseHandle(event_);
}
bool EventWindows::Set() {
// Note: setting an event that is already set has no effect.
return SetEvent(event_) == 1;
}
bool EventWindows::Reset() {
return ResetEvent(event_) == 1;
}
EventTypeWrapper EventWindows::Wait(unsigned long max_time) {
unsigned long res = WaitForSingleObject(event_, max_time);
switch (res) {
case WAIT_OBJECT_0:
return kEventSignaled;
case WAIT_TIMEOUT:
return kEventTimeout;
default:
return kEventError;
}
}
bool EventWindows::StartTimer(bool periodic, unsigned long time) {
if (timerID_ != NULL) {
timeKillEvent(timerID_);
timerID_ = NULL;
}
if (periodic) {
timerID_ = timeSetEvent(time, 0, (LPTIMECALLBACK)HANDLE(event_), 0,
TIME_PERIODIC | TIME_CALLBACK_EVENT_PULSE);
} else {
timerID_ = timeSetEvent(time, 0, (LPTIMECALLBACK)HANDLE(event_), 0,
TIME_ONESHOT | TIME_CALLBACK_EVENT_SET);
}
return timerID_ != NULL;
}
bool EventWindows::StopTimer() {
if (timerID_ != NULL) {
timeKillEvent(timerID_);
timerID_ = NULL;
}
return true;
}
} // namespace webrtc

View File

@@ -0,0 +1,41 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_EVENT_WIN_H_
#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_EVENT_WIN_H_
#include <windows.h>
#include "webrtc/system_wrappers/interface/event_wrapper.h"
#include "webrtc/typedefs.h"
namespace webrtc {
class EventWindows : public EventWrapper {
public:
EventWindows();
virtual ~EventWindows();
virtual EventTypeWrapper Wait(unsigned long max_time);
virtual bool Set();
virtual bool Reset();
virtual bool StartTimer(bool periodic, unsigned long time);
virtual bool StopTimer();
private:
HANDLE event_;
uint32_t timerID_;
};
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_EVENT_WIN_H_

View File

@@ -0,0 +1,22 @@
// Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
//
#include "webrtc/system_wrappers/interface/field_trial.h"
// Clients of webrtc that do not want to configure field trials can link with
// this instead of providing their own implementation.
namespace webrtc {
namespace field_trial {
std::string FindFullName(const std::string& name) {
return std::string();
}
} // namespace field_trial
} // namespace webrtc

View File

@@ -0,0 +1,278 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/system_wrappers/source/file_impl.h"
#include <assert.h>
#ifdef _WIN32
#include <Windows.h>
#else
#include <stdarg.h>
#include <string.h>
#endif
#include "webrtc/system_wrappers/interface/rw_lock_wrapper.h"
namespace webrtc {
FileWrapper* FileWrapper::Create() {
return new FileWrapperImpl();
}
FileWrapperImpl::FileWrapperImpl()
: rw_lock_(RWLockWrapper::CreateRWLock()),
id_(NULL),
managed_file_handle_(true),
open_(false),
looping_(false),
read_only_(false),
max_size_in_bytes_(0),
size_in_bytes_(0) {
memset(file_name_utf8_, 0, kMaxFileNameSize);
}
FileWrapperImpl::~FileWrapperImpl() {
if (id_ != NULL && managed_file_handle_) {
fclose(id_);
}
}
int FileWrapperImpl::CloseFile() {
WriteLockScoped write(*rw_lock_);
return CloseFileImpl();
}
int FileWrapperImpl::Rewind() {
WriteLockScoped write(*rw_lock_);
if (looping_ || !read_only_) {
if (id_ != NULL) {
size_in_bytes_ = 0;
return fseek(id_, 0, SEEK_SET);
}
}
return -1;
}
int FileWrapperImpl::SetMaxFileSize(size_t bytes) {
WriteLockScoped write(*rw_lock_);
max_size_in_bytes_ = bytes;
return 0;
}
int FileWrapperImpl::Flush() {
WriteLockScoped write(*rw_lock_);
return FlushImpl();
}
int FileWrapperImpl::FileName(char* file_name_utf8, size_t size) const {
ReadLockScoped read(*rw_lock_);
size_t length = strlen(file_name_utf8_);
if (length > kMaxFileNameSize) {
assert(false);
return -1;
}
if (length < 1) {
return -1;
}
// Make sure to NULL terminate
if (size < length) {
length = size - 1;
}
memcpy(file_name_utf8, file_name_utf8_, length);
file_name_utf8[length] = 0;
return 0;
}
bool FileWrapperImpl::Open() const {
ReadLockScoped read(*rw_lock_);
return open_;
}
int FileWrapperImpl::OpenFile(const char* file_name_utf8, bool read_only,
bool loop, bool text) {
WriteLockScoped write(*rw_lock_);
if (id_ != NULL && !managed_file_handle_)
return -1;
size_t length = strlen(file_name_utf8);
if (length > kMaxFileNameSize - 1) {
return -1;
}
read_only_ = read_only;
FILE* tmp_id = NULL;
#if defined _WIN32
wchar_t wide_file_name[kMaxFileNameSize];
wide_file_name[0] = 0;
MultiByteToWideChar(CP_UTF8,
0, // UTF8 flag
file_name_utf8,
-1, // Null terminated string
wide_file_name,
kMaxFileNameSize);
if (text) {
if (read_only) {
tmp_id = _wfopen(wide_file_name, L"rt");
} else {
tmp_id = _wfopen(wide_file_name, L"wt");
}
} else {
if (read_only) {
tmp_id = _wfopen(wide_file_name, L"rb");
} else {
tmp_id = _wfopen(wide_file_name, L"wb");
}
}
#else
if (text) {
if (read_only) {
tmp_id = fopen(file_name_utf8, "rt");
} else {
tmp_id = fopen(file_name_utf8, "wt");
}
} else {
if (read_only) {
tmp_id = fopen(file_name_utf8, "rb");
} else {
tmp_id = fopen(file_name_utf8, "wb");
}
}
#endif
if (tmp_id != NULL) {
// +1 comes from copying the NULL termination character.
memcpy(file_name_utf8_, file_name_utf8, length + 1);
if (id_ != NULL) {
fclose(id_);
}
id_ = tmp_id;
managed_file_handle_ = true;
looping_ = loop;
open_ = true;
return 0;
}
return -1;
}
int FileWrapperImpl::OpenFromFileHandle(FILE* handle,
bool manage_file,
bool read_only,
bool loop) {
WriteLockScoped write(*rw_lock_);
if (!handle)
return -1;
if (id_ != NULL) {
if (managed_file_handle_)
fclose(id_);
else
return -1;
}
id_ = handle;
managed_file_handle_ = manage_file;
read_only_ = read_only;
looping_ = loop;
open_ = true;
return 0;
}
int FileWrapperImpl::Read(void* buf, int length) {
WriteLockScoped write(*rw_lock_);
if (length < 0)
return -1;
if (id_ == NULL)
return -1;
int bytes_read = static_cast<int>(fread(buf, 1, length, id_));
if (bytes_read != length && !looping_) {
CloseFileImpl();
}
return bytes_read;
}
int FileWrapperImpl::WriteText(const char* format, ...) {
WriteLockScoped write(*rw_lock_);
if (format == NULL)
return -1;
if (read_only_)
return -1;
if (id_ == NULL)
return -1;
va_list args;
va_start(args, format);
int num_chars = vfprintf(id_, format, args);
va_end(args);
if (num_chars >= 0) {
return num_chars;
} else {
CloseFileImpl();
return -1;
}
}
bool FileWrapperImpl::Write(const void* buf, int length) {
WriteLockScoped write(*rw_lock_);
if (buf == NULL)
return false;
if (length < 0)
return false;
if (read_only_)
return false;
if (id_ == NULL)
return false;
// Check if it's time to stop writing.
if (max_size_in_bytes_ > 0 &&
(size_in_bytes_ + length) > max_size_in_bytes_) {
FlushImpl();
return false;
}
size_t num_bytes = fwrite(buf, 1, length, id_);
if (num_bytes > 0) {
size_in_bytes_ += num_bytes;
return true;
}
CloseFileImpl();
return false;
}
int FileWrapperImpl::CloseFileImpl() {
if (id_ != NULL) {
if (managed_file_handle_)
fclose(id_);
id_ = NULL;
}
memset(file_name_utf8_, 0, kMaxFileNameSize);
open_ = false;
return 0;
}
int FileWrapperImpl::FlushImpl() {
if (id_ != NULL) {
return fflush(id_);
}
return -1;
}
} // namespace webrtc

View File

@@ -0,0 +1,70 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_FILE_IMPL_H_
#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_FILE_IMPL_H_
#include <stdio.h>
#include "webrtc/system_wrappers/interface/file_wrapper.h"
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
namespace webrtc {
class RWLockWrapper;
class FileWrapperImpl : public FileWrapper {
public:
FileWrapperImpl();
virtual ~FileWrapperImpl();
virtual int FileName(char* file_name_utf8,
size_t size) const OVERRIDE;
virtual bool Open() const OVERRIDE;
virtual int OpenFile(const char* file_name_utf8,
bool read_only,
bool loop = false,
bool text = false) OVERRIDE;
virtual int OpenFromFileHandle(FILE* handle,
bool manage_file,
bool read_only,
bool loop = false) OVERRIDE;
virtual int CloseFile() OVERRIDE;
virtual int SetMaxFileSize(size_t bytes) OVERRIDE;
virtual int Flush() OVERRIDE;
virtual int Read(void* buf, int length) OVERRIDE;
virtual bool Write(const void* buf, int length) OVERRIDE;
virtual int WriteText(const char* format, ...) OVERRIDE;
virtual int Rewind() OVERRIDE;
private:
int CloseFileImpl();
int FlushImpl();
scoped_ptr<RWLockWrapper> rw_lock_;
FILE* id_;
bool managed_file_handle_;
bool open_;
bool looping_;
bool read_only_;
size_t max_size_in_bytes_; // -1 indicates file size limitation is off
size_t size_in_bytes_;
char file_name_utf8_[kMaxFileNameSize];
};
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_FILE_IMPL_H_

View File

@@ -0,0 +1,63 @@
/*
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/system_wrappers/interface/logcat_trace_context.h"
#include <android/log.h>
#include <assert.h>
#include "webrtc/system_wrappers/interface/logging.h"
namespace webrtc {
static android_LogPriority AndroidLogPriorityFromWebRtcLogLevel(
TraceLevel webrtc_level) {
// NOTE: this mapping is somewhat arbitrary. StateInfo and Info are mapped
// to DEBUG because they are highly verbose in webrtc code (which is
// unfortunate).
switch (webrtc_level) {
case webrtc::kTraceStateInfo: return ANDROID_LOG_DEBUG;
case webrtc::kTraceWarning: return ANDROID_LOG_WARN;
case webrtc::kTraceError: return ANDROID_LOG_ERROR;
case webrtc::kTraceCritical: return ANDROID_LOG_FATAL;
case webrtc::kTraceApiCall: return ANDROID_LOG_VERBOSE;
case webrtc::kTraceModuleCall: return ANDROID_LOG_VERBOSE;
case webrtc::kTraceMemory: return ANDROID_LOG_VERBOSE;
case webrtc::kTraceTimer: return ANDROID_LOG_VERBOSE;
case webrtc::kTraceStream: return ANDROID_LOG_VERBOSE;
case webrtc::kTraceDebug: return ANDROID_LOG_DEBUG;
case webrtc::kTraceInfo: return ANDROID_LOG_DEBUG;
case webrtc::kTraceTerseInfo: return ANDROID_LOG_INFO;
default:
LOG(LS_ERROR) << "Unexpected log level" << webrtc_level;
return ANDROID_LOG_FATAL;
}
}
LogcatTraceContext::LogcatTraceContext() {
webrtc::Trace::CreateTrace();
if (webrtc::Trace::SetTraceCallback(this) != 0)
assert(false);
}
LogcatTraceContext::~LogcatTraceContext() {
if (webrtc::Trace::SetTraceCallback(NULL) != 0)
assert(false);
webrtc::Trace::ReturnTrace();
}
void LogcatTraceContext::Print(TraceLevel level,
const char* message,
int length) {
__android_log_print(AndroidLogPriorityFromWebRtcLogLevel(level),
"WEBRTC", "%.*s", length, message);
}
} // namespace webrtc

View File

@@ -0,0 +1,61 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/system_wrappers/interface/logging.h"
#include <string.h>
#include <sstream>
#include "webrtc/common_types.h"
#include "webrtc/system_wrappers/interface/trace.h"
namespace webrtc {
namespace {
TraceLevel WebRtcSeverity(LoggingSeverity sev) {
switch (sev) {
// TODO(ajm): SENSITIVE doesn't have a corresponding webrtc level.
case LS_SENSITIVE: return kTraceInfo;
case LS_VERBOSE: return kTraceInfo;
case LS_INFO: return kTraceTerseInfo;
case LS_WARNING: return kTraceWarning;
case LS_ERROR: return kTraceError;
default: return kTraceNone;
}
}
const char* DescribeFile(const char* file) {
const char* end1 = ::strrchr(file, '/');
const char* end2 = ::strrchr(file, '\\');
if (!end1 && !end2)
return file;
else
return (end1 > end2) ? end1 + 1 : end2 + 1;
}
} // namespace
LogMessage::LogMessage(const char* file, int line, LoggingSeverity sev)
: severity_(sev) {
print_stream_ << "(" << DescribeFile(file) << ":" << line << "): ";
}
bool LogMessage::Loggable(LoggingSeverity sev) {
// |level_filter| is a bitmask, unlike libjingle's minimum severity value.
return WebRtcSeverity(sev) & Trace::level_filter() ? true : false;
}
LogMessage::~LogMessage() {
const std::string& str = print_stream_.str();
Trace::Add(WebRtcSeverity(severity_), kTraceUndefined, 0, str.c_str());
}
} // namespace webrtc

View File

@@ -0,0 +1,89 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/system_wrappers/interface/logging.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/system_wrappers/interface/condition_variable_wrapper.h"
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
#include "webrtc/system_wrappers/interface/sleep.h"
#include "webrtc/system_wrappers/interface/trace.h"
namespace webrtc {
namespace {
class LoggingTest : public ::testing::Test, public TraceCallback {
public:
virtual void Print(TraceLevel level, const char* msg, int length) {
CriticalSectionScoped cs(crit_.get());
// We test the length here to ensure (with high likelihood) that only our
// traces will be tested.
if (level_ != kTraceNone && static_cast<int>(expected_log_.str().size()) ==
length - Trace::kBoilerplateLength - 1) {
EXPECT_EQ(level_, level);
EXPECT_EQ(expected_log_.str(), &msg[Trace::kBoilerplateLength]);
level_ = kTraceNone;
cv_->Wake();
}
}
protected:
LoggingTest()
: crit_(CriticalSectionWrapper::CreateCriticalSection()),
cv_(ConditionVariableWrapper::CreateConditionVariable()),
level_(kTraceNone),
expected_log_() {
}
void SetUp() {
Trace::CreateTrace();
Trace::SetTraceCallback(this);
}
void TearDown() {
Trace::SetTraceCallback(NULL);
Trace::ReturnTrace();
CriticalSectionScoped cs(crit_.get());
ASSERT_EQ(kTraceNone, level_) << "Print() was not called";
}
scoped_ptr<CriticalSectionWrapper> crit_;
scoped_ptr<ConditionVariableWrapper> cv_;
TraceLevel level_ GUARDED_BY(crit_);
std::ostringstream expected_log_ GUARDED_BY(crit_);
};
TEST_F(LoggingTest, LogStream) {
{
CriticalSectionScoped cs(crit_.get());
level_ = kTraceWarning;
std::string msg = "Important message";
expected_log_ << "(logging_unittest.cc:" << __LINE__ + 1 << "): " << msg;
LOG(LS_WARNING) << msg;
cv_->SleepCS(*crit_.get(), 2000);
}
}
TEST_F(LoggingTest, LogFunctionError) {
{
CriticalSectionScoped cs(crit_.get());
int bar = 42;
int baz = 99;
level_ = kTraceError;
expected_log_ << "(logging_unittest.cc:" << __LINE__ + 2
<< "): Foo failed: bar=" << bar << ", baz=" << baz;
LOG_FERR2(LS_ERROR, Foo, bar, baz);
cv_->SleepCS(*crit_.get(), 2000);
}
}
} // namespace
} // namespace webrtc

View File

@@ -0,0 +1,226 @@
/*
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// Borrowed from Chromium's src/base/move.h.
#ifndef WEBRTC_SYSTEM_WRAPPERS_INTEFACE_MOVE_H_
#define WEBRTC_SYSTEM_WRAPPERS_INTEFACE_MOVE_H_
// Macro with the boilerplate that makes a type move-only in C++03.
//
// USAGE
//
// This macro should be used instead of DISALLOW_COPY_AND_ASSIGN to create
// a "move-only" type. Unlike DISALLOW_COPY_AND_ASSIGN, this macro should be
// the first line in a class declaration.
//
// A class using this macro must call .Pass() (or somehow be an r-value already)
// before it can be:
//
// * Passed as a function argument
// * Used as the right-hand side of an assignment
// * Returned from a function
//
// Each class will still need to define their own "move constructor" and "move
// operator=" to make this useful. Here's an example of the macro, the move
// constructor, and the move operator= from the scoped_ptr class:
//
// template <typename T>
// class scoped_ptr {
// MOVE_ONLY_TYPE_FOR_CPP_03(scoped_ptr, RValue)
// public:
// scoped_ptr(RValue& other) : ptr_(other.release()) { }
// scoped_ptr& operator=(RValue& other) {
// swap(other);
// return *this;
// }
// };
//
// Note that the constructor must NOT be marked explicit.
//
// For consistency, the second parameter to the macro should always be RValue
// unless you have a strong reason to do otherwise. It is only exposed as a
// macro parameter so that the move constructor and move operator= don't look
// like they're using a phantom type.
//
//
// HOW THIS WORKS
//
// For a thorough explanation of this technique, see:
//
// http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Move_Constructor
//
// The summary is that we take advantage of 2 properties:
//
// 1) non-const references will not bind to r-values.
// 2) C++ can apply one user-defined conversion when initializing a
// variable.
//
// The first lets us disable the copy constructor and assignment operator
// by declaring private version of them with a non-const reference parameter.
//
// For l-values, direct initialization still fails like in
// DISALLOW_COPY_AND_ASSIGN because the copy constructor and assignment
// operators are private.
//
// For r-values, the situation is different. The copy constructor and
// assignment operator are not viable due to (1), so we are trying to call
// a non-existent constructor and non-existing operator= rather than a private
// one. Since we have not committed an error quite yet, we can provide an
// alternate conversion sequence and a constructor. We add
//
// * a private struct named "RValue"
// * a user-defined conversion "operator RValue()"
// * a "move constructor" and "move operator=" that take the RValue& as
// their sole parameter.
//
// Only r-values will trigger this sequence and execute our "move constructor"
// or "move operator=." L-values will match the private copy constructor and
// operator= first giving a "private in this context" error. This combination
// gives us a move-only type.
//
// For signaling a destructive transfer of data from an l-value, we provide a
// method named Pass() which creates an r-value for the current instance
// triggering the move constructor or move operator=.
//
// Other ways to get r-values is to use the result of an expression like a
// function call.
//
// Here's an example with comments explaining what gets triggered where:
//
// class Foo {
// MOVE_ONLY_TYPE_FOR_CPP_03(Foo, RValue);
//
// public:
// ... API ...
// Foo(RValue other); // Move constructor.
// Foo& operator=(RValue rhs); // Move operator=
// };
//
// Foo MakeFoo(); // Function that returns a Foo.
//
// Foo f;
// Foo f_copy(f); // ERROR: Foo(Foo&) is private in this context.
// Foo f_assign;
// f_assign = f; // ERROR: operator=(Foo&) is private in this context.
//
//
// Foo f(MakeFoo()); // R-value so alternate conversion executed.
// Foo f_copy(f.Pass()); // R-value so alternate conversion executed.
// f = f_copy.Pass(); // R-value so alternate conversion executed.
//
//
// IMPLEMENTATION SUBTLETIES WITH RValue
//
// The RValue struct is just a container for a pointer back to the original
// object. It should only ever be created as a temporary, and no external
// class should ever declare it or use it in a parameter.
//
// It is tempting to want to use the RValue type in function parameters, but
// excluding the limited usage here for the move constructor and move
// operator=, doing so would mean that the function could take both r-values
// and l-values equially which is unexpected. See COMPARED To Boost.Move for
// more details.
//
// An alternate, and incorrect, implementation of the RValue class used by
// Boost.Move makes RValue a fieldless child of the move-only type. RValue&
// is then used in place of RValue in the various operators. The RValue& is
// "created" by doing *reinterpret_cast<RValue*>(this). This has the appeal
// of never creating a temporary RValue struct even with optimizations
// disabled. Also, by virtue of inheritance you can treat the RValue
// reference as if it were the move-only type itself. Unfortunately,
// using the result of this reinterpret_cast<> is actually undefined behavior
// due to C++98 5.2.10.7. In certain compilers (e.g., NaCl) the optimizer
// will generate non-working code.
//
// In optimized builds, both implementations generate the same assembly so we
// choose the one that adheres to the standard.
//
//
// WHY HAVE typedef void MoveOnlyTypeForCPP03
//
// Callback<>/Bind() needs to understand movable-but-not-copyable semantics
// to call .Pass() appropriately when it is expected to transfer the value.
// The cryptic typedef MoveOnlyTypeForCPP03 is added to make this check
// easy and automatic in helper templates for Callback<>/Bind().
// See IsMoveOnlyType template and its usage in base/callback_internal.h
// for more details.
//
//
// COMPARED TO C++11
//
// In C++11, you would implement this functionality using an r-value reference
// and our .Pass() method would be replaced with a call to std::move().
//
// This emulation also has a deficiency where it uses up the single
// user-defined conversion allowed by C++ during initialization. This can
// cause problems in some API edge cases. For instance, in scoped_ptr, it is
// impossible to make a function "void Foo(scoped_ptr<Parent> p)" accept a
// value of type scoped_ptr<Child> even if you add a constructor to
// scoped_ptr<> that would make it look like it should work. C++11 does not
// have this deficiency.
//
//
// COMPARED TO Boost.Move
//
// Our implementation similar to Boost.Move, but we keep the RValue struct
// private to the move-only type, and we don't use the reinterpret_cast<> hack.
//
// In Boost.Move, RValue is the boost::rv<> template. This type can be used
// when writing APIs like:
//
// void MyFunc(boost::rv<Foo>& f)
//
// that can take advantage of rv<> to avoid extra copies of a type. However you
// would still be able to call this version of MyFunc with an l-value:
//
// Foo f;
// MyFunc(f); // Uh oh, we probably just destroyed |f| w/o calling Pass().
//
// unless someone is very careful to also declare a parallel override like:
//
// void MyFunc(const Foo& f)
//
// that would catch the l-values first. This was declared unsafe in C++11 and
// a C++11 compiler will explicitly fail MyFunc(f). Unfortunately, we cannot
// ensure this in C++03.
//
// Since we have no need for writing such APIs yet, our implementation keeps
// RValue private and uses a .Pass() method to do the conversion instead of
// trying to write a version of "std::move()." Writing an API like std::move()
// would require the RValue struct to be public.
//
//
// CAVEATS
//
// If you include a move-only type as a field inside a class that does not
// explicitly declare a copy constructor, the containing class's implicit
// copy constructor will change from Containing(const Containing&) to
// Containing(Containing&). This can cause some unexpected errors.
//
// http://llvm.org/bugs/show_bug.cgi?id=11528
//
// The workaround is to explicitly declare your copy constructor.
//
#define WEBRTC_MOVE_ONLY_TYPE_FOR_CPP_03(type, rvalue_type) \
private: \
struct rvalue_type { \
explicit rvalue_type(type* object) : object(object) {} \
type* object; \
}; \
type(type&); \
void operator=(type&); \
public: \
operator rvalue_type() { return rvalue_type(this); } \
type Pass() { return type(rvalue_type(this)); } \
typedef void MoveOnlyTypeForCPP03; \
private:
#endif // WEBRTC_SYSTEM_WRAPPERS_INTEFACE_MOVE_H_

View File

@@ -0,0 +1,150 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/system_wrappers/interface/rtp_to_ntp.h"
#include "webrtc/system_wrappers/interface/clock.h"
#include <assert.h>
namespace webrtc {
RtcpMeasurement::RtcpMeasurement()
: ntp_secs(0), ntp_frac(0), rtp_timestamp(0) {}
RtcpMeasurement::RtcpMeasurement(uint32_t ntp_secs, uint32_t ntp_frac,
uint32_t timestamp)
: ntp_secs(ntp_secs), ntp_frac(ntp_frac), rtp_timestamp(timestamp) {}
// Calculates the RTP timestamp frequency from two pairs of NTP and RTP
// timestamps.
bool CalculateFrequency(
int64_t rtcp_ntp_ms1,
uint32_t rtp_timestamp1,
int64_t rtcp_ntp_ms2,
uint32_t rtp_timestamp2,
double* frequency_khz) {
if (rtcp_ntp_ms1 <= rtcp_ntp_ms2) {
return false;
}
*frequency_khz = static_cast<double>(rtp_timestamp1 - rtp_timestamp2) /
static_cast<double>(rtcp_ntp_ms1 - rtcp_ntp_ms2);
return true;
}
// Detects if there has been a wraparound between |old_timestamp| and
// |new_timestamp|, and compensates by adding 2^32 if that is the case.
bool CompensateForWrapAround(uint32_t new_timestamp,
uint32_t old_timestamp,
int64_t* compensated_timestamp) {
assert(compensated_timestamp);
int64_t wraps = CheckForWrapArounds(new_timestamp, old_timestamp);
if (wraps < 0) {
// Reordering, don't use this packet.
return false;
}
*compensated_timestamp = new_timestamp + (wraps << 32);
return true;
}
bool UpdateRtcpList(uint32_t ntp_secs,
uint32_t ntp_frac,
uint32_t rtp_timestamp,
RtcpList* rtcp_list,
bool* new_rtcp_sr) {
*new_rtcp_sr = false;
if (ntp_secs == 0 && ntp_frac == 0) {
return false;
}
RtcpMeasurement measurement;
measurement.ntp_secs = ntp_secs;
measurement.ntp_frac = ntp_frac;
measurement.rtp_timestamp = rtp_timestamp;
for (RtcpList::iterator it = rtcp_list->begin();
it != rtcp_list->end(); ++it) {
if (measurement.ntp_secs == (*it).ntp_secs &&
measurement.ntp_frac == (*it).ntp_frac) {
// This RTCP has already been added to the list.
return true;
}
}
// We need two RTCP SR reports to map between RTP and NTP. More than two will
// not improve the mapping.
if (rtcp_list->size() == 2) {
rtcp_list->pop_back();
}
rtcp_list->push_front(measurement);
*new_rtcp_sr = true;
return true;
}
// Converts |rtp_timestamp| to the NTP time base using the NTP and RTP timestamp
// pairs in |rtcp|. The converted timestamp is returned in
// |rtp_timestamp_in_ms|. This function compensates for wrap arounds in RTP
// timestamps and returns false if it can't do the conversion due to reordering.
bool RtpToNtpMs(int64_t rtp_timestamp,
const RtcpList& rtcp,
int64_t* rtp_timestamp_in_ms) {
assert(rtcp.size() == 2);
int64_t rtcp_ntp_ms_new = Clock::NtpToMs(rtcp.front().ntp_secs,
rtcp.front().ntp_frac);
int64_t rtcp_ntp_ms_old = Clock::NtpToMs(rtcp.back().ntp_secs,
rtcp.back().ntp_frac);
int64_t rtcp_timestamp_new = rtcp.front().rtp_timestamp;
int64_t rtcp_timestamp_old = rtcp.back().rtp_timestamp;
if (!CompensateForWrapAround(rtcp_timestamp_new,
rtcp_timestamp_old,
&rtcp_timestamp_new)) {
return false;
}
double freq_khz;
if (!CalculateFrequency(rtcp_ntp_ms_new,
rtcp_timestamp_new,
rtcp_ntp_ms_old,
rtcp_timestamp_old,
&freq_khz)) {
return false;
}
double offset = rtcp_timestamp_new - freq_khz * rtcp_ntp_ms_new;
int64_t rtp_timestamp_unwrapped;
if (!CompensateForWrapAround(rtp_timestamp, rtcp_timestamp_old,
&rtp_timestamp_unwrapped)) {
return false;
}
double rtp_timestamp_ntp_ms = (static_cast<double>(rtp_timestamp_unwrapped) -
offset) / freq_khz + 0.5f;
if (rtp_timestamp_ntp_ms < 0) {
return false;
}
*rtp_timestamp_in_ms = rtp_timestamp_ntp_ms;
return true;
}
int CheckForWrapArounds(uint32_t new_timestamp, uint32_t old_timestamp) {
if (new_timestamp < old_timestamp) {
// This difference should be less than -2^31 if we have had a wrap around
// (e.g. |new_timestamp| = 1, |rtcp_rtp_timestamp| = 2^32 - 1). Since it is
// cast to a int32_t, it should be positive.
if (static_cast<int32_t>(new_timestamp - old_timestamp) > 0) {
// Forward wrap around.
return 1;
}
} else if (static_cast<int32_t>(old_timestamp - new_timestamp) > 0) {
// This difference should be less than -2^31 if we have had a backward wrap
// around. Since it is cast to a int32_t, it should be positive.
return -1;
}
return 0;
}
} // namespace webrtc

View File

@@ -0,0 +1,146 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/system_wrappers/interface/rtp_to_ntp.h"
namespace webrtc {
TEST(WrapAroundTests, NoWrap) {
EXPECT_EQ(0, CheckForWrapArounds(0xFFFFFFFF, 0xFFFFFFFE));
EXPECT_EQ(0, CheckForWrapArounds(1, 0));
EXPECT_EQ(0, CheckForWrapArounds(0x00010000, 0x0000FFFF));
}
TEST(WrapAroundTests, ForwardWrap) {
EXPECT_EQ(1, CheckForWrapArounds(0, 0xFFFFFFFF));
EXPECT_EQ(1, CheckForWrapArounds(0, 0xFFFF0000));
EXPECT_EQ(1, CheckForWrapArounds(0x0000FFFF, 0xFFFFFFFF));
EXPECT_EQ(1, CheckForWrapArounds(0x0000FFFF, 0xFFFF0000));
}
TEST(WrapAroundTests, BackwardWrap) {
EXPECT_EQ(-1, CheckForWrapArounds(0xFFFFFFFF, 0));
EXPECT_EQ(-1, CheckForWrapArounds(0xFFFF0000, 0));
EXPECT_EQ(-1, CheckForWrapArounds(0xFFFFFFFF, 0x0000FFFF));
EXPECT_EQ(-1, CheckForWrapArounds(0xFFFF0000, 0x0000FFFF));
}
TEST(WrapAroundTests, OldRtcpWrapped) {
RtcpList rtcp;
uint32_t ntp_sec = 0;
uint32_t ntp_frac = 0;
uint32_t timestamp = 0;
const uint32_t kOneMsInNtpFrac = 4294967;
const uint32_t kTimestampTicksPerMs = 90;
rtcp.push_front(RtcpMeasurement(ntp_sec, ntp_frac, timestamp));
ntp_frac += kOneMsInNtpFrac;
timestamp -= kTimestampTicksPerMs;
rtcp.push_front(RtcpMeasurement(ntp_sec, ntp_frac, timestamp));
ntp_frac += kOneMsInNtpFrac;
timestamp -= kTimestampTicksPerMs;
int64_t timestamp_in_ms = -1;
// This expected to fail since it's highly unlikely that the older RTCP
// has a much smaller RTP timestamp than the newer.
EXPECT_FALSE(RtpToNtpMs(timestamp, rtcp, &timestamp_in_ms));
}
TEST(WrapAroundTests, NewRtcpWrapped) {
RtcpList rtcp;
uint32_t ntp_sec = 0;
uint32_t ntp_frac = 0;
uint32_t timestamp = 0xFFFFFFFF;
const uint32_t kOneMsInNtpFrac = 4294967;
const uint32_t kTimestampTicksPerMs = 90;
rtcp.push_front(RtcpMeasurement(ntp_sec, ntp_frac, timestamp));
ntp_frac += kOneMsInNtpFrac;
timestamp += kTimestampTicksPerMs;
rtcp.push_front(RtcpMeasurement(ntp_sec, ntp_frac, timestamp));
int64_t timestamp_in_ms = -1;
EXPECT_TRUE(RtpToNtpMs(rtcp.back().rtp_timestamp, rtcp, &timestamp_in_ms));
// Since this RTP packet has the same timestamp as the RTCP packet constructed
// at time 0 it should be mapped to 0 as well.
EXPECT_EQ(0, timestamp_in_ms);
}
TEST(WrapAroundTests, RtpWrapped) {
const uint32_t kOneMsInNtpFrac = 4294967;
const uint32_t kTimestampTicksPerMs = 90;
RtcpList rtcp;
uint32_t ntp_sec = 0;
uint32_t ntp_frac = 0;
uint32_t timestamp = 0xFFFFFFFF - 2 * kTimestampTicksPerMs;
rtcp.push_front(RtcpMeasurement(ntp_sec, ntp_frac, timestamp));
ntp_frac += kOneMsInNtpFrac;
timestamp += kTimestampTicksPerMs;
rtcp.push_front(RtcpMeasurement(ntp_sec, ntp_frac, timestamp));
ntp_frac += kOneMsInNtpFrac;
timestamp += kTimestampTicksPerMs;
int64_t timestamp_in_ms = -1;
EXPECT_TRUE(RtpToNtpMs(timestamp, rtcp, &timestamp_in_ms));
// Since this RTP packet has the same timestamp as the RTCP packet constructed
// at time 0 it should be mapped to 0 as well.
EXPECT_EQ(2, timestamp_in_ms);
}
TEST(WrapAroundTests, OldRtp_RtcpsWrapped) {
const uint32_t kOneMsInNtpFrac = 4294967;
const uint32_t kTimestampTicksPerMs = 90;
RtcpList rtcp;
uint32_t ntp_sec = 0;
uint32_t ntp_frac = 0;
uint32_t timestamp = 0;
rtcp.push_front(RtcpMeasurement(ntp_sec, ntp_frac, timestamp));
ntp_frac += kOneMsInNtpFrac;
timestamp += kTimestampTicksPerMs;
rtcp.push_front(RtcpMeasurement(ntp_sec, ntp_frac, timestamp));
ntp_frac += kOneMsInNtpFrac;
timestamp -= 2*kTimestampTicksPerMs;
int64_t timestamp_in_ms = -1;
EXPECT_FALSE(RtpToNtpMs(timestamp, rtcp, &timestamp_in_ms));
}
TEST(WrapAroundTests, OldRtp_NewRtcpWrapped) {
const uint32_t kOneMsInNtpFrac = 4294967;
const uint32_t kTimestampTicksPerMs = 90;
RtcpList rtcp;
uint32_t ntp_sec = 0;
uint32_t ntp_frac = 0;
uint32_t timestamp = 0xFFFFFFFF;
rtcp.push_front(RtcpMeasurement(ntp_sec, ntp_frac, timestamp));
ntp_frac += kOneMsInNtpFrac;
timestamp += kTimestampTicksPerMs;
rtcp.push_front(RtcpMeasurement(ntp_sec, ntp_frac, timestamp));
ntp_frac += kOneMsInNtpFrac;
timestamp -= kTimestampTicksPerMs;
int64_t timestamp_in_ms = -1;
EXPECT_TRUE(RtpToNtpMs(timestamp, rtcp, &timestamp_in_ms));
// Constructed at the same time as the first RTCP and should therefore be
// mapped to zero.
EXPECT_EQ(0, timestamp_in_ms);
}
TEST(WrapAroundTests, OldRtp_OldRtcpWrapped) {
const uint32_t kOneMsInNtpFrac = 4294967;
const uint32_t kTimestampTicksPerMs = 90;
RtcpList rtcp;
uint32_t ntp_sec = 0;
uint32_t ntp_frac = 0;
uint32_t timestamp = 0;
rtcp.push_front(RtcpMeasurement(ntp_sec, ntp_frac, timestamp));
ntp_frac += kOneMsInNtpFrac;
timestamp -= kTimestampTicksPerMs;
rtcp.push_front(RtcpMeasurement(ntp_sec, ntp_frac, timestamp));
ntp_frac += kOneMsInNtpFrac;
timestamp += 2*kTimestampTicksPerMs;
int64_t timestamp_in_ms = -1;
EXPECT_FALSE(RtpToNtpMs(timestamp, rtcp, &timestamp_in_ms));
}
}; // namespace webrtc

View File

@@ -0,0 +1,37 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/system_wrappers/interface/rw_lock_wrapper.h"
#include <assert.h>
#if defined(_WIN32)
#include "webrtc/system_wrappers/source/rw_lock_generic.h"
#include "webrtc/system_wrappers/source/rw_lock_win.h"
#else
#include "webrtc/system_wrappers/source/rw_lock_posix.h"
#endif
namespace webrtc {
RWLockWrapper* RWLockWrapper::CreateRWLock() {
#ifdef _WIN32
// Native implementation is faster, so use that if available.
RWLockWrapper* lock = RWLockWin::Create();
if (lock) {
return lock;
}
return new RWLockGeneric();
#else
return RWLockPosix::Create();
#endif
}
} // namespace webrtc

View File

@@ -0,0 +1,77 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/system_wrappers/source/rw_lock_generic.h"
#include "webrtc/system_wrappers/interface/condition_variable_wrapper.h"
#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
namespace webrtc {
RWLockGeneric::RWLockGeneric()
: readers_active_(0),
writer_active_(false),
readers_waiting_(0),
writers_waiting_(0) {
critical_section_ = CriticalSectionWrapper::CreateCriticalSection();
read_condition_ = ConditionVariableWrapper::CreateConditionVariable();
write_condition_ = ConditionVariableWrapper::CreateConditionVariable();
}
RWLockGeneric::~RWLockGeneric() {
delete write_condition_;
delete read_condition_;
delete critical_section_;
}
void RWLockGeneric::AcquireLockExclusive() {
CriticalSectionScoped cs(critical_section_);
if (writer_active_ || readers_active_ > 0) {
++writers_waiting_;
while (writer_active_ || readers_active_ > 0) {
write_condition_->SleepCS(*critical_section_);
}
--writers_waiting_;
}
writer_active_ = true;
}
void RWLockGeneric::ReleaseLockExclusive() {
CriticalSectionScoped cs(critical_section_);
writer_active_ = false;
if (writers_waiting_ > 0) {
write_condition_->Wake();
} else if (readers_waiting_ > 0) {
read_condition_->WakeAll();
}
}
void RWLockGeneric::AcquireLockShared() {
CriticalSectionScoped cs(critical_section_);
if (writer_active_ || writers_waiting_ > 0) {
++readers_waiting_;
while (writer_active_ || writers_waiting_ > 0) {
read_condition_->SleepCS(*critical_section_);
}
--readers_waiting_;
}
++readers_active_;
}
void RWLockGeneric::ReleaseLockShared() {
CriticalSectionScoped cs(critical_section_);
--readers_active_;
if (readers_active_ == 0 && writers_waiting_ > 0) {
write_condition_->Wake();
}
}
} // namespace webrtc

View File

@@ -0,0 +1,46 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_GENERIC_H_
#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_GENERIC_H_
#include "webrtc/system_wrappers/interface/rw_lock_wrapper.h"
#include "webrtc/typedefs.h"
namespace webrtc {
class CriticalSectionWrapper;
class ConditionVariableWrapper;
class RWLockGeneric : public RWLockWrapper {
public:
RWLockGeneric();
virtual ~RWLockGeneric();
virtual void AcquireLockExclusive() OVERRIDE;
virtual void ReleaseLockExclusive() OVERRIDE;
virtual void AcquireLockShared() OVERRIDE;
virtual void ReleaseLockShared() OVERRIDE;
private:
CriticalSectionWrapper* critical_section_;
ConditionVariableWrapper* read_condition_;
ConditionVariableWrapper* write_condition_;
int readers_active_;
bool writer_active_;
int readers_waiting_;
int writers_waiting_;
};
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_GENERIC_H_

View File

@@ -0,0 +1,51 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/system_wrappers/source/rw_lock_posix.h"
namespace webrtc {
RWLockPosix::RWLockPosix() : lock_() {
}
RWLockPosix::~RWLockPosix() {
pthread_rwlock_destroy(&lock_);
}
RWLockPosix* RWLockPosix::Create() {
RWLockPosix* ret_val = new RWLockPosix();
if (!ret_val->Init()) {
delete ret_val;
return NULL;
}
return ret_val;
}
bool RWLockPosix::Init() {
return pthread_rwlock_init(&lock_, 0) == 0;
}
void RWLockPosix::AcquireLockExclusive() {
pthread_rwlock_wrlock(&lock_);
}
void RWLockPosix::ReleaseLockExclusive() {
pthread_rwlock_unlock(&lock_);
}
void RWLockPosix::AcquireLockShared() {
pthread_rwlock_rdlock(&lock_);
}
void RWLockPosix::ReleaseLockShared() {
pthread_rwlock_unlock(&lock_);
}
} // namespace webrtc

View File

@@ -0,0 +1,41 @@
/*
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_POSIX_H_
#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_POSIX_H_
#include "webrtc/system_wrappers/interface/rw_lock_wrapper.h"
#include "webrtc/typedefs.h"
#include <pthread.h>
namespace webrtc {
class RWLockPosix : public RWLockWrapper {
public:
static RWLockPosix* Create();
virtual ~RWLockPosix();
virtual void AcquireLockExclusive() OVERRIDE;
virtual void ReleaseLockExclusive() OVERRIDE;
virtual void AcquireLockShared() OVERRIDE;
virtual void ReleaseLockShared() OVERRIDE;
private:
RWLockPosix();
bool Init();
pthread_rwlock_t lock_;
};
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_POSIX_H_

View File

@@ -0,0 +1,97 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/system_wrappers/source/rw_lock_win.h"
#include "webrtc/system_wrappers/interface/trace.h"
namespace webrtc {
static bool native_rw_locks_supported = false;
static bool module_load_attempted = false;
static HMODULE library = NULL;
typedef void (WINAPI* InitializeSRWLock)(PSRWLOCK);
typedef void (WINAPI* AcquireSRWLockExclusive)(PSRWLOCK);
typedef void (WINAPI* ReleaseSRWLockExclusive)(PSRWLOCK);
typedef void (WINAPI* AcquireSRWLockShared)(PSRWLOCK);
typedef void (WINAPI* ReleaseSRWLockShared)(PSRWLOCK);
InitializeSRWLock initialize_srw_lock;
AcquireSRWLockExclusive acquire_srw_lock_exclusive;
AcquireSRWLockShared acquire_srw_lock_shared;
ReleaseSRWLockShared release_srw_lock_shared;
ReleaseSRWLockExclusive release_srw_lock_exclusive;
RWLockWin::RWLockWin() {
initialize_srw_lock(&lock_);
}
RWLockWin* RWLockWin::Create() {
if (!LoadModule()) {
return NULL;
}
return new RWLockWin();
}
void RWLockWin::AcquireLockExclusive() {
acquire_srw_lock_exclusive(&lock_);
}
void RWLockWin::ReleaseLockExclusive() {
release_srw_lock_exclusive(&lock_);
}
void RWLockWin::AcquireLockShared() {
acquire_srw_lock_shared(&lock_);
}
void RWLockWin::ReleaseLockShared() {
release_srw_lock_shared(&lock_);
}
bool RWLockWin::LoadModule() {
if (module_load_attempted) {
return native_rw_locks_supported;
}
module_load_attempted = true;
// Use native implementation if supported (i.e Vista+)
library = LoadLibrary(TEXT("Kernel32.dll"));
if (!library) {
return false;
}
WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, "Loaded Kernel.dll");
initialize_srw_lock =
(InitializeSRWLock)GetProcAddress(library, "InitializeSRWLock");
acquire_srw_lock_exclusive =
(AcquireSRWLockExclusive)GetProcAddress(library,
"AcquireSRWLockExclusive");
release_srw_lock_exclusive =
(ReleaseSRWLockExclusive)GetProcAddress(library,
"ReleaseSRWLockExclusive");
acquire_srw_lock_shared =
(AcquireSRWLockShared)GetProcAddress(library, "AcquireSRWLockShared");
release_srw_lock_shared =
(ReleaseSRWLockShared)GetProcAddress(library, "ReleaseSRWLockShared");
if (initialize_srw_lock && acquire_srw_lock_exclusive &&
release_srw_lock_exclusive && acquire_srw_lock_shared &&
release_srw_lock_shared) {
WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, "Loaded Native RW Lock");
native_rw_locks_supported = true;
}
return native_rw_locks_supported;
}
} // namespace webrtc

View File

@@ -0,0 +1,40 @@
/*
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_WIN_H_
#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_WIN_H_
#include "webrtc/system_wrappers/interface/rw_lock_wrapper.h"
#include <Windows.h>
namespace webrtc {
class RWLockWin : public RWLockWrapper {
public:
static RWLockWin* Create();
~RWLockWin() {}
virtual void AcquireLockExclusive();
virtual void ReleaseLockExclusive();
virtual void AcquireLockShared();
virtual void ReleaseLockShared();
private:
RWLockWin();
static bool LoadModule();
SRWLOCK lock_;
};
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_WIN_H_

View File

@@ -0,0 +1,328 @@
/*
* Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
// Borrowed from Chromium's src/base/memory/scoped_vector_unittest.cc
#include "webrtc/system_wrappers/interface/scoped_vector.h"
#include "webrtc/system_wrappers/interface/scoped_ptr.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace webrtc {
namespace {
// The LifeCycleObject notifies its Observer upon construction & destruction.
class LifeCycleObject {
public:
class Observer {
public:
virtual void OnLifeCycleConstruct(LifeCycleObject* o) = 0;
virtual void OnLifeCycleDestroy(LifeCycleObject* o) = 0;
protected:
virtual ~Observer() {}
};
~LifeCycleObject() {
observer_->OnLifeCycleDestroy(this);
}
private:
friend class LifeCycleWatcher;
explicit LifeCycleObject(Observer* observer)
: observer_(observer) {
observer_->OnLifeCycleConstruct(this);
}
Observer* observer_;
DISALLOW_COPY_AND_ASSIGN(LifeCycleObject);
};
// The life cycle states we care about for the purposes of testing ScopedVector
// against objects.
enum LifeCycleState {
LC_INITIAL,
LC_CONSTRUCTED,
LC_DESTROYED,
};
// Because we wish to watch the life cycle of an object being constructed and
// destroyed, and further wish to test expectations against the state of that
// object, we cannot save state in that object itself. Instead, we use this
// pairing of the watcher, which observes the object and notifies of
// construction & destruction. Since we also may be testing assumptions about
// things not getting freed, this class also acts like a scoping object and
// deletes the |constructed_life_cycle_object_|, if any when the
// LifeCycleWatcher is destroyed. To keep this simple, the only expected state
// changes are:
// INITIAL -> CONSTRUCTED -> DESTROYED.
// Anything more complicated than that should start another test.
class LifeCycleWatcher : public LifeCycleObject::Observer {
public:
LifeCycleWatcher() : life_cycle_state_(LC_INITIAL) {}
virtual ~LifeCycleWatcher() {}
// Assert INITIAL -> CONSTRUCTED and no LifeCycleObject associated with this
// LifeCycleWatcher.
virtual void OnLifeCycleConstruct(LifeCycleObject* object) OVERRIDE {
ASSERT_EQ(LC_INITIAL, life_cycle_state_);
ASSERT_EQ(NULL, constructed_life_cycle_object_.get());
life_cycle_state_ = LC_CONSTRUCTED;
constructed_life_cycle_object_.reset(object);
}
// Assert CONSTRUCTED -> DESTROYED and the |object| being destroyed is the
// same one we saw constructed.
virtual void OnLifeCycleDestroy(LifeCycleObject* object) OVERRIDE {
ASSERT_EQ(LC_CONSTRUCTED, life_cycle_state_);
LifeCycleObject* constructed_life_cycle_object =
constructed_life_cycle_object_.release();
ASSERT_EQ(constructed_life_cycle_object, object);
life_cycle_state_ = LC_DESTROYED;
}
LifeCycleState life_cycle_state() const { return life_cycle_state_; }
// Factory method for creating a new LifeCycleObject tied to this
// LifeCycleWatcher.
LifeCycleObject* NewLifeCycleObject() {
return new LifeCycleObject(this);
}
// Returns true iff |object| is the same object that this watcher is tracking.
bool IsWatching(LifeCycleObject* object) const {
return object == constructed_life_cycle_object_.get();
}
private:
LifeCycleState life_cycle_state_;
scoped_ptr<LifeCycleObject> constructed_life_cycle_object_;
DISALLOW_COPY_AND_ASSIGN(LifeCycleWatcher);
};
TEST(ScopedVectorTest, LifeCycleWatcher) {
LifeCycleWatcher watcher;
EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
LifeCycleObject* object = watcher.NewLifeCycleObject();
EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
delete object;
EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state());
}
TEST(ScopedVectorTest, PopBack) {
LifeCycleWatcher watcher;
EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
ScopedVector<LifeCycleObject> scoped_vector;
scoped_vector.push_back(watcher.NewLifeCycleObject());
EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
scoped_vector.pop_back();
EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state());
EXPECT_TRUE(scoped_vector.empty());
}
TEST(ScopedVectorTest, Clear) {
LifeCycleWatcher watcher;
EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
ScopedVector<LifeCycleObject> scoped_vector;
scoped_vector.push_back(watcher.NewLifeCycleObject());
EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
scoped_vector.clear();
EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state());
EXPECT_TRUE(scoped_vector.empty());
}
TEST(ScopedVectorTest, WeakClear) {
LifeCycleWatcher watcher;
EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
ScopedVector<LifeCycleObject> scoped_vector;
scoped_vector.push_back(watcher.NewLifeCycleObject());
EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
scoped_vector.weak_clear();
EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
EXPECT_TRUE(scoped_vector.empty());
}
TEST(ScopedVectorTest, ResizeShrink) {
LifeCycleWatcher first_watcher;
EXPECT_EQ(LC_INITIAL, first_watcher.life_cycle_state());
LifeCycleWatcher second_watcher;
EXPECT_EQ(LC_INITIAL, second_watcher.life_cycle_state());
ScopedVector<LifeCycleObject> scoped_vector;
scoped_vector.push_back(first_watcher.NewLifeCycleObject());
EXPECT_EQ(LC_CONSTRUCTED, first_watcher.life_cycle_state());
EXPECT_EQ(LC_INITIAL, second_watcher.life_cycle_state());
EXPECT_TRUE(first_watcher.IsWatching(scoped_vector[0]));
EXPECT_FALSE(second_watcher.IsWatching(scoped_vector[0]));
scoped_vector.push_back(second_watcher.NewLifeCycleObject());
EXPECT_EQ(LC_CONSTRUCTED, first_watcher.life_cycle_state());
EXPECT_EQ(LC_CONSTRUCTED, second_watcher.life_cycle_state());
EXPECT_FALSE(first_watcher.IsWatching(scoped_vector[1]));
EXPECT_TRUE(second_watcher.IsWatching(scoped_vector[1]));
// Test that shrinking a vector deletes elements in the disappearing range.
scoped_vector.resize(1);
EXPECT_EQ(LC_CONSTRUCTED, first_watcher.life_cycle_state());
EXPECT_EQ(LC_DESTROYED, second_watcher.life_cycle_state());
EXPECT_EQ(1u, scoped_vector.size());
EXPECT_TRUE(first_watcher.IsWatching(scoped_vector[0]));
}
TEST(ScopedVectorTest, ResizeGrow) {
LifeCycleWatcher watcher;
EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
ScopedVector<LifeCycleObject> scoped_vector;
scoped_vector.push_back(watcher.NewLifeCycleObject());
EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
scoped_vector.resize(5);
EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
ASSERT_EQ(5u, scoped_vector.size());
EXPECT_TRUE(watcher.IsWatching(scoped_vector[0]));
EXPECT_FALSE(watcher.IsWatching(scoped_vector[1]));
EXPECT_FALSE(watcher.IsWatching(scoped_vector[2]));
EXPECT_FALSE(watcher.IsWatching(scoped_vector[3]));
EXPECT_FALSE(watcher.IsWatching(scoped_vector[4]));
}
TEST(ScopedVectorTest, Scope) {
LifeCycleWatcher watcher;
EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
{
ScopedVector<LifeCycleObject> scoped_vector;
scoped_vector.push_back(watcher.NewLifeCycleObject());
EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
}
EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state());
}
TEST(ScopedVectorTest, MoveConstruct) {
LifeCycleWatcher watcher;
EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
{
ScopedVector<LifeCycleObject> scoped_vector;
scoped_vector.push_back(watcher.NewLifeCycleObject());
EXPECT_FALSE(scoped_vector.empty());
EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
ScopedVector<LifeCycleObject> scoped_vector_copy(scoped_vector.Pass());
EXPECT_TRUE(scoped_vector.empty());
EXPECT_FALSE(scoped_vector_copy.empty());
EXPECT_TRUE(watcher.IsWatching(scoped_vector_copy.back()));
EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
}
EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state());
}
TEST(ScopedVectorTest, MoveAssign) {
LifeCycleWatcher watcher;
EXPECT_EQ(LC_INITIAL, watcher.life_cycle_state());
{
ScopedVector<LifeCycleObject> scoped_vector;
scoped_vector.push_back(watcher.NewLifeCycleObject());
ScopedVector<LifeCycleObject> scoped_vector_assign;
EXPECT_FALSE(scoped_vector.empty());
EXPECT_TRUE(watcher.IsWatching(scoped_vector.back()));
scoped_vector_assign = scoped_vector.Pass();
EXPECT_TRUE(scoped_vector.empty());
EXPECT_FALSE(scoped_vector_assign.empty());
EXPECT_TRUE(watcher.IsWatching(scoped_vector_assign.back()));
EXPECT_EQ(LC_CONSTRUCTED, watcher.life_cycle_state());
}
EXPECT_EQ(LC_DESTROYED, watcher.life_cycle_state());
}
class DeleteCounter {
public:
explicit DeleteCounter(int* deletes)
: deletes_(deletes) {
}
~DeleteCounter() {
(*deletes_)++;
}
void VoidMethod0() {}
private:
int* const deletes_;
DISALLOW_COPY_AND_ASSIGN(DeleteCounter);
};
// This class is used in place of Chromium's base::Callback.
template <typename T>
class PassThru {
public:
explicit PassThru(ScopedVector<T> scoper) : scoper_(scoper.Pass()) {}
ScopedVector<T> Run() {
return scoper_.Pass();
}
private:
ScopedVector<T> scoper_;
};
TEST(ScopedVectorTest, Passed) {
int deletes = 0;
ScopedVector<DeleteCounter> deleter_vector;
deleter_vector.push_back(new DeleteCounter(&deletes));
EXPECT_EQ(0, deletes);
PassThru<DeleteCounter> pass_thru(deleter_vector.Pass());
EXPECT_EQ(0, deletes);
ScopedVector<DeleteCounter> result = pass_thru.Run();
EXPECT_EQ(0, deletes);
result.clear();
EXPECT_EQ(1, deletes);
};
TEST(ScopedVectorTest, InsertRange) {
LifeCycleWatcher watchers[5];
size_t watchers_size = sizeof(watchers) / sizeof(*watchers);
std::vector<LifeCycleObject*> vec;
for (LifeCycleWatcher* it = watchers; it != watchers + watchers_size;
++it) {
EXPECT_EQ(LC_INITIAL, it->life_cycle_state());
vec.push_back(it->NewLifeCycleObject());
EXPECT_EQ(LC_CONSTRUCTED, it->life_cycle_state());
}
// Start scope for ScopedVector.
{
ScopedVector<LifeCycleObject> scoped_vector;
scoped_vector.insert(scoped_vector.end(), vec.begin() + 1, vec.begin() + 3);
for (LifeCycleWatcher* it = watchers; it != watchers + watchers_size;
++it)
EXPECT_EQ(LC_CONSTRUCTED, it->life_cycle_state());
}
for (LifeCycleWatcher* it = watchers; it != watchers + 1; ++it)
EXPECT_EQ(LC_CONSTRUCTED, it->life_cycle_state());
for (LifeCycleWatcher* it = watchers + 1; it != watchers + 3; ++it)
EXPECT_EQ(LC_DESTROYED, it->life_cycle_state());
for (LifeCycleWatcher* it = watchers + 3; it != watchers + watchers_size;
++it)
EXPECT_EQ(LC_CONSTRUCTED, it->life_cycle_state());
}
} // namespace
} // namespace webrtc

View File

@@ -0,0 +1,108 @@
/*
Source:
http://msdn.microsoft.com/en-us/cc300389.aspx#P
License:
This license governs use of code marked as “sample” or “example” available on
this web site without a license agreement, as provided under the section above
titled “NOTICE SPECIFIC TO SOFTWARE AVAILABLE ON THIS WEB SITE.” If you use
such code (the “software”), you accept this license. If you do not accept the
license, do not use the software.
1. Definitions
The terms “reproduce,” “reproduction,” “derivative works,” and “distribution”
have the same meaning here as under U.S. copyright law.
A “contribution” is the original software, or any additions or changes to the
software.
A “contributor” is any person that distributes its contribution under this
license.
“Licensed patents” are a contributors patent claims that read directly on its
contribution.
2. Grant of Rights
(A) Copyright Grant - Subject to the terms of this license, including the
license conditions and limitations in section 3, each contributor grants you a
non-exclusive, worldwide, royalty-free copyright license to reproduce its
contribution, prepare derivative works of its contribution, and distribute its
contribution or any derivative works that you create.
(B) Patent Grant - Subject to the terms of this license, including the license
conditions and limitations in section 3, each contributor grants you a
non-exclusive, worldwide, royalty-free license under its licensed patents to
make, have made, use, sell, offer for sale, import, and/or otherwise dispose
of its contribution in the software or derivative works of the contribution in
the software.
3. Conditions and Limitations
(A) No Trademark License- This license does not grant you rights to use any
contributors name, logo, or trademarks.
(B) If you bring a patent claim against any contributor over patents that you
claim are infringed by the software, your patent license from such contributor
to the software ends automatically.
(C) If you distribute any portion of the software, you must retain all
copyright, patent, trademark, and attribution notices that are present in the
software.
(D) If you distribute any portion of the software in source code form, you may
do so only under this license by including a complete copy of this license
with your distribution. If you distribute any portion of the software in
compiled or object code form, you may only do so under a license that complies
with this license.
(E) The software is licensed “as-is.” You bear the risk of using it. The
contributors give no express warranties, guarantees or conditions. You may
have additional consumer rights under your local laws which this license
cannot change. To the extent permitted under your local laws, the contributors
exclude the implied warranties of merchantability, fitness for a particular
purpose and non-infringement.
(F) Platform Limitation - The licenses granted in sections 2(A) and 2(B)
extend only to the software or derivative works that you create that run on a
Microsoft Windows operating system product.
*/
/*
* The original code can be found here:
* http://msdn.microsoft.com/en-us/library/xcb2z8hs(VS.71).aspx
*/
#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_WINDOWS_SET_NAME_H_
#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_WINDOWS_SET_NAME_H_
namespace webrtc {
struct THREADNAME_INFO
{
DWORD dwType; // must be 0x1000
LPCSTR szName; // pointer to name (in user addr space)
DWORD dwThreadID; // thread ID (-1 = caller thread)
DWORD dwFlags; // reserved for future use, must be zero
};
void SetThreadName(DWORD dwThreadID, LPCSTR szThreadName)
{
THREADNAME_INFO info;
info.dwType = 0x1000;
info.szName = szThreadName;
info.dwThreadID = dwThreadID;
info.dwFlags = 0;
__try
{
RaiseException(0x406D1388, 0, sizeof(info) / sizeof(DWORD),
(ULONG_PTR*)&info);
}
__except (EXCEPTION_CONTINUE_EXECUTION)
{
}
}
} // namespace webrtc
#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_WINDOWS_SET_NAME_H_

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